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 "../shared_ptr.h"
00027 #include "itpp/itbase.h"
00028 
00029 
00030 using std::string;
00031 using namespace std;
00032 using namespace libconfig;
00033 
00034 namespace bdm {
00035 
00039 class UIException : public std::exception {
00040 
00041 public:
00043         const string message;
00044 
00046         const string path;
00047 
00048 private:
00049         string what_message;
00050 
00051 public:
00053         UIException ( const string &message, const Setting &element )
00054                         : message ( "UI error: " + message + "." ), path ( "Check path \"" + string ( element.getPath() ) + "\"." ) {
00055                 init_what_message();
00056         }
00057 
00059         UIException ( const string &message, const string &path )
00060                         : message ( "UI error: " + message + "." ), path ( "Check path \"" + path + "\"." ) {
00061                 init_what_message();
00062         }
00063 
00065         virtual const char* what() const throw() {
00066                 return what_message.c_str();
00067         }
00068 
00069         ~UIException() throw() {};
00070 
00071 private:
00072         void init_what_message() {
00073                 what_message = message;
00074                 what_message += ' ';
00075                 what_message += path;
00076         }
00077 };
00078 
00079 
00104 class UIFile : public Config {
00105 public:
00107         UIFile();
00108 
00110         UIFile ( const string &file_name );
00111 
00113         void save ( const string &file_name );
00114 
00116         operator Setting&();
00117 };
00118 
00185 class SettingResolver : root {
00186 private:
00188         UIFile *file;
00189 
00195         const Setting &initialize_reference ( UIFile* &file, const Setting &potential_link );
00196 
00197 public:
00199         const Setting &result;
00200 
00202         SettingResolver ( const Setting &potential_link );
00203 
00205         ~SettingResolver();
00206 };
00207 
00218 class UI {
00219 private:
00225         class MappedUI {
00226         private:
00228                 typedef map< const string, const UI* const > StringToUIMap;
00229 
00231                 typedef map< const type_info * const, const string > TypeInfoToStringMap;
00232 
00234                 static StringToUIMap& mapped_strings();
00235 
00237                 static TypeInfoToStringMap& mapped_type_infos();
00238 
00240                 static void unregistered_class_error ( const string &unregistered_class_name );
00241 
00242         public:
00244                 static void add_class ( const string &class_name, const type_info * const class_type_info, const UI* const ui );
00245 
00247                 static const UI& retrieve_ui ( const string &class_name );
00248 
00250                 static const string& retrieve_class_name ( const type_info* const class_type_info );
00251         };
00252 
00254         static void assert_type ( const Setting &element, Setting::Type type );
00255 
00264         virtual root* new_instance() const = 0;
00265 
00267         static const Setting& to_child_setting ( const Setting &element, const int index );
00268 
00270         static const Setting& to_child_setting ( const Setting &element, const string &name );
00271 
00273         static void from_setting ( mat& matrix, const Setting &element );
00275         static void from_setting ( ivec &vector, const Setting &element );
00277         static void from_setting ( string &str, const Setting &element );
00279         static void from_setting ( vec &vector, const Setting &element );
00281         static void from_setting ( int &integer, const Setting &element );
00283         static void from_setting ( double &real, const Setting &element );
00284 
00286         template<class T> static void from_setting ( T* &instance, const Setting &element ) {
00287                 const SettingResolver link ( element );
00288                 assert_type ( link.result, Setting::TypeGroup );
00289 
00290                 
00291                 string class_name;
00292                 if ( !link.result.lookupValue ( "class", class_name ) )
00293                         throw UIException ( "the obligatory \"class\" identifier is missing", link.result );
00294 
00295                 
00296                 const UI& related_UI = MappedUI::retrieve_ui ( class_name );
00297 
00298                 root *typeless_instance = related_UI.new_instance();
00299                 it_assert_debug ( typeless_instance, "UI::new_instance failed" );
00300 
00301                 instance = dynamic_cast<T*> ( typeless_instance );
00302                 if ( !instance ) {
00303                         delete typeless_instance;
00304                         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 );
00305                 }
00306 
00307                 try {
00308                         instance->from_setting ( link.result );
00309                 } catch ( SettingException sttng_xcptn ) {
00310                         string msg = "the method " + class_name + ".from_setting(Setting&) has thrown a SettingException. Try to correct this method. Check path \"" + sttng_xcptn.getPath() + "\".";
00311                         throw UIException(msg, link.result);
00312                 }
00313         }
00314 
00317         template<class T>
00318         static void from_setting ( shared_ptr<T> &instance, const Setting &element ) {
00319                 T *tmp_inst = 0;
00320                 from_setting ( tmp_inst, element );
00321                 it_assert_debug ( tmp_inst, "UI::from_setting failed" );
00322                 instance = tmp_inst;
00323         }
00324 
00326         template<class T> static void from_setting ( Array<T> &array_to_load, const Setting &element ) {
00327                 const SettingResolver link ( element );
00328 
00329                 assert_type ( link.result, Setting::TypeList );
00330 
00331                 int len = link.result.getLength();
00332                 array_to_load.set_length ( len );
00333                 if ( len == 0 ) return;
00334 
00335                 for ( int i = 0; i < len; i++ )
00336                         from_setting ( array_to_load ( i ), link.result[i] );
00337         }
00338 
00343         template<class T> static void from_setting ( T &variable_to_load, const Setting &element ) {
00344                 std::string msg = "from_setting is not implemented for type ";
00345                 msg += typeid(T).name();
00346                 throw UIException ( msg, element );
00347         }
00348 
00349 
00350 protected:
00352         UI ( const string& class_name, const type_info * const class_type_info ) {
00353                 MappedUI::add_class ( class_name, class_type_info, this );
00354         }
00355 
00356 public:
00357 
00359         enum SettingPresence { optional, compulsory } ;
00360 
00364 
00368         template<class T>
00369         static shared_ptr<T> build ( const Setting &element, const string &name, SettingPresence settingPresence = optional ) {
00370                 if ( !element.exists ( name ) ) {
00371                         if ( settingPresence == optional )
00372                                 return shared_ptr<T>();
00373                         else
00374                                 throw UIException ( "the compulsory Setting named \"" + name + "\" is missing", element );
00375                 }
00376 
00377                 shared_ptr<T> instance;
00378                 from_setting<T> ( instance, to_child_setting ( element, name ) );
00379                 return instance;
00380         }
00381 
00385         template<class T>
00386         static shared_ptr<T> build ( const Setting &element, const int index, SettingPresence settingPresence = optional ) {
00387                 if ( element.getLength() <= index ) {
00388                         if ( settingPresence == optional )
00389                                 return shared_ptr<T>();
00390                         else {
00391                                 stringstream stream;
00392                                 stream << index;
00393                                 throw UIException ( "the compulsory Setting with the index " + stream.str() + " is missing", element );
00394                         }
00395                 }
00396 
00397                 shared_ptr<T> instance;
00398                 from_setting<T> ( instance, to_child_setting ( element, index ) );
00399                 return instance;
00400         }
00401 
00403 
00407 
00410         template<class T> static bool get ( T &instance, const Setting &element, const string &name, SettingPresence settingPresence = optional ) {
00411                 if ( !element.exists ( name ) ) {
00412                         if ( settingPresence == optional )
00413                                 return false;
00414                         else
00415                                 throw UIException ( "the compulsory Setting named \"" + name + "\" is missing", element );
00416                 }
00417 
00418                 from_setting ( instance, to_child_setting ( element, name ) );
00419                 return true;
00420         }
00421 
00424         template<class T> static bool get ( T &instance, const Setting &element, const int index, SettingPresence settingPresence = optional ) {
00425                 if ( element.getLength() <= index ) {
00426                         if ( settingPresence == optional )
00427                                 return false;
00428                         else {
00429                                 stringstream stream;
00430                                 stream << index;
00431                                 throw UIException ( "the compulsory Setting with the index " + stream.str() + " is missing", element );
00432                         }
00433                 }
00434 
00435                 from_setting ( instance, to_child_setting ( element, index ) );
00436                 return true;
00437         }
00438 
00440         template<class T> static bool get ( T &instance, const Setting &element ) {
00441                 from_setting ( instance, element );
00442                 return true;
00443         }
00445 
00449 
00452         template<class T> static bool get ( Array<T> &array_to_load, const Setting &element, const string &name, SettingPresence settingPresence = optional ) {
00453                 if ( !element.exists ( name ) )
00454                         return false;
00455 
00456                 from_setting ( array_to_load, to_child_setting ( element, name ) );
00457                 return true;
00458         }
00459 
00462         template<class T> static bool get ( Array<T> &array_to_load, const Setting &element, const int index, SettingPresence settingPresence = optional ) {
00463                 if ( element.getLength() <= index )
00464                         return false;
00465 
00466                 from_setting ( array_to_load, to_child_setting ( element, index ) );
00467                 return true;
00468         }
00469 
00471         template<class T> static bool get ( Array<T> &array_to_load, const Setting &element ) {
00472                 from_setting ( array_to_load, element );
00473                 return true;
00474         }
00476 
00481 
00483         template< class T> static void save ( const T * const instance, Setting &element, const string &name = "" ) {
00484                 Setting &set = ( name == "" ) ? element.add ( Setting::TypeGroup )
00485                                : element.add ( name, Setting::TypeGroup );
00486 
00487                 const string &class_name = MappedUI::retrieve_class_name ( &typeid ( *instance ) );
00488 
00489                 
00490                 Setting &type = set.add ( "class", Setting::TypeString );
00491                 type = class_name;
00492 
00493                 try {
00494                         instance->to_setting ( set );
00495                 } catch ( SettingException sttng_xcptn ) {
00496                     string msg = "the method ";
00497                     msg += class_name;
00498                     msg += ".to_setting(Setting&) has thrown a SettingException. Try to correct this method.";
00499                     throw UIException(msg, sttng_xcptn.getPath());
00500                 }
00501         }
00502 
00503         template< class T> static void save ( const shared_ptr<T> &instance, Setting &element, const string &name = "" ) {
00504                 save<T> ( instance.get(), element, name );
00505         }
00506 
00508         template<class T> static void save ( const Array<T> &array_to_save, Setting &element, const string &name = "" ) {
00509                 assert_type ( element, Setting::TypeGroup );
00510                 Setting &list = ( name == "" ) ? element.add ( Setting::TypeList )
00511                                 : element.add ( name, Setting::TypeList );
00512                 for ( int i = 0; i < array_to_save.length(); i++ )
00513                         save ( array_to_save ( i ), list );
00514         }
00515 
00517         static void save ( const mat &matrix, Setting &element, const string &name = "" );
00518 
00520         static void save ( const ivec &vec, Setting &element, const string &name = "" );
00521 
00523         static void save ( const vec &vector, Setting &element, const string &name = "" );
00524 
00526         static void save ( const string &str, Setting &element, const string &name = "" );
00527 
00529         static void save ( const int &integer, Setting &element, const string &name = "" );
00530 
00532         static void save ( const double &real, Setting &element, const string &name = "" );
00534 
00535 };
00536 
00537 
00540 template<typename T> class ParticularUI : private UI {
00541 public:
00543         ParticularUI<T> ( const string &class_name ) : UI ( class_name, &typeid ( T ) ) {};
00544 
00546         root* new_instance() const {
00547                 return new T();
00548         }
00549 };
00550 
00551 }
00552 
00562 #ifndef BDMLIB
00563 #define UIREGISTER(class_name) static bdm::ParticularUI<class_name> UI##class_name(#class_name)
00564 #else
00565 #define UIREGISTER(class_name)
00566 #endif
00567 
00569 #define QUOTEME(x) #x
00570 
00579 #ifndef BDMLIB
00580 #define UIREGISTER2(class_name, temp_name) static bdm::ParticularUI<class_name<temp_name> > UI##class_name##_##temp_name( QUOTEME(class_name<temp_name>) )
00581 #else
00582 #define UIREGISTER2(class_name,temp_name) 
00583 #endif
00584 
00585 #endif // #ifndef USER_INFO_H