00001 #ifndef USER_INFO_H
00002 #define USER_INFO_H
00003 
00004 #include <stdio.h>
00005 #include <string>
00006 #include <typeinfo>
00007 #include <map>
00008 
00009 #include "libconfig/libconfig.h++"
00010 #include "bdmroot.h"
00011 #include "itpp/itbase.h"
00012 
00013 
00014 using std::string;
00015 using namespace std;
00016 using namespace libconfig;
00017 
00018 #ifndef BDMLIB 
00019 #define UIREGISTER(class_name) template<> const Particular_UI<class_name>& Particular_UI<class_name>::ui = Particular_UI<class_name>(#class_name) 
00020 #warning BDMLIB-defined
00021 #else
00022 #define UIREGISTER(class_name)
00023 #warning BDMLIB-empty
00024 #endif
00025 
00026 #define ASSERT_UITYPE(S,Type) it_assert_debug(S.getType()==Setting::Type, string("Wrong setting type, see input path \"")+string(S.getPath())+string("\""))
00027 
00028 namespace bdm
00029 {
00030 class UI_File : public Config
00031 {
00032 private:
00033         const string file_name;
00034 
00035 public:
00037         UI_File();
00038 
00040         UI_File( const string &file_name );
00041 
00043         void save(const string &file_name);
00044 
00045         operator Setting&();
00046 };
00047 
00079 class UI 
00080 {
00081 private:
00086         class Mapped_UI
00087         {
00088         private:
00090                 typedef map< const string, const UI* const > String_To_UI_Map;
00091 
00093                 typedef map< const type_info * const, const string > Type_Info_To_String_Map;
00094 
00096                 static String_To_UI_Map& mapped_strings();
00097 
00099                 static Type_Info_To_String_Map& mapped_type_infos();
00100 
00101         public:
00103                 static void add_class( const string &class_name, const type_info * const class_type_info, const UI* const ui );
00104 
00106                 static const UI& retrieve_ui( const string &class_name );
00107 
00109                 static const string& retrieve_class_name( const type_info* const class_type_info );
00110         };
00111 
00112 
00113 
00114 
00116         virtual bdmroot* new_instance() const = 0;
00117         
00121         static const Setting& to_child_setting( const Setting &element, const int index );
00122 
00123         static const Setting& to_child_setting( const Setting &element, const string &name );
00124 
00125 
00128 
00130         static void from_setting( mat& matrix, const Setting &element );        
00132         static void from_setting( ivec &vector, const Setting &element );
00133         
00134         static void from_setting( string &str, const Setting &element );
00136 
00137         static void from_setting( vec &vector, const Setting &element );
00138 
00139         template<class T> static void from_setting( T* &instance, const Setting &element )
00140         {                       
00141                 const SettingsResolver link_expander( element );
00142                 const Setting &root = link_expander.root();
00143 
00144                 ASSERT_UITYPE(root,TypeGroup);
00145 
00146                 
00147                 string class_name;
00148                 if( !root.lookupValue( "class", class_name ) )
00149                         ui_error( "the obligatory ""class"" identifier is missing", root );
00150         
00151                 
00152                 const UI& related_UI = Mapped_UI::retrieve_ui( class_name );
00153                 
00154                 bdmroot* typeless_instance = related_UI.new_instance();
00155 
00156                 instance = NULL;
00157                 try
00158                 {
00159                         instance = (T*) typeless_instance ;
00160                 }
00161                 catch(...)
00162                 {
00163                         it_error ( "UI error: class " + class_name + " is not a descendant of the desired output class. Try to call the UI::build function with a different type parameter." );
00164                 }
00165                 
00166                 try
00167                 {
00168                         instance->from_setting( root );
00169                 }
00170                 catch(SettingException xcptn)
00171                 {
00172                         it_error ( "UI error: the method " + class_name + ".from_setting(Setting&) has thrown an exception when parsing the setting " + xcptn.getPath() + ". Try to correct this method." );
00173                 }
00174         }       
00175 
00176 
00178         
00179         template<class T> static void from_setting( Array<T> &array_to_load, const Setting &element )
00180         {
00181                 const SettingsResolver link_expander( element );
00182                 const Setting &root = link_expander.root();
00183 
00184                 ASSERT_UITYPE(root,TypeList);
00185 
00186                 int len = root.getLength();
00187                 array_to_load.set_length( len );
00188                 if( len == 0 ) return;
00189                 
00190                 for( int i=0; i < len; i++ ) 
00191                         from_setting( array_to_load(i), root[i] ); 
00192         }
00193 
00195 
00196 
00197         static void ui_error( string message, const Setting &element );
00198 
00199 protected:
00201         UI( const string& class_name, const type_info * const class_type_info ) 
00202         {       
00203                 Mapped_UI::add_class( class_name, class_type_info, this );
00204         }
00205 
00207         virtual ~UI(){};
00208 
00209 public: 
00213 
00214         
00215         
00216         class SettingsResolver  
00217         {
00218         private:
00219                 UI_File *file;
00220                 const Setting *result;
00221 
00222         public:
00223 
00224                 SettingsResolver( const Setting &potential_link );
00225                 
00226                 ~SettingsResolver();
00227                 
00228                 const Setting& root() const;
00229         };
00230 
00231 
00232 
00234         template<class T> static T* build( const Setting &element, const int index )
00235         {
00236                 T* instance;
00237                 from_setting<T>( to_child_setting( element, index ) );
00238                 return instance;
00239         }
00240 
00241         template<class T> static T* build( const Setting &element, const string &name )
00242         {                       
00243                 T* instance;
00244                 from_setting<T>( instance, to_child_setting( element, name ) );
00245                 return instance;
00246         }
00247 
00249         template<class T> static void get( T &instance, const Setting &element, const string &name )
00250         {
00251                 from_setting( instance, to_child_setting( element, name ) );
00252         }
00253 
00255         template<class T> static void get( T &instance, const Setting &element, const int index )
00256         {
00257                 from_setting( instance, to_child_setting( element, index ) );
00258         }
00259 
00261         template<class T> static void get( Array<T> &array_to_load, const Setting &element, const string &name )
00262         {
00263                 from_setting( array_to_load, to_child_setting( element, name ) );
00264         }
00265 
00267         template<class T> static void get( Array<T> &array_to_load, const Setting &element, const int index )
00268         {
00269                 from_setting( array_to_load, to_child_setting( element, index ) );
00270         }
00271 
00272         template< class T> static void save( const T * const instance, Setting &element, const string &name = "")
00273         {
00274                 Setting &root = (name == "") ? element.add( Setting::TypeGroup )                                                        
00275                                                                          : element.add( name, Setting::TypeGroup );             
00276 
00277                 const string &class_name = Mapped_UI::retrieve_class_name( &typeid(*instance) );
00278                         
00279                 
00280                 Setting &type = root.add( "class", Setting::TypeString );
00281                 type = class_name;
00282 
00283                 try
00284                 {
00285                         instance->to_setting( root );
00286                 }
00287                 catch(SettingException xcptn)
00288                 {
00289                         it_error ( "UI error: the method " + class_name + ".to_setting(Setting&) has thrown an exception when filling the setting " + xcptn.getPath() + ". Try to correct this method." );
00290                 }       
00291         }
00292 
00294         template<class T> static void save( const Array<T> &array_to_save, Setting &element, const string &name = "" )
00295         {
00296                 ASSERT_UITYPE(element,TypeGroup);
00297                 Setting &list = (name == "") ? element.add( Setting::TypeList )                                                 
00298                                                                          : element.add( name, Setting::TypeList );              
00299                 for( int i=0; i<array_to_save.length(); i++ ) 
00300                         save( array_to_save(i), list );
00301         }
00302 
00303 
00305         static void save( const mat &matrix, Setting &element, const string &name = "" );
00306 
00308         static void save( const ivec &vec, Setting &element, const string &name = "" );
00309         
00310         static void save( const vec &vector, Setting &element, const string &name);
00311 
00312         private: 
00314         static void save( const string &str, Setting &element); 
00315 
00316 };
00317 
00318 
00324 template<typename T> class Particular_UI : private UI
00325 {
00326         public:
00327 
00329         Particular_UI<T>( const string &class_name) : UI( class_name, &typeid(T) ) 
00330         {       cout << class_name << endl;
00331         };
00332 
00335         static const Particular_UI<T>& ui;      
00336 
00337         bdmroot* new_instance() const
00338         {
00339                 return new T();
00340         }
00341 };
00342 
00343 
00344 
00345 
00346 }
00347 
00371 #endif // #ifndef USER_INFO_H