// @(#)root/tmva $Id$   
// Author: Andreas Hoecker, Joerg Stelzer, Helge Voss

/**********************************************************************************
 * Project: TMVA - a Root-integrated toolkit for multivariate data analysis       *
 * Package: TMVA                                                                  *
 * Class  : Option                                                                *
 * Web    : http://tmva.sourceforge.net                                           *
 *                                                                                *
 * Description:                                                                   *
 *      Option container                                                          *
 *                                                                                *
 * Authors (alphabetical):                                                        *
 *      Andreas Hoecker <Andreas.Hocker@cern.ch> - CERN, Switzerland              *
 *      Joerg Stelzer   <Joerg.Stelzer@cern.ch>  - CERN, Switzerland              *
 *      Helge Voss      <Helge.Voss@cern.ch>     - MPI-K Heidelberg, Germany      *
 *                                                                                *
 * Copyright (c) 2005:                                                            *
 *      CERN, Switzerland                                                         * 
 *      U. of Victoria, Canada                                                    * 
 *      MPI-K Heidelberg, Germany                                                 * 
 *      LAPP, Annecy, France                                                      *
 *                                                                                *
 * Redistribution and use in source and binary forms, with or without             *
 * modification, are permitted according to the terms listed in LICENSE           *
 * (http://mva.sourceforge.net/license.txt)                                       *
 **********************************************************************************/

#ifndef ROOT_TMVA_Option
#define ROOT_TMVA_Option

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// Option                                                               //
//                                                                      //
// Class for TMVA-option handling                                        //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include <iomanip>
#include <sstream>
#include <vector>

#ifndef ROOT_TObject
#include "TObject.h"
#endif
#ifndef ROOT_TString
#include "TString.h"
#endif
#ifndef ROOT_TList
#include "TList.h"
#endif
#ifndef ROOT_TMVA_MsgLogger
#include "TMVA/MsgLogger.h"
#endif

namespace TMVA {

   class Configurable;

   class OptionBase : public TObject {

   public:

      friend class Configurable;

      OptionBase( const TString& name, const TString& desc );
      virtual ~OptionBase() {}
         
      virtual const char* GetName() const { return fNameAllLower.Data(); }
      virtual const char* TheName() const { return fName.Data(); }
      virtual TString     GetValue(Int_t i=-1) const = 0;

      Bool_t IsSet() const { return fIsSet; }
      virtual Bool_t IsArrayOpt() const = 0;
      const TString& Description() const { return fDescription; }
      virtual Bool_t IsPreDefinedVal(const TString&) const = 0;
      virtual Bool_t HasPreDefinedVal() const = 0;
      virtual Int_t  GetArraySize() const = 0;
      virtual Bool_t SetValue( const TString& vs, Int_t i=-1 );

      using TObject::Print;
      virtual void Print( std::ostream&, Int_t levelofdetail=0 ) const = 0;

   private:

      virtual void SetValueLocal(const TString& vs, Int_t i=-1) = 0;         

      const TString fName;         // name of variable 
      TString fNameAllLower;       // name of variable 
      const TString fDescription;  // its description
      Bool_t        fIsSet;        // set by user ?

   protected:

      static MsgLogger& Log();
   protected:
       
       ClassDef(OptionBase,1);
   };
      
   // ---------------------------------------------------------------------------

   template <class T>

      class Option : public OptionBase {
     
   public:

   Option( T& ref, const TString& name, const TString& desc ) : 
      OptionBase(name, desc), fRefPtr(&ref) {}
      virtual ~Option() {}

      // getters
      virtual TString  GetValue( Int_t i=-1 ) const;
      virtual const T& Value   ( Int_t i=-1 ) const;
      virtual Bool_t HasPreDefinedVal() const { return (fPreDefs.size()!=0); }
      virtual Bool_t IsPreDefinedVal( const TString& ) const; 
      virtual Bool_t IsArrayOpt()   const { return kFALSE; }
      virtual Int_t  GetArraySize() const { return 0; }

      // setters
      virtual void AddPreDefVal(const T&);
      using OptionBase::Print;
      virtual void Print       ( std::ostream&, Int_t levelofdetail=0 ) const;
      virtual void PrintPreDefs( std::ostream&, Int_t levelofdetail=0 ) const;

   protected:

      T& Value(Int_t=-1);
  
      virtual void   SetValueLocal( const TString& val, Int_t i=-1 );
      virtual Bool_t IsPreDefinedValLocal( const T& ) const;

      T* fRefPtr;
      std::vector<T> fPreDefs;  // templated vector
   };      

   template<typename T>
      class Option<T*> : public Option<T> {

   public:

   Option( T*& ref, Int_t size, const TString& name, const TString& desc ) : 
      Option<T>(*ref,name, desc), fVRefPtr(&ref), fSize(size) {}
      virtual ~Option() {}

      TString GetValue( Int_t i ) const {
         std::stringstream str;
         str << std::scientific << Value(i);
         return str.str();
      }
      const T& Value( Int_t i ) const { return (*fVRefPtr)[i]; }
      virtual Bool_t IsArrayOpt()   const { return kTRUE; }
      virtual Int_t  GetArraySize() const { return fSize; }
   
      using Option<T>::Print;
      virtual void Print( std::ostream&, Int_t levelofdetail=0 ) const;

      virtual Bool_t SetValue( const TString& val, Int_t i=0 );

      T& Value(Int_t i) { return (*fVRefPtr)[i]; }
      T ** fVRefPtr;
      Int_t fSize;

   };

} // namespace

namespace TMVA {

   //______________________________________________________________________
   template<class T>
      inline const T& TMVA::Option<T>::Value( Int_t ) const {
      return *fRefPtr;
   }

   template<class T>
      inline T& TMVA::Option<T>::Value( Int_t ) {
      return *fRefPtr;
   }

   template<class T>
      inline TString TMVA::Option<T>::GetValue( Int_t ) const {
      std::stringstream str;      
      str << std::scientific << this->Value();
      return str.str();
   }

   template<>
      inline TString TMVA::Option<Bool_t>::GetValue( Int_t ) const {
      return Value() ? "True" : "False";
   }

   template<>
      inline TString TMVA::Option<Bool_t*>::GetValue( Int_t i ) const {
      return Value(i) ? "True" : "False";
   }

   template<class T>
      inline Bool_t TMVA::Option<T>::IsPreDefinedVal( const TString& val ) const 
      {
         // template 
         T tmpVal;
         std::stringstream str(val.Data());
         str >> tmpVal;
         return IsPreDefinedValLocal(tmpVal);
      }

   template<class T>
      inline Bool_t TMVA::Option<T>::IsPreDefinedValLocal(const T& val) const 
      {
         // template
         if (fPreDefs.size()==0) return kTRUE; // if nothing pre-defined then allow everything

         typename std::vector<T>::const_iterator predefIt;
         predefIt = fPreDefs.begin();
         for (;predefIt!=fPreDefs.end(); predefIt++) 
            if ( (*predefIt)==val ) return kTRUE;
      
         return kFALSE;
      }

   template<>
      inline Bool_t TMVA::Option<TString>::IsPreDefinedValLocal( const TString& val ) const 
      {
         // template specialization for Bool_t 
         TString tVal(val);
         tVal.ToLower();
         if (fPreDefs.size()==0) return kFALSE; // if nothing pre-defined then allow everything
         Bool_t foundPreDef = kFALSE;   
         std::vector<TString>::const_iterator predefIt;
         predefIt = fPreDefs.begin();
         for (;predefIt!=fPreDefs.end(); predefIt++) {
            TString s(*predefIt);
            s.ToLower();
            if (s==tVal) { foundPreDef = kTRUE; break; }
         }
         return foundPreDef;
      }

   //______________________________________________________________________
   template<class T>
      inline void TMVA::Option<T>::AddPreDefVal( const T& val ) 
      {
         // template 
         fPreDefs.push_back(val);
      }

   template<>
      inline void TMVA::Option<Bool_t>::AddPreDefVal( const Bool_t& ) 
      {
         // template specialization for Bool_t 
         Log() << kFATAL << "<AddPreDefVal> predefined values for Option<Bool_t> don't make sense" 
               << Endl;
      }

   template<>
      inline void TMVA::Option<Float_t>::AddPreDefVal( const Float_t& ) 
      {
         // template specialization for Float_t 
         Log() << kFATAL << "<AddPreDefVal> predefined values for Option<Float_t> don't make sense" 
               << Endl;
      }

   template<class T>
      inline void TMVA::Option<T>::Print( std::ostream& os, Int_t levelofdetail ) const 
      {
         // template specialization for TString printing
         os << TheName() << ": " << "\"" << GetValue() << "\"" << " [" << Description() << "]";
         this->PrintPreDefs(os,levelofdetail);
      }

   template<class T>
      inline void TMVA::Option<T*>::Print( std::ostream& os, Int_t levelofdetail ) const 
      {
         // template specialization for TString printing
         for (Int_t i=0; i<fSize; i++) {
            if (i==0)
               os << this->TheName() << "[" << i << "]: " << "\"" << this->GetValue(i) << "\"" << " [" << this->Description() << "]";
            else
               os << "    " << this->TheName() << "[" << i << "]: " << "\"" << this->GetValue(i) << "\"";
            if (i!=fSize-1) os << std::endl;
         }
         this->PrintPreDefs(os,levelofdetail);
      }

   //______________________________________________________________________
   template<class T>
      inline void TMVA::Option<T>::PrintPreDefs( std::ostream& os, Int_t levelofdetail ) const 
      {
         // template specialization for TString printing
         if (HasPreDefinedVal() && levelofdetail>0) {
            os << std::endl << "PreDefined - possible values are:" << std::endl;
            typename std::vector<T>::const_iterator predefIt;
            predefIt = fPreDefs.begin();
            for (;predefIt!=fPreDefs.end(); predefIt++) {
               os << "                       ";
               os << "  - " << (*predefIt) << std::endl;
            }
         }
      }
   
   //______________________________________________________________________
   template<class T>
      inline Bool_t TMVA::Option<T*>::SetValue( const TString& val, Int_t ind ) 
      {
         // template 
         if (ind >= fSize) return kFALSE;
         std::stringstream str(val.Data());
         if (ind < 0) {
            str >> Value(0);
            for (Int_t i=1; i<fSize; i++) Value(i) = Value(0);      
         } 
         else {
            str >> Value(ind);
         }
         return kTRUE;
      }

   template<class T>
      inline void TMVA::Option<T>::SetValueLocal( const TString& val, Int_t i ) 
      {
         // template 
         std::stringstream str(val.Data());
         str >> Value(i);
      }

   template<>
      inline void TMVA::Option<TString>::SetValueLocal( const TString& val, Int_t ) 
      {
         // set TString value
         TString valToSet(val);
         if (fPreDefs.size()!=0) {
            TString tVal(val);
            tVal.ToLower();
            std::vector<TString>::const_iterator predefIt;
            predefIt = fPreDefs.begin();
            for (;predefIt!=fPreDefs.end(); predefIt++) {
               TString s(*predefIt);
               s.ToLower();
               if (s==tVal) { valToSet = *predefIt; break; }
            }
         }

         std::stringstream str(valToSet.Data());
         str >> Value(-1);
      }

   template<>
      inline void TMVA::Option<Bool_t>::SetValueLocal( const TString& val, Int_t ) 
      {
         // set Bool_t value
         TString valToSet(val);
         valToSet.ToLower();
         if (valToSet=="1" || valToSet=="true" || valToSet=="ktrue" || valToSet=="t") {
            this->Value() = true;
         }
         else if (valToSet=="0" || valToSet=="false" || valToSet=="kfalse" || valToSet=="f") {
            this->Value() = false;
         }
         else {
            Log() << kFATAL << "<SetValueLocal> value \'" << val 
                  << "\' can not be interpreted as boolean" << Endl;
         }
      }
}
#endif
 Option.h:1
 Option.h:2
 Option.h:3
 Option.h:4
 Option.h:5
 Option.h:6
 Option.h:7
 Option.h:8
 Option.h:9
 Option.h:10
 Option.h:11
 Option.h:12
 Option.h:13
 Option.h:14
 Option.h:15
 Option.h:16
 Option.h:17
 Option.h:18
 Option.h:19
 Option.h:20
 Option.h:21
 Option.h:22
 Option.h:23
 Option.h:24
 Option.h:25
 Option.h:26
 Option.h:27
 Option.h:28
 Option.h:29
 Option.h:30
 Option.h:31
 Option.h:32
 Option.h:33
 Option.h:34
 Option.h:35
 Option.h:36
 Option.h:37
 Option.h:38
 Option.h:39
 Option.h:40
 Option.h:41
 Option.h:42
 Option.h:43
 Option.h:44
 Option.h:45
 Option.h:46
 Option.h:47
 Option.h:48
 Option.h:49
 Option.h:50
 Option.h:51
 Option.h:52
 Option.h:53
 Option.h:54
 Option.h:55
 Option.h:56
 Option.h:57
 Option.h:58
 Option.h:59
 Option.h:60
 Option.h:61
 Option.h:62
 Option.h:63
 Option.h:64
 Option.h:65
 Option.h:66
 Option.h:67
 Option.h:68
 Option.h:69
 Option.h:70
 Option.h:71
 Option.h:72
 Option.h:73
 Option.h:74
 Option.h:75
 Option.h:76
 Option.h:77
 Option.h:78
 Option.h:79
 Option.h:80
 Option.h:81
 Option.h:82
 Option.h:83
 Option.h:84
 Option.h:85
 Option.h:86
 Option.h:87
 Option.h:88
 Option.h:89
 Option.h:90
 Option.h:91
 Option.h:92
 Option.h:93
 Option.h:94
 Option.h:95
 Option.h:96
 Option.h:97
 Option.h:98
 Option.h:99
 Option.h:100
 Option.h:101
 Option.h:102
 Option.h:103
 Option.h:104
 Option.h:105
 Option.h:106
 Option.h:107
 Option.h:108
 Option.h:109
 Option.h:110
 Option.h:111
 Option.h:112
 Option.h:113
 Option.h:114
 Option.h:115
 Option.h:116
 Option.h:117
 Option.h:118
 Option.h:119
 Option.h:120
 Option.h:121
 Option.h:122
 Option.h:123
 Option.h:124
 Option.h:125
 Option.h:126
 Option.h:127
 Option.h:128
 Option.h:129
 Option.h:130
 Option.h:131
 Option.h:132
 Option.h:133
 Option.h:134
 Option.h:135
 Option.h:136
 Option.h:137
 Option.h:138
 Option.h:139
 Option.h:140
 Option.h:141
 Option.h:142
 Option.h:143
 Option.h:144
 Option.h:145
 Option.h:146
 Option.h:147
 Option.h:148
 Option.h:149
 Option.h:150
 Option.h:151
 Option.h:152
 Option.h:153
 Option.h:154
 Option.h:155
 Option.h:156
 Option.h:157
 Option.h:158
 Option.h:159
 Option.h:160
 Option.h:161
 Option.h:162
 Option.h:163
 Option.h:164
 Option.h:165
 Option.h:166
 Option.h:167
 Option.h:168
 Option.h:169
 Option.h:170
 Option.h:171
 Option.h:172
 Option.h:173
 Option.h:174
 Option.h:175
 Option.h:176
 Option.h:177
 Option.h:178
 Option.h:179
 Option.h:180
 Option.h:181
 Option.h:182
 Option.h:183
 Option.h:184
 Option.h:185
 Option.h:186
 Option.h:187
 Option.h:188
 Option.h:189
 Option.h:190
 Option.h:191
 Option.h:192
 Option.h:193
 Option.h:194
 Option.h:195
 Option.h:196
 Option.h:197
 Option.h:198
 Option.h:199
 Option.h:200
 Option.h:201
 Option.h:202
 Option.h:203
 Option.h:204
 Option.h:205
 Option.h:206
 Option.h:207
 Option.h:208
 Option.h:209
 Option.h:210
 Option.h:211
 Option.h:212
 Option.h:213
 Option.h:214
 Option.h:215
 Option.h:216
 Option.h:217
 Option.h:218
 Option.h:219
 Option.h:220
 Option.h:221
 Option.h:222
 Option.h:223
 Option.h:224
 Option.h:225
 Option.h:226
 Option.h:227
 Option.h:228
 Option.h:229
 Option.h:230
 Option.h:231
 Option.h:232
 Option.h:233
 Option.h:234
 Option.h:235
 Option.h:236
 Option.h:237
 Option.h:238
 Option.h:239
 Option.h:240
 Option.h:241
 Option.h:242
 Option.h:243
 Option.h:244
 Option.h:245
 Option.h:246
 Option.h:247
 Option.h:248
 Option.h:249
 Option.h:250
 Option.h:251
 Option.h:252
 Option.h:253
 Option.h:254
 Option.h:255
 Option.h:256
 Option.h:257
 Option.h:258
 Option.h:259
 Option.h:260
 Option.h:261
 Option.h:262
 Option.h:263
 Option.h:264
 Option.h:265
 Option.h:266
 Option.h:267
 Option.h:268
 Option.h:269
 Option.h:270
 Option.h:271
 Option.h:272
 Option.h:273
 Option.h:274
 Option.h:275
 Option.h:276
 Option.h:277
 Option.h:278
 Option.h:279
 Option.h:280
 Option.h:281
 Option.h:282
 Option.h:283
 Option.h:284
 Option.h:285
 Option.h:286
 Option.h:287
 Option.h:288
 Option.h:289
 Option.h:290
 Option.h:291
 Option.h:292
 Option.h:293
 Option.h:294
 Option.h:295
 Option.h:296
 Option.h:297
 Option.h:298
 Option.h:299
 Option.h:300
 Option.h:301
 Option.h:302
 Option.h:303
 Option.h:304
 Option.h:305
 Option.h:306
 Option.h:307
 Option.h:308
 Option.h:309
 Option.h:310
 Option.h:311
 Option.h:312
 Option.h:313
 Option.h:314
 Option.h:315
 Option.h:316
 Option.h:317
 Option.h:318
 Option.h:319
 Option.h:320
 Option.h:321
 Option.h:322
 Option.h:323
 Option.h:324
 Option.h:325
 Option.h:326
 Option.h:327
 Option.h:328
 Option.h:329
 Option.h:330
 Option.h:331
 Option.h:332
 Option.h:333
 Option.h:334
 Option.h:335
 Option.h:336
 Option.h:337
 Option.h:338
 Option.h:339
 Option.h:340
 Option.h:341
 Option.h:342
 Option.h:343
 Option.h:344
 Option.h:345
 Option.h:346
 Option.h:347
 Option.h:348
 Option.h:349
 Option.h:350
 Option.h:351
 Option.h:352
 Option.h:353
 Option.h:354
 Option.h:355
 Option.h:356
 Option.h:357
 Option.h:358
 Option.h:359
 Option.h:360
 Option.h:361
 Option.h:362
 Option.h:363
 Option.h:364
 Option.h:365
 Option.h:366
 Option.h:367
 Option.h:368