otbWrapperCommandLineLauncher.cxx 30.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/*
 * Copyright (C) 2005-2017 Centre National d'Etudes Spatiales (CNES)
 *
 * This file is part of Orfeo Toolbox
 *
 *     https://www.orfeo-toolbox.org/
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
20 21

#include "otbWrapperCommandLineLauncher.h"
22 23

// Single value parameter
24 25
#include "otbWrapperChoiceParameter.h"
#include "otbWrapperDirectoryParameter.h"
26
#include "otbWrapperInputFilenameParameter.h"
27
#include "otbWrapperOutputFilenameParameter.h"
28 29 30 31 32
#include "otbWrapperInputImageParameter.h"
#include "otbWrapperInputVectorDataParameter.h"
#include "otbWrapperOutputImageParameter.h"
#include "otbWrapperOutputVectorDataParameter.h"
#include "otbWrapperRadiusParameter.h"
33
#include "otbWrapperListViewParameter.h"
34
#include "otbWrapperRAMParameter.h"
35
#include "otbWrapperOutputProcessXMLParameter.h"
36
#include "otbWrapperAddProcessToWatchEvent.h"
37

38 39
// List value parameter
#include "otbWrapperInputImageListParameter.h"
40
#include "otbWrapperInputVectorDataListParameter.h"
41
#include "otbWrapperInputFilenameListParameter.h"
42 43
#include "otbWrapperStringListParameter.h"

44

45
#include "otbWrapperApplicationRegistry.h"
46
#include "otbWrapperTypes.h"
47 48 49
#include <itksys/RegularExpression.hxx>
#include <string>
#include <iostream>
50

51 52
using std::string;

53 54 55 56 57
namespace otb
{
namespace Wrapper
{

58
CommandLineLauncher::CommandLineLauncher() :
59
  /*m_Expression(""),*/m_VExpression(), m_WatcherList(), m_ReportProgress(true)
60
{
61
  m_Application = nullptr;
62
  m_Parser = CommandLineParser::New();
63
  m_LogOutput = itk::StdStreamLogOutput::New();
64
  m_LogOutput->SetStream(std::cout);
65 66 67

  // Add the callback to be added when a AddProcessToWatch event is invoked
  m_AddProcessCommand = AddProcessCommandType::New();
68
  m_AddProcessCommand->SetCallbackFunction(this, &CommandLineLauncher::LinkWatchers);
69 70 71 72
}

CommandLineLauncher::~CommandLineLauncher()
{
73
  this->DeleteWatcherList();
74
  m_Application = nullptr;
75
  ApplicationRegistry::CleanRegistry();
76
}
77

78
void CommandLineLauncher::DeleteWatcherList()
79
{
80
  for (unsigned int i = 0; i < m_WatcherList.size(); i++)
81
    {
82
    delete m_WatcherList[i];
83
    m_WatcherList[i] = nullptr;
84 85 86 87
    }
  m_WatcherList.clear();
}

Mickael Savinaud's avatar
Mickael Savinaud committed
88

89
bool CommandLineLauncher::Load(const std::vector<std::string> &vexp)
Mickael Savinaud's avatar
Mickael Savinaud committed
90 91
{
  m_VExpression = vexp;
92
  return this->Load();
93 94
}

Mickael Savinaud's avatar
Mickael Savinaud committed
95

96
bool CommandLineLauncher::Load()
97
{
98
  if (this->CheckParametersPrefix() == false)
99
    {
100
    std::cerr << "ERROR: Parameters are set using \"-\", not \"--\"." << std::endl;
101
    return false;
102 103
    }

104
  if (this->CheckUnicity() == false)
105
    {
106
    std::cerr << "ERROR: At least one parameter is not unique in the expression." << std::endl;
107
    return false;
108 109
    }

110
  if (this->LoadPath() == false)
111
    {
Mickael Savinaud's avatar
Mickael Savinaud committed
112
    if (m_Parser->GetPathsAsString(m_VExpression).size() != 0)
113
      {
Mickael Savinaud's avatar
Mickael Savinaud committed
114
      std::cerr << "ERROR: At least one specified path within \"" << m_Parser->GetPathsAsString(m_VExpression)
115
                << "\" is invalid or doesn't exist." << std::endl;
116
      return false;
117
      }
118 119
    }

120
  return this->LoadApplication();
121 122
}

123
bool CommandLineLauncher::Execute()
124
{
125
  if (this->BeforeExecute() == false)
126
    {
127
    return false;
128
    }
129

130 131 132
  if( m_Application->Execute() == 0 )
    {
    this->DisplayOutputParameters();
133
    return true;
134
    }
OTB Bot's avatar
OTB Bot committed
135
  else
136
    return false;
OTB Bot's avatar
OTB Bot committed
137
}
138

139
bool CommandLineLauncher::ExecuteAndWriteOutputNoCatch()
140
{
141 142
   if (this->BeforeExecute() == false)
      {
143
      return false;
144
      }
145
    if( m_Application->ExecuteAndWriteOutput() == 0 )
146
      {
147
      this->DisplayOutputParameters();
148
      }
149
    else
150
      {
151
      return false;
152 153 154 155 156 157 158 159 160
      }
    return true;
}

bool CommandLineLauncher::ExecuteAndWriteOutput()
{
  // If testenv is used, do not catch exceptions
  if (m_Parser->IsAttributExists("-testenv", m_VExpression) == true)
    {
161
    return ExecuteAndWriteOutputNoCatch();
162
    }
163 164 165 166
  else
    {
    try
      {
167
      return ExecuteAndWriteOutputNoCatch();
168 169 170
      }
    catch(otb::ApplicationException& err)
      {
171 172 173 174 175 176
      // These are thrown with otbAppLogFATAL, a macro which logs a user
      // friendly error message before throwing. So log exception details only
      // in debug.
      m_Application->GetLogger()->Debug("Caught otb::ApplicationException during application execution:\n");
      m_Application->GetLogger()->Debug(string(err.what()) + "\n");
      return false;
177 178 179
      }
    catch(otb::ImageFileReaderException& err)
      {
180 181
      m_Application->GetLogger()->Debug("Caught otb::ImageFileReaderException during application execution:\n");
      m_Application->GetLogger()->Debug(string(err.what()) + "\n");
182
      m_Application->GetLogger()->Fatal(string("Cannot open image ") + err.m_Filename + string(". ") + err.GetDescription() + string("\n"));
183
      return false;
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
      }
    catch(itk::ExceptionObject& err)
      {
      m_Application->GetLogger()->Debug("Caught itk::ExceptionObject during application execution:\n");
      m_Application->GetLogger()->Debug(string(err.what()) + "\n");
      m_Application->GetLogger()->Fatal(string(err.GetDescription()) + "\n");
      return false;
      }
    catch(std::exception& err)
      {
      m_Application->GetLogger()->Fatal(std::string("Caught std::exception during application execution: ") + err.what() + "\n");
      return false;
      }
    catch(...)
      {
      m_Application->GetLogger()->Fatal("Caught unknown exception during application execution.\n");
      return false;
      }
    }
203
}
204

205
bool CommandLineLauncher::BeforeExecute()
206
{
207
  if (m_Application.IsNull())
208
    {
209
    std::cerr << "ERROR: No loaded application." << std::endl;
210
    return false;
211
    }
212

213 214 215
  // Check if there's keys in the expression if the application takes
  // at least 1 mandatory parameter
  const std::vector<std::string> appKeyList = m_Application->GetParametersKeys(true);
Mickael Savinaud's avatar
Mickael Savinaud committed
216
  std::vector<std::string> keyList = m_Parser->GetKeyList( m_VExpression );
217

218 219
  if( appKeyList.size()!=0 && keyList.size()==0 )
    {
220
    std::cerr << "ERROR: Waiting for at least one parameter." << std::endl;
221
    std::cerr << std::endl;
222 223 224 225
    this->DisplayHelp();
    return false;
    }

226
  // if help is asked...
Mickael Savinaud's avatar
Mickael Savinaud committed
227
  if (m_Parser->IsAttributExists("-help", m_VExpression) == true)
228
    {
229 230 231 232 233 234 235 236 237
    std::vector<std::string> val;
    val = m_Parser->GetAttribut("-help", m_VExpression);

    if(val.empty())
      {      
      this->DisplayHelp(true);
      }
    else
      {
238
     
239 240 241 242 243 244 245 246 247 248
      
      for(std::vector<std::string>::const_iterator it = val.begin(); it!=val.end();++it)
        {
        Parameter::Pointer param = m_Application->GetParameterByKey(*it);
        if (param->GetRole() != Role_Output)
          {
          std::cerr << this->DisplayParameterHelp(param, *it,true)<<std::endl;
          }
        }
      }
249
    return false;
250
    }
251

252
  //display OTB version
Mickael Savinaud's avatar
Mickael Savinaud committed
253
  if (m_Parser->IsAttributExists("-version", m_VExpression) == true)
254 255 256 257 258
    {
    std::cerr << "This is the "<<m_Application->GetName() << " application, version " << OTB_VERSION_STRING <<std::endl;
    return false;
    }

259
  // if we want to load test environnement
Mickael Savinaud's avatar
Mickael Savinaud committed
260
  if (m_Parser->IsAttributExists("-testenv", m_VExpression) == true)
261 262 263
    {
    this->LoadTestEnv();
    }
264

265
  // Check the key validity (ie. exist in the application parameters)
266 267
  std::string unknownKey;
  if (this->CheckKeyValidity(unknownKey) == false)
268
    {
269
    std::cerr << "ERROR: Parameter -" << unknownKey <<" does not exist in the application." << std::endl;
270
    return false;
271
    }
272

273
  ParamResultType result = this->LoadParameters();
274

275
  if (result == MISSINGMANDATORYPARAMETER)
276
    {
277
    std::cerr << std::endl;
278
    this->DisplayHelp();
279
    return false;
280
    }
281
  else if (result != OKPARAM)
282
    {
283
    return false;
284
    }
285

286
  return true;
287
}
288

289
bool CommandLineLauncher::LoadPath()
290 291
{
  std::vector<std::string> pathList;
292
  // If users has set path...
Mickael Savinaud's avatar
Mickael Savinaud committed
293 294
  //if (m_Parser->GetPaths(pathList, m_Expression) == CommandLineParser::OK)
  if (m_Parser->GetPaths(pathList, m_VExpression) == CommandLineParser::OK)
OTB Bot's avatar
OTB Bot committed
295
    {
296
    for (unsigned i = 0; i < pathList.size(); i++)
297
      {
298
      ApplicationRegistry::AddApplicationPath(pathList[i]);
299
      }
300
    }
301 302
  else
    {
303
    return false;
304 305
    }

306
  return true;
307 308
}

309
bool CommandLineLauncher::LoadApplication()
310 311 312
{
  // Look for the module name
  std::string moduleName;
Mickael Savinaud's avatar
Mickael Savinaud committed
313
  if (m_Parser->GetModuleName(moduleName, m_VExpression) != CommandLineParser::OK)
314
    {
315
    std::cerr << "ERROR: Invalid module name: " << m_VExpression[0] << "." << std::endl;
316
    return false;
317
    }
318

Jonathan Guinet's avatar
Jonathan Guinet committed
319
  // Instantiate the application using the factory
320
  m_Application = ApplicationRegistry::CreateApplication(moduleName);
321

322 323
  if (m_Application.IsNull())
    {
324
    std::cerr << "ERROR: Could not find application \"" << moduleName << "\"" << std::endl;
325 326
    std::string modulePath = ApplicationRegistry::GetApplicationPath();
    std::cerr << "ERROR: Module search path: " << (modulePath.empty() ? "none (check OTB_APPLICATION_PATH)" : modulePath) << std::endl;
327

328
    std::vector<std::string> list = ApplicationRegistry::GetAvailableApplications();
329
    if (list.size() == 0)
330
      {
331
      std::cerr << "ERROR: Available modules: none." << std::endl;
332 333 334
      }
    else
      {
335
      std::cerr << "ERROR: Available modules:" << std::endl;
336 337
      for (std::vector<std::string>::const_iterator it = list.begin(); it != list.end(); ++it)
        {
Cyrille Valladeau's avatar
Cyrille Valladeau committed
338
        std::cerr << "\t" << *it << std::endl;
339
        }
340
      }
341
    return false;
342
    }
343 344 345 346
  else
    {
    // Attach log output to the Application logger
    m_Application->GetLogger()->AddLogOutput(m_LogOutput);
347

348 349
    // Add an observer to the AddedProcess event
    m_Application->AddObserver(AddProcessToWatchEvent(), m_AddProcessCommand.GetPointer());
350

351
    return true;
352
    }
353 354
}

355
CommandLineLauncher::ParamResultType CommandLineLauncher::LoadParameters()
356
{
357
  if (m_Application.IsNull())
358
    {
359
    itkExceptionMacro("No application loaded");
360
    }
361

362 363 364 365 366
  /* Check for inxml parameter. If exists Update all Parameters from xml and
   * check for user defined parameters for overriding those from XML
   */
  const char *inXMLKey =  "inxml";
  const char *attrib   = "-inxml";
Mickael Savinaud's avatar
Mickael Savinaud committed
367
  const bool paramInXMLExists(m_Parser->IsAttributExists(attrib, m_VExpression));
368 369 370
  if(paramInXMLExists)
    {
    std::vector<std::string> inXMLValues;
Mickael Savinaud's avatar
Mickael Savinaud committed
371
    inXMLValues = m_Parser->GetAttribut(attrib, m_VExpression);
372 373 374 375
    m_Application->SetParameterString(inXMLKey, inXMLValues[0]);
    m_Application->UpdateParameters();
    }

376 377
  // Check for the progress report parameter
  if (m_Parser->IsAttributExists("-progress", m_VExpression) == true)
378
    {
379 380
    std::vector<std::string> val = m_Parser->GetAttribut("-progress", m_VExpression);
    if (val.size() == 1 && (val[0] == "1" || val[0] == "true"))
381
      {
382
      m_ReportProgress = true;
383
      }
384
    else if (val.size() == 1 && (val[0] == "0" || val[0] == "false"))
385
      {
386
      m_ReportProgress = false;
387
      }
388
    else
389
      {
390 391
      std::cerr << "ERROR: Invalid value for parameter -progress. It must be 0, 1, false or true." << std::endl;
      return WRONGPARAMETERVALUE;
392
      }
393 394
    }

395
  const std::vector<std::string> appKeyList = m_Application->GetParametersKeys(true);
396
  // Loop over each parameter key declared in the application
397
  // FIRST PASS : set parameter values
398
  for (unsigned int i = 0; i < appKeyList.size(); i++)
399
    {
400 401
    const std::string paramKey(appKeyList[i]);
    std::vector<std::string> values;
402

403 404
    ParameterType type = m_Application->GetParameterType(paramKey);

Mickael Savinaud's avatar
Mickael Savinaud committed
405
    const bool paramExists(m_Parser->IsAttributExists(std::string("-").append(paramKey), m_VExpression));
406

407
    // if param is a Group, don't do anything, ParamGroup don't have values
408 409
    if (type != ParameterType_Group)
      {
410
      // Get the attribute relative to this key as vector
Mickael Savinaud's avatar
Mickael Savinaud committed
411
      values = m_Parser->GetAttribut(std::string("-").append(paramKey), m_VExpression);
412

413
      // If the param does not exists in the cli, don't try to set a
414 415 416 417 418 419
      // value on it, an exception will be thrown later in this function
      if (paramExists)
        {
        // Check if there is a value associated to the attribute
        if ( values.empty() )
          {
420
          std::cerr << "ERROR: No value associated to parameter -" << paramKey << "." << std::endl;
421 422
          return INVALIDNUMBEROFVALUE;
          }
423

424 425 426 427 428
        if (type == ParameterType_InputVectorDataList ||
            type == ParameterType_InputImageList ||
            type == ParameterType_InputFilenameList ||
            type == ParameterType_StringList ||
            type == ParameterType_ListView)
OTB Bot's avatar
OTB Bot committed
429
          {
430 431
          // Multiple values parameters
          m_Application->SetParameterStringList(paramKey, values);
432
          }
433
        else if (type == ParameterType_Choice ||
434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449
                 type == ParameterType_Float ||
                 type == ParameterType_Int ||
                 type == ParameterType_Radius ||
                 type == ParameterType_Directory ||
                 type == ParameterType_String ||
                 type == ParameterType_InputFilename ||
                 type == ParameterType_OutputFilename ||
                 type == ParameterType_ComplexInputImage ||
                 type == ParameterType_InputImage ||
                 type == ParameterType_OutputImage ||
                 type == ParameterType_ComplexOutputImage ||
                 type == ParameterType_InputVectorData ||
                 type == ParameterType_OutputVectorData ||
                 type == ParameterType_RAM ||
                 type == ParameterType_OutputProcessXML ||
                 type == ParameterType_Bool) // || type == ParameterType_InputProcessXML)
450
          {
451
          // Single value parameter
OTB Bot's avatar
OTB Bot committed
452
          m_Application->SetParameterString(paramKey, values[0]);
453 454

          if (type == ParameterType_OutputImage)
455
            {
456 457 458 459 460 461 462 463 464 465 466 467 468
            // Check if pixel type is given
            if (values.size() == 2)
              {
              ImagePixelType pixType = ImagePixelType_float;
              if ( !OutputImageParameter::ConvertStringToPixelType(values[1],pixType) )
                {
                std::cerr << "ERROR: Invalid output type for parameter -" <<
                  paramKey << ": " << values[1] << "." << std::endl;
                return WRONGPARAMETERVALUE;
                }
              m_Application->SetParameterOutputImagePixelType(paramKey, pixType);
              }
            else if (values.size() > 2)
469
              {
470 471
              std::cerr << "ERROR: Too many values for parameter -" <<
                paramKey << " (expected 2 or 1, got " << values.size() << ")."
472
                        << std::endl;
473
              return INVALIDNUMBEROFVALUE;
474
              }
475 476 477 478 479 480 481 482
            }
          else if (type == ParameterType_ComplexOutputImage)
            {
            // Check if pixel type is given
            if (values.size() == 2)
              {
              ComplexImagePixelType cpixType = ComplexImagePixelType_float;
              if ( !ComplexOutputImageParameter::ConvertStringToPixelType(values[1],cpixType) )
483
                {
484 485 486
                std::cerr << "ERROR: Invalid output type for parameter -" <<
                  paramKey << ": " << values[1] << "." << std::endl;
                return WRONGPARAMETERVALUE;
487
                }
488 489 490
              m_Application->SetParameterComplexOutputImagePixelType(paramKey, cpixType);
              }
            else if (values.size() > 2)
OTB Bot's avatar
OTB Bot committed
491
              {
492 493 494
              std::cerr << "ERROR: Too many values for parameter: -" << paramKey
                        << " (expected 2 or 1, got " << values.size() << ")." <<std::endl;
              return INVALIDNUMBEROFVALUE;
495
              }
496
            }
497
          }
498
        // Call the DoUpdateParameter to update dependent params
499 500 501
        m_Application->UpdateParameters();
        }
      }
502 503
    }

504 505
  // SECOND PASS : checks
  for (const auto & paramKey : appKeyList)
506
    {
507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529
    // Check for missing mandatory parameters
    if(!CheckMissingMandatoryParameter(paramKey))
      return MISSINGMANDATORYPARAMETER;

    // Check and warn unused parameters
    CheckUnusedParameter(paramKey);

    // Check output paths are valid
    if(!CheckOutputPathsValidity(paramKey))
      return WRONGPARAMETERVALUE;
    }

  return OKPARAM;
}

bool CommandLineLauncher::CheckOutputPathsValidity(const std::string & paramKey) const
{
  ParameterType type = m_Application->GetParameterType(paramKey);
  if (m_Application->HasValue(paramKey) &&
      type == ParameterType_OutputFilename)
    {
    std::string filename = m_Application->GetParameterString(paramKey);
    itksys::String path = itksys::SystemTools::GetFilenamePath(filename);
530
    if (path!="" && !itksys::SystemTools::FileIsDirectory(path))
531
      {
532
      std::cerr <<"ERROR: Directory doesn't exist : "<< path << std::endl;
533 534 535 536 537 538 539 540
      return false;
        }
      }
  return true;
}

bool CommandLineLauncher::CheckMissingMandatoryParameter(const std::string & paramKey) const
{
541
    if (m_Application->IsParameterMissing(paramKey))
542
      {
543
      std::cerr << "ERROR: Missing mandatory parameter -" << paramKey << "." << std::endl;
Julien Michel's avatar
Julien Michel committed
544
      return false;
545
      }
Julien Michel's avatar
Julien Michel committed
546
    return true;
547
}
548

549 550 551
void CommandLineLauncher::CheckUnusedParameter(const std::string & paramKey) const
{
  // Check for ignored parameters
552 553
    if(m_Application->HasUserValue(paramKey))
      {
554 555

      // Find the position of the next dot
556 557
      unsigned int start = 0;
      auto end = paramKey.find_first_of('.',start);
558 559

      // Until we reach en of key
560 561
      while(end != std::string::npos)
        {
562 563 564 565
        // Extract key until the current dot
        const std::string & key = paramKey.substr(0,end);

        // Find the corresponding parameter type
566
        ParameterType type = m_Application->GetParameterType(key);
567 568 569 570 571 572

        // In any case update the position of current and next dot
        start = end+1;
        end = paramKey.find_first_of('.',start);

        // If the current parameter (paramKey) has a choice in it
573 574
        if(type == ParameterType_Choice)
          {
575
          const std::string & value = m_Application->GetParameterString(key);
576

577
          // Check that this choice is active
578 579
          if(paramKey.find(value) == std::string::npos)
            {
580
            std::cerr<<"WARNING: Parameter -"<<paramKey<<" will be ignored because -"<<key<<" is "<<value<<"."<<std::endl;
581 582 583 584 585 586
            
            break;
            }
          }
        }
      }
587 588
}

589
void CommandLineLauncher::LinkWatchers(itk::Object * itkNotUsed(caller), const itk::EventObject & event)
590
{
591
  // Report the progress only if asked
592
  if (m_ReportProgress)
593
    {
594

595
    if (typeid(otb::Wrapper::AddProcessToWatchEvent) == typeid( event ))
596
      {
597
      const AddProcessToWatchEvent* eventToWatch = dynamic_cast<const AddProcessToWatchEvent*> (&event);
598

599 600
      StandardOneLineFilterWatcher * watch = new StandardOneLineFilterWatcher(eventToWatch->GetProcess(),
                                                                              eventToWatch->GetProcessDescription());
601
      m_WatcherList.push_back(watch);
602
      }
603 604 605
    }
}

606
void CommandLineLauncher::DisplayHelp(bool longHelp)
607
{
608 609
  std::cerr<<std::endl;
  std::cerr << "This is the "<<m_Application->GetDocName() << " ("<<m_Application->GetName()<<") application, version " << OTB_VERSION_STRING <<std::endl<<std::endl;
610 611

  std::cerr << m_Application->GetDescription() << std::endl;
612

613 614 615 616 617 618 619 620 621 622
  if(longHelp)
    { 
    std::cerr<<"Tags: ";

    std::vector<std::string> tags = m_Application->GetDocTags();
    
    for(std::vector<std::string>::const_iterator it = tags.begin(); it!=tags.end();++it)
      {
      std::cerr<<*it<<" ";
      }
623
    std::cerr<<std::endl;
624 625 626
  
    std::cerr<<std::endl;
    std::cerr<<m_Application->GetDocLongDescription() << std::endl;
627
    std::cerr<<std::endl;
628 629 630 631 632 633 634 635 636 637
    }
  else
    {
    std::string link = m_Application->GetDocLink();
    if (!link.empty())
      {
      std::cerr << "Complete documentation: " << link << " or -help" <<std::endl;
      std::cerr<<std::endl;
      }
    }
638

639
  std::cerr << "Parameters: " << std::endl;
640

641 642 643
  const std::vector<std::string> appKeyList = m_Application->GetParametersKeys(true);
  const unsigned int nbOfParam = appKeyList.size();

644
  unsigned int maxKeySize = GetMaxKeySize();
645

646 647
  //// progress report parameter
  std::string bigKey = "progress";
648
  for(unsigned int i=0; i<maxKeySize-std::string("progress").size(); i++)
649
    bigKey.append(" ");
650

651
  for (unsigned int i = 0; i < nbOfParam; i++)
652
    {
653 654 655 656 657
    Parameter::Pointer param = m_Application->GetParameterByKey(appKeyList[i]);
    if (param->GetRole() != Role_Output)
      {
      std::cerr << this->DisplayParameterHelp(param, appKeyList[i]);
      }
658
    }
659

660 661 662 663 664 665
  std::cerr << "        -"<<bigKey<<" <boolean>        Report progress " << std::endl;
  bigKey = "help";
  for(unsigned int i=0; i<maxKeySize-std::string("help").size(); i++)
    bigKey.append(" ");
  std::cerr << "        -"<<bigKey<<" <string list>    Display long help (empty list), or help for given parameters keys" << std::endl;

666
  std::cerr<<std::endl;
667 668
  //std::string cl(m_Application->GetCLExample());

669 670 671 672

  std::cerr<<"Use -help param1 [... paramN] to see detailed documentation of those parameters."<<std::endl;
  std::cerr<<std::endl;
  
673
  std::cerr << "Examples: " << std::endl;
674 675
  std::cerr << m_Application->GetCLExample() << std::endl;

676 677 678
  if(longHelp)
    {
    std::cerr<<"Authors: "<<std::endl<<m_Application->GetDocAuthors() << std::endl;
679

680 681 682 683 684 685
    std::cerr<<std::endl;
    std::cerr<<"Limitations: "<<std::endl<<m_Application->GetDocLimitations() << std::endl;

    std::cerr<<std::endl;
    std::cerr<<"See also: "<<std::endl<<m_Application->GetDocSeeAlso() << std::endl;
    std::cerr<<std::endl;
686

687 688 689
    }  

}
690 691 692 693

void CommandLineLauncher::LoadTestEnv()
{
  //Set seed for rand and itk mersenne twister
694
  //srand(1);
695
  // itk::Statistics::MersenneTwisterRandomVariateGenerator::GetInstance()->SetSeed(121212);
696 697 698
}


699
std::string CommandLineLauncher::DisplayParameterHelp(const Parameter::Pointer & param, const std::string paramKey, bool longHelp)
700
{
701
  // Display the type the type
702
  ParameterType type = m_Application->GetParameterType(paramKey);
703

704 705 706
  std::string bigKey = paramKey;
  
  unsigned int maxKeySize = GetMaxKeySize();
707

708 709 710 711 712 713 714 715
  bool singleSelectionForListView = false;

  if(type == ParameterType_ListView)
    {
    ListViewParameter * tmp = static_cast<ListViewParameter *>(param.GetPointer());
    singleSelectionForListView = tmp->GetSingleSelection();
    }

716
  std::ostringstream oss;
717

718
  if( m_Application->IsParameterMissing(paramKey) )
719
    {
720
    oss << "MISSING ";
721
    }
722
  else
723
    {
724
    oss << "        ";
725
    }
726 727
  
  for(unsigned int i=0; i<maxKeySize-paramKey.size(); i++)
728
    bigKey.append(" ");
729

730
  oss<< "-" << bigKey << " ";
731 732 733

  // Display the type the parameter
  if (type == ParameterType_Radius || type == ParameterType_Int || type == ParameterType_RAM)
734
    {
735 736
    oss << "<int32>         ";
    }
737
  else if (type == ParameterType_Bool)
738 739 740 741 742 743 744
    {
    oss << "<boolean>       ";
    }
  else if (type == ParameterType_Float)
    {
    oss << "<float>         ";
    }
745
  else if (type == ParameterType_InputFilename || type == ParameterType_OutputFilename ||type == ParameterType_Directory || type == ParameterType_InputImage || type == ParameterType_OutputProcessXML || type == ParameterType_InputProcessXML ||
746
           type == ParameterType_ComplexInputImage || type == ParameterType_InputVectorData || type == ParameterType_OutputVectorData ||
747
           type == ParameterType_String || type == ParameterType_Choice || (type == ParameterType_ListView && singleSelectionForListView))
748 749 750
    {
    oss << "<string>        ";
    }
751
  else if (type == ParameterType_OutputImage || type == ParameterType_ComplexOutputImage)
752 753 754
    {
    oss << "<string> [pixel]";
    }
755
  else if (type == ParameterType_Choice || (type == ParameterType_ListView && !singleSelectionForListView) || type == ParameterType_InputImageList ||
756 757
           type == ParameterType_InputVectorDataList || type == ParameterType_InputFilenameList ||
           type == ParameterType_StringList )
758
    {
759
    oss << "<string list>   ";
760
    }
761 762 763 764
  else if(type == ParameterType_Group)
    {
    oss<< "<group>         ";
    }
765
  else
766
    itkExceptionMacro("Not handled parameter type.");
767 768


769
  oss<< " " << m_Application->GetParameterName(paramKey) << " ";
770

771 772
  if (type == ParameterType_OutputImage)
    {
773 774 775 776 777 778
    OutputImageParameter* paramDown = dynamic_cast<OutputImageParameter*>(param.GetPointer());
    std::string defPixType("float");
    if (paramDown)
      {
      defPixType = OutputImageParameter::ConvertPixelTypeToString(paramDown->GetDefaultPixelType());
      }
779
    oss << " [pixel=uint8/uint16/int16/uint32/int32/float/double/cint16/cint32/cfloat/cdouble]";
780
    oss << " (default value is " << defPixType <<")";
781 782
    }

783 784
  if (type == ParameterType_ComplexOutputImage)
    {
785 786 787 788 789 790
    ComplexOutputImageParameter* paramDown = dynamic_cast<ComplexOutputImageParameter*>(param.GetPointer());
    std::string defPixType("cfloat");
    if (paramDown)
      {
      defPixType = ComplexOutputImageParameter::ConvertPixelTypeToString(paramDown->GetDefaultComplexPixelType());
      }
791
    oss << " [pixel=cfloat/cdouble]";
792
    oss << " (default value is "<< defPixType <<")";
793 794
    }

795 796 797

  if (type == ParameterType_Choice)
    {
Victor Poughon's avatar
Victor Poughon committed
798 799 800 801 802
    ChoiceParameter* paramDown = dynamic_cast<ChoiceParameter*>(param.GetPointer());
    if (paramDown)
      {
      std::vector<std::string> keys = paramDown->GetChoiceKeys();
      std::vector<std::string> names = paramDown->GetChoiceNames();
803

Victor Poughon's avatar
Victor Poughon committed
804 805
      oss << "[";
      for(unsigned int i=0; i<keys.size(); i++)
806
        {
Victor Poughon's avatar
Victor Poughon committed
807 808 809
        oss<<keys[i];
        if( i != keys.size()-1 )
          oss << "/";
810
        }
811

Victor Poughon's avatar
Victor Poughon committed
812 813
      oss << "]";
      }
814
    }
815

816
  if(type != ParameterType_Group)
817
    {
818

819
    if(m_Application->IsMandatory(paramKey))
820
      {
821
      oss<<" (mandatory";
822 823 824
      }
    else
      {
825
      oss<<" (optional";
826

827 828 829 830 831 832 833 834 835 836 837 838
      if(m_Application->IsParameterEnabled(paramKey))
        {
        oss<<", on by default";
        }
      else
        {
        oss<<", off by default";
        }
      }
    
    if(m_Application->HasValue(paramKey))
      {
839 840 841 842 843 844 845
      if ( m_Application->GetParameterAsString(paramKey).empty() )
        oss<<", no default value";
      else
        {
        oss<<", default value is "
           <<m_Application->GetParameterAsString(paramKey);
        }
846 847
      }
    oss<<")";
848
    }
849
  oss << std::endl;
850 851 852 853

  if(longHelp)
    {
    oss << "        ";
854
    for(unsigned int i=0; i<maxKeySize;++i)
855 856 857 858
      oss<<" ";
    oss<<"                   ";
    oss<<m_Application->GetParameterDescription(paramKey)<<std::endl;

859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876

    if (type == ParameterType_Choice)
      {
      std::vector<std::string> keys = dynamic_cast<ChoiceParameter*>(param.GetPointer())->GetChoiceKeys();
      std::vector<std::string> names = dynamic_cast<ChoiceParameter*>(param.GetPointer())->GetChoiceNames();
      
      auto keyIt = keys.begin();
      auto nameIt = names.begin();
      
      for( ; keyIt!=keys.end()&&nameIt!=names.end();++keyIt,++nameIt)
        {
        oss << "        ";
        for(unsigned int i=0; i<maxKeySize;++i)
          oss<<" ";
        oss<<"                   ";
        oss<<"- "<<*nameIt<<" ("<<*keyIt<<"): "<<m_Application->GetParameterDescription(paramKey+"."+(*keyIt))<<std::endl;
        }
      }
877
    }
878 879 880
  return oss.str();
}

881
bool CommandLineLauncher::CheckUnicity()
882
{
883
  bool res = true;
884
  // Extract expression keys
Mickael Savinaud's avatar
Mickael Savinaud committed
885 886
  //std::vector<std::string> keyList = m_Parser->GetKeyList(m_Expression);
  std::vector<std::string> keyList = m_Parser->GetKeyList(m_VExpression);
887 888

  // Check Unicity
889
  for (unsigned int i = 0; i < keyList.size(); i++)
890
    {
891 892
    std::vector<std::string> listTmp = keyList;
    const std::string keyRef = keyList[i];
893 894
    listTmp.erase(listTmp.begin() + i);
    for (unsigned int j = 0; j < listTmp.size(); j++)
895
      {
896
      if (keyRef == listTmp[j])
897
        {
898
        res = false;
899
        break;
900 901
        }
      }
902 903
    if (!res)
      break;
904 905 906 907 908
    }

  return res;
}

909
bool CommandLineLauncher::CheckParametersPrefix()
910
{
Mickael Savinaud's avatar
Mickael Savinaud committed
911
  // Check if the chain " --" appears in the args, could be a common mistake
OTB Bot's avatar
OTB Bot committed
912
  for (std::vector<std::string>::iterator it = m_VExpression.begin(); it != m_VExpression.end(); ++it)
913
    {
914
    if (it->compare(0, 2, "--") == 0 )
Mickael Savinaud's avatar
Mickael Savinaud committed
915 916 917
      {
      return false;
      }
918
    }
Mickael Savinaud's avatar
Mickael Savinaud committed
919
  return true;
920 921
}

922
bool CommandLineLauncher::CheckKeyValidity(std::string& refKey)
923
{
924
  bool res = true;
925
  // Extract expression keys
Mickael Savinaud's avatar
Mickael Savinaud committed
926
  std::vector<std::string> expKeyList = m_Parser->GetKeyList(m_VExpression);
927

928 929 930 931 932
  // Extract application keys
  std::vector<std::string> appKeyList = m_Application->GetParametersKeys(true);
  appKeyList.push_back("help");
  appKeyList.push_back("progress");
  appKeyList.push_back("testenv");
933
  appKeyList.push_back("version");
934

935
  // Check if each key in the expression exists in the application
936
  for (unsigned int i = 0; i < expKeyList.size(); i++)
937
    {
938
    refKey = expKeyList[i];
939
    bool keyExist = false;
940
    for (unsigned int j = 0; j < appKeyList.size(); j++)
941
      {
942
      if (refKey == appKeyList[j])
943
        {
944 945
        keyExist = true;
        break;
946
        }
947
      }
948
    if (keyExist == false)
949
      {
950
      res = false;
951 952
      break;
      }
953 954 955 956 957
    }

  return res;
}

958 959 960 961 962 963 964
void CommandLineLauncher::DisplayOutputParameters()
{
  std::vector< std::pair<std::string, std::string> > paramList;
  paramList = m_Application->GetOutputParametersSumUp();
  if( paramList.size() == 0 )
    return;

965
  std::ostringstream oss;
966 967 968 969 970 971 972 973
  for( unsigned int i=0; i<paramList.size(); i++)
    {
    oss << paramList[i].first;
    oss << ": ";
    oss << paramList[i].second;
    oss << std::endl;
    }

974

Mickael Savinaud's avatar
Mickael Savinaud committed
975
  if ( m_Parser->IsAttributExists("-testenv", m_VExpression) )
976
    {
Mickael Savinaud's avatar
Mickael Savinaud committed
977
    std::vector<std::string> val = m_Parser->GetAttribut("-testenv", m_VExpression);
978
    if( val.size() == 1 )
OTB Bot's avatar
OTB Bot committed
979
      {
980
      std::ofstream ofs(val[0]);
981 982 983 984 985 986
      if (!ofs.is_open())
        {
        fprintf(stderr, "Error, can't open file");
        itkExceptionMacro( << "Error, can't open file "<<val[0]<<".");
        }
      ofs << oss.str();
OTB Bot's avatar
OTB Bot committed
987
      ofs.close();
988 989
      }
    }
990

991
  std::cout << "Output parameters value:" << std::endl;
992 993 994
  std::cout << oss.str() << std::endl;
}

995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013
unsigned int CommandLineLauncher::GetMaxKeySize() const
{
  const std::vector<std::string> appKeyList = m_Application->GetParametersKeys(true);
  const unsigned int nbOfParam = appKeyList.size();

  unsigned int maxKeySize = std::string("progress").size();
  
  for (unsigned int i = 0; i < nbOfParam; i++)
    {
    if (m_Application->GetParameterRole(appKeyList[i]) != Role_Output)
      {
      if( maxKeySize < appKeyList[i].size() )
        maxKeySize = appKeyList[i].size();
      }
    }
  
  return maxKeySize;
}

1014 1015
}
}