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 private:
00042         const string message;
00043 
00044 public:
00049         UIException ( const string &message ) :
00050                 message ( message ) {
00051         }
00052 
00054         virtual const char* what() const throw() {
00055                 return message.c_str();
00056         }
00057 
00058         ~UIException() throw() {};
00059 
00060 protected:
00065         static string format_message( const string &reason, const string &path );
00066 };
00067 
00071 class UISettingException : public UIException {
00072 public:
00074         UISettingException ( const string &message, const Setting &element ):
00075                 UIException ( format_message ( message, string ( element.getPath() ) ) ) {
00076         }
00077 
00079         UISettingException ( const string &message, const string &path ):
00080                 UIException ( format_message ( message, path ) ) {
00081         }
00082 
00083         ~UISettingException() throw() {};
00084 };
00085 
00089 class UIClassException : public UIException {
00090 public:
00092         UIClassException ( const string &message, const Setting &element ):
00093                 UIException ( format_message ( message, string ( element.getPath() ) ) ) {
00094         }
00095 
00097         UIClassException ( const string &message, const string &path ):
00098                 UIException ( format_message ( message, path ) ) {
00099         }
00100 
00101         ~UIClassException() throw() {};
00102 };
00103 
00128 class UIFile : public Config {
00129 public:
00131         UIFile();
00132 
00134         UIFile ( const string &file_name );
00135 
00137         void save ( const string &file_name );
00138 
00140         operator Setting&();
00141 };
00142 
00209 class SettingResolver : root {
00210 private:
00212         UIFile *file;
00213 
00219         const Setting &initialize_reference ( UIFile* &file, const Setting &potential_link );
00220 
00221 public:
00223         const Setting &result;
00224 
00226         SettingResolver ( const Setting &potential_link );
00227 
00229         ~SettingResolver();
00230 };
00231 
00242 class UI {
00243 private:
00249         class MappedUI {
00250         private:
00252                 typedef map< const string, const UI* const > StringToUIMap;
00253 
00255                 typedef map< const type_info * const, const string > TypeInfoToStringMap;
00256 
00258                 static StringToUIMap& mapped_strings();
00259 
00261                 static TypeInfoToStringMap& mapped_type_infos();
00262 
00264                 static void unregistered_class_error ( const string &unregistered_class_name );
00265 
00266         public:
00268                 static void add_class ( const string &class_name, const type_info * const class_type_info, const UI* const ui );
00269 
00271                 static const UI& retrieve_ui ( const string &class_name );
00272 
00274                 static const string& retrieve_class_name ( const type_info* const class_type_info );
00275         };
00276 
00278         static void assert_type ( const Setting &element, Setting::Type type );
00279 
00288         virtual root* new_instance() const = 0;
00289 
00291         static const Setting& to_child_setting ( const Setting &element, const int index );
00292 
00294         static const Setting& to_child_setting ( const Setting &element, const string &name );
00295 
00297         static void from_setting ( mat& matrix, const Setting &element );
00299         static void from_setting ( ivec &vector, const Setting &element );
00301         static void from_setting ( string &str, const Setting &element );
00303         static void from_setting ( vec &vector, const Setting &element );
00305         static void from_setting ( int &integer, const Setting &element );
00307         static void from_setting ( double &real, const Setting &element );
00308 
00310         template<class T> static void from_setting ( T* &instance, const Setting &element ) {
00311                 const SettingResolver link ( element );
00312                 assert_type ( link.result, Setting::TypeGroup );
00313 
00314                 
00315                 string class_name;
00316                 if ( !link.result.lookupValue ( "class", class_name ) )
00317                         throw UIClassException ( "UIException: the obligatory \"class\" identifier is missing.", link.result );
00318 
00319                 
00320                 const UI& related_UI = MappedUI::retrieve_ui ( class_name );
00321 
00322                 root *typeless_instance = related_UI.new_instance();
00323                 bdm_assert_debug ( typeless_instance, "UI::new_instance failed" );
00324 
00325                 instance = dynamic_cast<T*> ( typeless_instance );
00326                 if ( !instance ) {
00327                         delete typeless_instance;
00328                         throw UIClassException ( "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 );
00329                 }
00330 
00331                 try {
00332                         instance->from_setting ( link.result );
00333                 } catch ( SettingException &sttng_xcptn ) {
00334                         delete instance;
00335                         instance = 0;
00336                         string msg = "UIException: method ";
00337                         msg += class_name;
00338                         msg += ".from_setting(Setting&) has thrown a SettingException.";
00339                         throw UISettingException(msg, sttng_xcptn.getPath());
00340                 } catch (...) {
00341                         delete instance;
00342                         instance = 0;
00343                         throw;
00344                 }
00345         }
00346 
00349         template<class T>
00350         static void from_setting ( shared_ptr<T> &instance, const Setting &element ) {
00351                 T *tmp_inst = 0;
00352                 from_setting ( tmp_inst, element );
00353                 bdm_assert_debug ( tmp_inst, "UI::from_setting failed" );
00354                 instance = tmp_inst;
00355         }
00356 
00358         template<class T> static void from_setting ( Array<T> &array_to_load, const Setting &element ) {
00359                 const SettingResolver link ( element );
00360 
00361                 assert_type ( link.result, Setting::TypeList );
00362 
00363                 int len = link.result.getLength();
00364                 array_to_load.set_length ( len );
00365                 if ( len == 0 ) return;
00366 
00367                 for ( int i = 0; i < len; i++ )
00368                         from_setting ( array_to_load ( i ), link.result[i] );
00369         }
00370 
00375         template<class T> static void from_setting ( T &variable_to_load, const Setting &element ) {
00376                 std::string msg = "UIException: from_setting is not implemented for type ";
00377                 msg += typeid(T).name();
00378                 msg += '.';
00379                 throw UISettingException ( msg, element );
00380         }
00381 
00382 
00383 protected:
00385         UI ( const string& class_name, const type_info * const class_type_info ) {
00386                 MappedUI::add_class ( class_name, class_type_info, this );
00387         }
00388 
00389 public:
00390 
00392         enum SettingPresence { optional, compulsory } ;
00393 
00397 
00401         template<class T>
00402         static shared_ptr<T> build ( const Setting &element, const string &name, SettingPresence settingPresence = optional ) {
00403                 if ( !element.exists ( name ) ) {
00404                         if ( settingPresence == optional )
00405                                 return shared_ptr<T>();
00406                         else
00407                                 throw UISettingException ( "UIException: the compulsory Setting named \"" + name + "\" is missing.", element );
00408                 }
00409 
00410                 shared_ptr<T> instance;
00411                 from_setting<T> ( instance, to_child_setting ( element, name ) );
00412                 return instance;
00413         }
00414 
00418         template<class T>
00419         static shared_ptr<T> build ( const Setting &element, const int index, SettingPresence settingPresence = optional ) {
00420                 if ( element.getLength() <= index ) {
00421                         if ( settingPresence == optional )
00422                                 return shared_ptr<T>();
00423                         else {
00424                                 stringstream stream;
00425                                 stream << index;
00426                                 throw UISettingException ( "UIException: the compulsory Setting with the index " + stream.str() + " is missing.", element );
00427                         }
00428                 }
00429 
00430                 shared_ptr<T> instance;
00431                 from_setting<T> ( instance, to_child_setting ( element, index ) );
00432                 return instance;
00433         }
00434 
00436 
00440 
00443         template<class T> static bool get ( T &instance, const Setting &element, const string &name, SettingPresence settingPresence = optional ) {
00444                 if ( !element.exists ( name ) ) {
00445                         if ( settingPresence == optional )
00446                                 return false;
00447                         else
00448                                 throw UISettingException ( "UIException: the compulsory Setting named \"" + name + "\" is missing.", element );
00449                 }
00450 
00451                 from_setting ( instance, to_child_setting ( element, name ) );
00452                 return true;
00453         }
00454 
00457         template<class T> static bool get ( T &instance, const Setting &element, const int index, SettingPresence settingPresence = optional ) {
00458                 if ( element.getLength() <= index ) {
00459                         if ( settingPresence == optional )
00460                                 return false;
00461                         else {
00462                                 stringstream stream;
00463                                 stream << "UIException: the compulsory Setting with the index " << index << " is missing.";
00464                                 stream << index;
00465                                 throw UISettingException (stream.str(), element );
00466                         }
00467                 }
00468 
00469                 from_setting ( instance, to_child_setting ( element, index ) );
00470                 return true;
00471         }
00472 
00474         template<class T> static bool get ( T &instance, const Setting &element ) {
00475                 from_setting ( instance, element );
00476                 return true;
00477         }
00479 
00483 
00486         template<class T> static bool get ( Array<T> &array_to_load, const Setting &element, const string &name, SettingPresence settingPresence = optional ) {
00487                 if ( !element.exists ( name ) )
00488                         return false;
00489 
00490                 from_setting ( array_to_load, to_child_setting ( element, name ) );
00491                 return true;
00492         }
00493 
00496         template<class T> static bool get ( Array<T> &array_to_load, const Setting &element, const int index, SettingPresence settingPresence = optional ) {
00497                 if ( element.getLength() <= index )
00498                         return false;
00499 
00500                 from_setting ( array_to_load, to_child_setting ( element, index ) );
00501                 return true;
00502         }
00503 
00505         template<class T> static bool get ( Array<T> &array_to_load, const Setting &element ) {
00506                 from_setting ( array_to_load, element );
00507                 return true;
00508         }
00510 
00515 
00517         template< class T> static void save ( const T * const instance, Setting &element, const string &name = "" ) {
00518                 Setting &set = ( name == "" ) ? element.add ( Setting::TypeGroup )
00519                                : element.add ( name, Setting::TypeGroup );
00520 
00521                 const string &class_name = MappedUI::retrieve_class_name ( &typeid ( *instance ) );
00522 
00523                 
00524                 Setting &type = set.add ( "class", Setting::TypeString );
00525                 type = class_name;
00526 
00527                 try {
00528                         instance->to_setting ( set );
00529                 } catch ( SettingException &sttng_xcptn ) {
00530                         string msg = "UIException: method ";
00531                         msg += class_name;
00532                         msg += ".to_setting(Setting&) has thrown a SettingException.";
00533                         throw UISettingException(msg, sttng_xcptn.getPath());
00534                 }
00535         }
00536 
00537         template< class T> static void save ( const shared_ptr<T> &instance, Setting &element, const string &name = "" ) {
00538                 save<T> ( instance.get(), element, name );
00539         }
00540 
00542         template<class T> static void save ( const Array<T> &array_to_save, Setting &element, const string &name = "" ) {
00543                 assert_type ( element, Setting::TypeGroup );
00544                 Setting &list = ( name == "" ) ? element.add ( Setting::TypeList )
00545                                 : element.add ( name, Setting::TypeList );
00546                 for ( int i = 0; i < array_to_save.length(); i++ )
00547                         save ( array_to_save ( i ), list );
00548         }
00549 
00551         static void save ( const mat &matrix, Setting &element, const string &name = "" );
00552 
00554         static void save ( const ivec &vec, Setting &element, const string &name = "" );
00555 
00557         static void save ( const vec &vector, Setting &element, const string &name = "" );
00558 
00560         static void save ( const string &str, Setting &element, const string &name = "" );
00561 
00563         static void save ( const int &integer, Setting &element, const string &name = "" );
00564 
00566         static void save ( const double &real, Setting &element, const string &name = "" );
00568 
00569 };
00570 
00571 
00574 template<typename T> class ParticularUI : private UI {
00575 public:
00577         ParticularUI<T> ( const string &class_name ) : UI ( class_name, &typeid ( T ) ) {};
00578 
00580         root* new_instance() const {
00581                 return new T();
00582         }
00583 };
00584 
00585 }
00586 
00596 #ifndef BDMLIB
00597 #define UIREGISTER(class_name) static bdm::ParticularUI<class_name> UI##class_name(#class_name)
00598 #else
00599 #define UIREGISTER(class_name)
00600 #endif
00601 
00603 #define QUOTEME(x) #x
00604 
00613 #ifndef BDMLIB
00614 #define UIREGISTER2(class_name, temp_name) static bdm::ParticularUI<class_name<temp_name> > UI##class_name##_##temp_name( QUOTEME(class_name<temp_name>) )
00615 #else
00616 #define UIREGISTER2(class_name,temp_name) 
00617 #endif
00618 
00619 #endif // #ifndef USER_INFO_H