// @(#)root/tmva:$Id$
// Author: Omar Zapata   2016

/*************************************************************************
 * Copyright (C) 2016, Omar Andres Zapata Mesa                           *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/
#ifndef ROOT_TMVA_OptionMap
#define ROOT_TMVA_OptionMap

#include <sstream>
#include<iostream>
#include<map>

#ifndef ROOT_TNamed
#include<TNamed.h>
#endif

#ifndef ROOT_TMVA_MsgLogger
#include "TMVA/MsgLogger.h"
#endif

#ifndef ROOT_TObjString
#include "TObjString.h"
#endif

#ifndef ROOT_TObjArray
#include "TObjArray.h"
#endif


namespace TMVA {
       
       /**
        *      \class OptionMap
        *         class to storage options for the differents methods
        *         \ingroup TMVA
        */
       
       class OptionMap
       {
       protected:
           TString fName;
           std::map<TString,TString> fOptMap; //
           TMVA::MsgLogger fLogger;                 //!
           class Binding
           {
           private:
               std::map<TString,TString> &fInternalMap;
               TString fInternalKey;
           public:
               Binding(std::map<TString,TString>  &fmap,TString key):fInternalMap(fmap),fInternalKey(key){}
               Binding(const Binding &obj):fInternalMap(obj.fInternalMap)  
               {
                   fInternalKey  = obj.fInternalKey;
               }
               ~Binding(){}
               void SetKey(TString key){fInternalKey=key;}
               TString GetKey(){return fInternalKey;}
               Binding &operator=(const Binding &obj)
               {
                   fInternalMap  = obj.fInternalMap;    
                   fInternalKey  = obj.fInternalKey;
                   return *this;
               }
               
               template<class T> Binding& operator=(const T &value)
               {
                   ParseValue(fInternalMap[fInternalKey],*const_cast<T*>(&value));
                   return *this;
               }
               
               template<class T> operator T()
               {
                   return GetValue<T>();
               }
               template<class T> T GetValue()
               {
                   T result;
                   ParseValue(fInternalMap[fInternalKey],result,kFALSE);
                   return result;
               }
            
               template<class T> void  ParseValue(TString &str,T &value,Bool_t input=kTRUE)
               {
                   std::stringstream fStringStream;
                   if(input)
                   {
                       fStringStream<<value;
                       str=fStringStream.str();
                   }else{
                       fStringStream<<str.Data();
                       fStringStream>>value;
                   }
                   
               }

               
           };
           Binding fBinder;     //!
       public:
           OptionMap(const TString options="",const TString name="Option"):fName(name),fLogger(name.Data()),fBinder(fOptMap,""){
               ParseOption(options); 
           }
           
           OptionMap(const Char_t *options,const TString name="Option"):fName(name),fLogger(name.Data()),fBinder(fOptMap,""){
               ParseOption(options); 
           }
           OptionMap(const OptionMap &obj):fBinder(obj.fBinder)
           {
               fName   = obj.fName;
               fLogger = obj.fLogger;
           }
//            OptionMap(const Char_t *options,const TString name="Option"):fName(name),fLogger(name.Data()),fBinder(fOptMap,"")
//            {
//              ParseOption(options);  
//            }
           
           virtual ~OptionMap(){}
           
           Bool_t IsEmpty(){return fOptMap.empty();}
           
           Bool_t HasKey(TString key)
           {
               return fOptMap.count( key )==1;
           }
           
           Binding& operator[](TString key)
           {
               fBinder.SetKey(key);
               return fBinder;
           }
           
           OptionMap& operator=(TString options)
           {
               ParseOption(options);
               return *this;
           }
           
           void Print() const
           {
               MsgLogger Log(fLogger);
               for(auto &item:fOptMap)
               {
                   Log<<kINFO<<item.first.Data()<<": "<<item.second.Data()<<Endl;
               }
           }

           template<class T> T GetValue(const TString & key)
           {
               T result;
               fBinder.ParseValue(fOptMap[key],result,kFALSE);
               return result;
           }
           
           
           template<class T> T GetValue(const TString & key) const
           {
               T result;
               std::stringstream oss;
               oss<<fOptMap.at(key);
               oss>>result;
               return result;
           }
           void ParseOption(TString options)
           {
               options.ReplaceAll(" ","");
               auto opts=options.Tokenize(":");
               for(auto opt:*opts)
               {
                   TObjString *objstr=(TObjString*)opt;
                   
                   if(objstr->GetString().Contains("="))
                   {
                      auto pair=objstr->String().Tokenize("=");
                      TObjString *key   = (TObjString *)pair->At(0);
                      TObjString *value = (TObjString *)pair->At(1);
                      
                      fOptMap[key->GetString()] = value->GetString();
                   }else{
                      if(objstr->GetString().BeginsWith("!"))
                      {
                          objstr->GetString().ReplaceAll("!","");
                          fOptMap[objstr->GetString()]=TString("0");    
                      }else{
                          fOptMap[objstr->GetString()]=TString("1");                              
                      }
                   }
               }

           }
           ClassDef(OptionMap,1);
       };
       
}

#endif
 OptionMap.h:1
 OptionMap.h:2
 OptionMap.h:3
 OptionMap.h:4
 OptionMap.h:5
 OptionMap.h:6
 OptionMap.h:7
 OptionMap.h:8
 OptionMap.h:9
 OptionMap.h:10
 OptionMap.h:11
 OptionMap.h:12
 OptionMap.h:13
 OptionMap.h:14
 OptionMap.h:15
 OptionMap.h:16
 OptionMap.h:17
 OptionMap.h:18
 OptionMap.h:19
 OptionMap.h:20
 OptionMap.h:21
 OptionMap.h:22
 OptionMap.h:23
 OptionMap.h:24
 OptionMap.h:25
 OptionMap.h:26
 OptionMap.h:27
 OptionMap.h:28
 OptionMap.h:29
 OptionMap.h:30
 OptionMap.h:31
 OptionMap.h:32
 OptionMap.h:33
 OptionMap.h:34
 OptionMap.h:35
 OptionMap.h:36
 OptionMap.h:37
 OptionMap.h:38
 OptionMap.h:39
 OptionMap.h:40
 OptionMap.h:41
 OptionMap.h:42
 OptionMap.h:43
 OptionMap.h:44
 OptionMap.h:45
 OptionMap.h:46
 OptionMap.h:47
 OptionMap.h:48
 OptionMap.h:49
 OptionMap.h:50
 OptionMap.h:51
 OptionMap.h:52
 OptionMap.h:53
 OptionMap.h:54
 OptionMap.h:55
 OptionMap.h:56
 OptionMap.h:57
 OptionMap.h:58
 OptionMap.h:59
 OptionMap.h:60
 OptionMap.h:61
 OptionMap.h:62
 OptionMap.h:63
 OptionMap.h:64
 OptionMap.h:65
 OptionMap.h:66
 OptionMap.h:67
 OptionMap.h:68
 OptionMap.h:69
 OptionMap.h:70
 OptionMap.h:71
 OptionMap.h:72
 OptionMap.h:73
 OptionMap.h:74
 OptionMap.h:75
 OptionMap.h:76
 OptionMap.h:77
 OptionMap.h:78
 OptionMap.h:79
 OptionMap.h:80
 OptionMap.h:81
 OptionMap.h:82
 OptionMap.h:83
 OptionMap.h:84
 OptionMap.h:85
 OptionMap.h:86
 OptionMap.h:87
 OptionMap.h:88
 OptionMap.h:89
 OptionMap.h:90
 OptionMap.h:91
 OptionMap.h:92
 OptionMap.h:93
 OptionMap.h:94
 OptionMap.h:95
 OptionMap.h:96
 OptionMap.h:97
 OptionMap.h:98
 OptionMap.h:99
 OptionMap.h:100
 OptionMap.h:101
 OptionMap.h:102
 OptionMap.h:103
 OptionMap.h:104
 OptionMap.h:105
 OptionMap.h:106
 OptionMap.h:107
 OptionMap.h:108
 OptionMap.h:109
 OptionMap.h:110
 OptionMap.h:111
 OptionMap.h:112
 OptionMap.h:113
 OptionMap.h:114
 OptionMap.h:115
 OptionMap.h:116
 OptionMap.h:117
 OptionMap.h:118
 OptionMap.h:119
 OptionMap.h:120
 OptionMap.h:121
 OptionMap.h:122
 OptionMap.h:123
 OptionMap.h:124
 OptionMap.h:125
 OptionMap.h:126
 OptionMap.h:127
 OptionMap.h:128
 OptionMap.h:129
 OptionMap.h:130
 OptionMap.h:131
 OptionMap.h:132
 OptionMap.h:133
 OptionMap.h:134
 OptionMap.h:135
 OptionMap.h:136
 OptionMap.h:137
 OptionMap.h:138
 OptionMap.h:139
 OptionMap.h:140
 OptionMap.h:141
 OptionMap.h:142
 OptionMap.h:143
 OptionMap.h:144
 OptionMap.h:145
 OptionMap.h:146
 OptionMap.h:147
 OptionMap.h:148
 OptionMap.h:149
 OptionMap.h:150
 OptionMap.h:151
 OptionMap.h:152
 OptionMap.h:153
 OptionMap.h:154
 OptionMap.h:155
 OptionMap.h:156
 OptionMap.h:157
 OptionMap.h:158
 OptionMap.h:159
 OptionMap.h:160
 OptionMap.h:161
 OptionMap.h:162
 OptionMap.h:163
 OptionMap.h:164
 OptionMap.h:165
 OptionMap.h:166
 OptionMap.h:167
 OptionMap.h:168
 OptionMap.h:169
 OptionMap.h:170
 OptionMap.h:171
 OptionMap.h:172
 OptionMap.h:173
 OptionMap.h:174
 OptionMap.h:175
 OptionMap.h:176
 OptionMap.h:177
 OptionMap.h:178
 OptionMap.h:179
 OptionMap.h:180
 OptionMap.h:181
 OptionMap.h:182
 OptionMap.h:183
 OptionMap.h:184
 OptionMap.h:185
 OptionMap.h:186
 OptionMap.h:187
 OptionMap.h:188
 OptionMap.h:189
 OptionMap.h:190
 OptionMap.h:191
 OptionMap.h:192
 OptionMap.h:193
 OptionMap.h:194
 OptionMap.h:195
 OptionMap.h:196
 OptionMap.h:197
 OptionMap.h:198
 OptionMap.h:199
 OptionMap.h:200