00001 
00015 #ifndef USER_INFO_H
00016 #define USER_INFO_H
00017 
00018 #include <stdio.h>
00019 #include <string>
00020 #include <typeinfo>
00021 #include <map>
00022 #include <stdexcept>
00023 
00024 #include "libconfig/libconfig.h++"
00025 #include "../bdmroot.h"
00026 #include "itpp/itbase.h"
00027 
00028 
00029 using std::string;
00030 using namespace std;
00031 using namespace libconfig;
00032 
00033 namespace bdm {
00034 
00038 class UIException : public std::exception {
00039 
00040 public:
00042         const string message;
00043 
00045         const string path;
00046 
00048         UIException ( const string &message, const Setting &element )
00049                         : message ( "UI error: " + message + "." ), path ( "Check path \"" + string ( element.getPath() ) + "\"." ) {
00050         }
00051 
00053         UIException ( const string &message, const string &path )
00054                         : message ( "UI error: " + message + "." ), path ( "Check path \"" + path + "\"." ) {
00055         }
00056 
00058         virtual const char* what() const throw() {
00059                 return ( message + " " + path ).c_str();
00060         }
00061         ~UIException() throw() {};
00062 };
00063 
00064 
00089 class UIFile : public Config {
00090 public:
00092         UIFile();
00093 
00095         UIFile ( const string &file_name );
00096 
00098         void save ( const string &file_name );
00099 
00101         operator Setting&();
00102 };
00103 
00170 class SettingResolver : root {
00171 private:
00173         UIFile *file;
00174 
00180         const Setting &initialize_reference ( UIFile* &file, const Setting &potential_link );
00181 
00182 public:
00184         const Setting &result;
00185 
00187         SettingResolver ( const Setting &potential_link );
00188 
00190         ~SettingResolver();
00191 };
00192 
00203 class UI {
00204 private:
00210         class MappedUI {
00211         private:
00213                 typedef map< const string, const UI* const > StringToUIMap;
00214 
00216                 typedef map< const type_info * const, const string > TypeInfoToStringMap;
00217 
00219                 static StringToUIMap& mapped_strings();
00220 
00222                 static TypeInfoToStringMap& mapped_type_infos();
00223 
00225                 static void unregistered_class_error ( const string &unregistered_class_name );
00226 
00227         public:
00229                 static void add_class ( const string &class_name, const type_info * const class_type_info, const UI* const ui );
00230 
00232                 static const UI& retrieve_ui ( const string &class_name );
00233 
00235                 static const string& retrieve_class_name ( const type_info* const class_type_info );
00236         };
00237 
00239         static void assert_type ( const Setting &element, Setting::Type type );
00240 
00242         virtual root* new_instance() const = 0;
00243 
00245         static const Setting& to_child_setting ( const Setting &element, const int index );
00246 
00248         static const Setting& to_child_setting ( const Setting &element, const string &name );
00249 
00251         static void from_setting ( mat& matrix, const Setting &element );
00253         static void from_setting ( ivec &vector, const Setting &element );
00255         static void from_setting ( string &str, const Setting &element );
00257         static void from_setting ( vec &vector, const Setting &element );
00259         static void from_setting ( int &integer, const Setting &element );
00261         static void from_setting ( double &real, const Setting &element );
00263         template<class T> static void from_setting ( T* &instance, const Setting &element ) {
00264                 const SettingResolver link ( element );
00265                 assert_type ( link.result, Setting::TypeGroup );
00266 
00267                 
00268                 string class_name;
00269                 if ( !link.result.lookupValue ( "class", class_name ) )
00270                         throw UIException ( "the obligatory \"class\" identifier is missing", link.result );
00271 
00272                 
00273                 const UI& related_UI = MappedUI::retrieve_ui ( class_name );
00274 
00275                 root* typeless_instance = related_UI.new_instance();
00276 
00277                 instance = dynamic_cast<T*> ( typeless_instance );
00278                 if ( !instance )
00279                         throw UIException ( "class " + class_name + " is not a descendant of the desired output class. Try to call the UI::build<T> function with a different type parameter.", link.result );
00280 
00281                 try {
00282                         instance->from_setting ( link.result );
00283                 } catch ( SettingException sttng_xcptn ) {
00284                         string msg = "the method " + class_name + ".from_setting(Setting&) has thrown a SettingException. Try to correct this method. Check path \"" + sttng_xcptn.getPath() + "\".";
00285                         throw exception ( msg.c_str() );
00286                 } catch ( UIException uixcptn ) {
00287                         string msg = "the method " + class_name + ".from_setting(Setting&) has thrown an UIException \"" + uixcptn.message + "\" Try to correct this method. Check path \"" + uixcptn.path + "\".";
00288                         throw exception ( msg.c_str() );
00289                 } catch ( exception xcptn ) {
00290                         string msg = "the method " + class_name + ".from_setting(Setting&) has thrown a general exception \"" + xcptn.what() + "\" Try to correct this method. Check path \"" + element.getPath() + "\".";
00291                         throw exception ( msg.c_str() );
00292                 }
00293         }
00294 
00296         template<class T> static void from_setting ( Array<T> &array_to_load, const Setting &element ) {
00297                 const SettingResolver link ( element );
00298 
00299                 assert_type ( link.result, Setting::TypeList );
00300 
00301                 int len = link.result.getLength();
00302                 array_to_load.set_length ( len );
00303                 if ( len == 0 ) return;
00304 
00305                 for ( int i = 0; i < len; i++ )
00306                         from_setting ( array_to_load ( i ), link.result[i] );
00307         }
00308 
00313         template<class T> static void from_setting ( T &array_to_load, const Setting &element ) {
00314                 throw UIException( "from_setting is not implemented for this type", element );
00315         }
00316 
00317 
00318 protected:
00320         UI ( const string& class_name, const type_info * const class_type_info ) {
00321                 MappedUI::add_class ( class_name, class_type_info, this );
00322         }
00323 
00324 public:
00325 
00327         enum SettingPresence { optional, compulsory } ;
00328 
00332 
00336         template<class T> static T* build ( const Setting &element, const string &name, SettingPresence settingPresence = optional ) {
00337                 if ( !element.exists ( name ) )
00338                 {
00339                         if( settingPresence == optional )
00340                                 return NULL;
00341                         else
00342                                 throw UIException ( "the compulsory Setting named \"" + name + "\" is missing", element );
00343                 }
00344 
00345                 T* instance;
00346                 from_setting<T> ( instance, to_child_setting ( element, name ) );
00347                 return instance;
00348         }
00349 
00353         template<class T> static T* build ( const Setting &element, const int index, SettingPresence settingPresence = optional ) {
00354                 if ( element.getLength() <= index )
00355                 {
00356                         if( settingPresence == optional )
00357                                 return NULL;
00358                         else
00359                         {
00360                                 stringstream stream;
00361                                 stream << index;
00362                                 throw UIException ( "the compulsory Setting with the index " + stream.str()+ " is missing", element );
00363                         }
00364                 }
00365 
00366                 T* instance;
00367                 from_setting<T> ( instance, to_child_setting ( element, index ) );
00368                 return instance;
00369         }
00370 
00372         template<class T> static T* build ( const Setting &element ) {
00373                 T* instance;
00374                 from_setting<T> ( instance,  element );
00375                 return instance;
00376 
00377         }
00378 
00380 
00384 
00387         template<class T> static bool get ( T &instance, const Setting &element, const string &name, SettingPresence settingPresence = optional ) {
00388                 if ( !element.exists ( name ) )
00389                 {
00390                         if( settingPresence == optional )
00391                                 return false;
00392                         else
00393                                 throw UIException ( "the compulsory Setting named \"" + name + "\" is missing", element );
00394                 }
00395 
00396                 from_setting ( instance, to_child_setting ( element, name ) );
00397                 return true;
00398         }
00399 
00402         template<class T> static bool get ( T &instance, const Setting &element, const int index, SettingPresence settingPresence = optional ) {
00403                 if ( element.getLength() <= index )
00404                 {
00405                         if( settingPresence == optional )
00406                                 return false;
00407                         else
00408                         {
00409                                 stringstream stream;
00410                                 stream << index;
00411                                 throw UIException ( "the compulsory Setting with the index " + stream.str()+ " is missing", element );
00412                         }
00413                 }
00414 
00415                 from_setting ( instance, to_child_setting ( element, index ) );
00416                 return true;
00417         }
00418 
00420         template<class T> static bool get ( T &instance, const Setting &element ) {
00421                 from_setting ( instance, element );
00422                 return true;
00423         }
00425 
00429 
00432         template<class T> static bool get ( Array<T> &array_to_load, const Setting &element, const string &name, SettingPresence settingPresence = optional ) {
00433                 if ( !element.exists ( name ) )
00434                         return false;
00435 
00436                 from_setting ( array_to_load, to_child_setting ( element, name ) );
00437                 return true;
00438         }
00439 
00442         template<class T> static bool get ( Array<T> &array_to_load, const Setting &element, const int index, SettingPresence settingPresence = optional ) {
00443                 if ( element.getLength() <= index )
00444                         return false;
00445 
00446                 from_setting ( array_to_load, to_child_setting ( element, index ) );
00447                 return true;
00448         }
00449 
00451         template<class T> static bool get ( Array<T> &array_to_load, const Setting &element ) {
00452                 from_setting ( array_to_load, element );
00453                 return true;
00454         }
00456 
00461 
00463         template< class T> static void save ( const T * const instance, Setting &element, const string &name = "" ) {
00464                 Setting &set = ( name == "" ) ? element.add ( Setting::TypeGroup )
00465                                : element.add ( name, Setting::TypeGroup );
00466 
00467                 const string &class_name = MappedUI::retrieve_class_name ( &typeid ( *instance ) );
00468 
00469                 
00470                 Setting &type = set.add ( "class", Setting::TypeString );
00471                 type = class_name;
00472 
00473                 try {
00474                         instance->to_setting ( set );
00475                 } catch ( SettingException sttng_xcptn ) {
00476                         string msg = "the method " + class_name + ".to_setting(Setting&) has thrown a SettingException. Try to correct this method. Check path \"" + sttng_xcptn.getPath() + "\".";
00477                         throw exception ( msg.c_str() );
00478                 } catch ( UIException uixcptn ) {
00479                         string msg = "the method " + class_name + ".to_setting(Setting&) has thrown an UIException \"" + uixcptn.message + "\" Try to correct this method. Check path \"" + uixcptn.path + "\".";
00480                         throw exception ( msg.c_str() );
00481                 } catch ( exception xcptn ) {
00482                         string msg = "the method " + class_name + ".to_setting(Setting&) has thrown a general exception \"" + xcptn.what() + "\" Try to correct this method. Check path \"" + element.getPath() + "\".";
00483                         throw exception ( msg.c_str() );
00484                 }
00485         }
00486 
00488         template<class T> static void save ( const Array<T> &array_to_save, Setting &element, const string &name = "" ) {
00489                 assert_type ( element, Setting::TypeGroup );
00490                 Setting &list = ( name == "" ) ? element.add ( Setting::TypeList )
00491                                 : element.add ( name, Setting::TypeList );
00492                 for ( int i = 0; i < array_to_save.length(); i++ )
00493                         save ( array_to_save ( i ), list );
00494         }
00495 
00497         static void save ( const mat &matrix, Setting &element, const string &name = "" );
00498 
00500         static void save ( const ivec &vec, Setting &element, const string &name = "" );
00501 
00503         static void save ( const vec &vector, Setting &element, const string &name = "" );
00504 
00506         static void save ( const string &str, Setting &element, const string &name = "" );
00507 
00509         static void save ( const int &integer, Setting &element, const string &name = "" );
00510 
00512         static void save ( const double &real, Setting &element, const string &name = "" );
00514 
00515 };
00516 
00517 
00520 template<typename T> class ParticularUI : private UI {
00521 private:
00523         ParticularUI<T> ( const string &class_name ) : UI ( class_name, &typeid ( T ) ) {};
00524 
00525 public:
00527         static const ParticularUI<T>& factory;
00528 
00530         root* new_instance() const {
00531                 return new T();
00532         }
00533 };
00534 
00535 }
00536 
00546 #ifndef BDMLIB
00547 #define UIREGISTER(class_name) template<> const ParticularUI<class_name>& ParticularUI<class_name>::factory = ParticularUI<class_name>(#class_name)
00548 #else
00549 #define UIREGISTER(class_name)
00550 #endif
00551 
00552 #endif // #ifndef USER_INFO_H