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 ( 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 (std::runtime_error &e) {
00341                         delete instance;
00342                         instance = 0;
00343                         string msg = "UIException: method ";
00344                         msg += class_name;
00345                         msg += " says: ";
00346                         msg += e.what();
00347                         throw UISettingException(msg, link.result);
00348                 } catch (...) {
00349                         delete instance;
00350                         instance = 0;
00351                         throw;
00352                 }
00353 }
00354 
00357         template<class T>
00358         static void from_setting ( shared_ptr<T> &instance, const Setting &element ) {
00359                 T *tmp_inst = 0;
00360                 from_setting ( tmp_inst, element );
00361                 bdm_assert ( tmp_inst, "UI::from_setting failed" );
00362                 instance = tmp_inst;
00363         }
00364 
00366         template<class T> static void from_setting ( Array<T> &array_to_load, const Setting &element ) {
00367                 const SettingResolver link ( element );
00368 
00369                 assert_type ( link.result, Setting::TypeList );
00370 
00371                 int len = link.result.getLength();
00372                 array_to_load.set_length ( len );
00373                 if ( len == 0 ) return;
00374 
00375                 for ( int i = 0; i < len; i++ )
00376                         from_setting ( array_to_load ( i ), link.result[i] );
00377         }
00378 
00383         template<class T> static void from_setting ( T &variable_to_load, const Setting &element ) {
00384                 std::string msg = "UIException: from_setting is not implemented for type ";
00385                 msg += typeid(T).name();
00386                 msg += '.';
00387                 throw UISettingException ( msg, element );
00388         }
00389 
00390 
00391 protected:
00393         UI ( const string& class_name, const type_info * const class_type_info ) {
00394                 MappedUI::add_class ( class_name, class_type_info, this );
00395         }
00396 
00397 public:
00398 
00400         enum SettingPresence { optional, compulsory } ;
00401 
00405 
00409         template<class T>
00410         static shared_ptr<T> build ( const Setting &element, const string &name, SettingPresence settingPresence = optional ) {
00411                 if ( !element.exists ( name ) ) {
00412                         if ( settingPresence == optional )
00413                                 return shared_ptr<T>();
00414                         else
00415                                 throw UISettingException ( "UIException: the compulsory Setting named \"" + name + "\" is missing.", element );
00416                 }
00417 
00418                 shared_ptr<T> instance;
00419                 from_setting<T> ( instance, to_child_setting ( element, name ) );
00420                 return instance;
00421         }
00422 
00426         template<class T>
00427         static shared_ptr<T> build ( const Setting &element, const int index, SettingPresence settingPresence = optional ) {
00428                 if ( element.getLength() <= index ) {
00429                         if ( settingPresence == optional )
00430                                 return shared_ptr<T>();
00431                         else {
00432                                 stringstream stream;
00433                                 stream << index;
00434                                 throw UISettingException ( "UIException: the compulsory Setting with the index " + stream.str() + " is missing.", element );
00435                         }
00436                 }
00437 
00438                 shared_ptr<T> instance;
00439                 from_setting<T> ( instance, to_child_setting ( element, index ) );
00440                 return instance;
00441         }
00442 
00444 
00448 
00451         template<class T> static bool get ( T &instance, const Setting &element, const string &name, SettingPresence settingPresence = optional ) {
00452                 if ( !element.exists ( name ) ) {
00453                         if ( settingPresence == optional )
00454                                 return false;
00455                         else
00456                                 throw UISettingException ( "UIException: the compulsory Setting named \"" + name + "\" is missing.", element );
00457                 }
00458 
00459                 from_setting ( instance, to_child_setting ( element, name ) );
00460                 return true;
00461         }
00462 
00465         template<class T> static bool get ( T &instance, const Setting &element, const int index, SettingPresence settingPresence = optional ) {
00466                 if ( element.getLength() <= index ) {
00467                         if ( settingPresence == optional )
00468                                 return false;
00469                         else {
00470                                 stringstream stream;
00471                                 stream << "UIException: the compulsory Setting with the index " << index << " is missing.";
00472                                 stream << index;
00473                                 throw UISettingException (stream.str(), element );
00474                         }
00475                 }
00476 
00477                 from_setting ( instance, to_child_setting ( element, index ) );
00478                 return true;
00479         }
00480 
00482         template<class T> static bool get ( T &instance, const Setting &element ) {
00483                 from_setting ( instance, element );
00484                 return true;
00485         }
00487 
00491 
00494         template<class T> static bool get ( Array<T> &array_to_load, const Setting &element, const string &name, SettingPresence settingPresence = optional ) {
00495                 if ( !element.exists ( name ) )
00496                         return false;
00497 
00498                 from_setting ( array_to_load, to_child_setting ( element, name ) );
00499                 return true;
00500         }
00501 
00504         template<class T> static bool get ( Array<T> &array_to_load, const Setting &element, const int index, SettingPresence settingPresence = optional ) {
00505                 if ( element.getLength() <= index )
00506                         return false;
00507 
00508                 from_setting ( array_to_load, to_child_setting ( element, index ) );
00509                 return true;
00510         }
00511 
00513         template<class T> static bool get ( Array<T> &array_to_load, const Setting &element ) {
00514                 from_setting ( array_to_load, element );
00515                 return true;
00516         }
00518 
00523 
00525         template< class T> static void save ( const T * const instance, Setting &element, const string &name = "" ) {
00526                 Setting &set = ( name == "" ) ? element.add ( Setting::TypeGroup )
00527                                : element.add ( name, Setting::TypeGroup );
00528 
00529                 const string &class_name = MappedUI::retrieve_class_name ( &typeid ( *instance ) );
00530 
00531                 
00532                 Setting &type = set.add ( "class", Setting::TypeString );
00533                 type = class_name;
00534 
00535                 try {
00536                         instance->to_setting ( set );
00537                 } catch ( SettingException &sttng_xcptn ) {
00538                         string msg = "UIException: method ";
00539                         msg += class_name;
00540                         msg += ".to_setting(Setting&) has thrown a SettingException.";
00541                         throw UISettingException(msg, sttng_xcptn.getPath());
00542                 }
00543         }
00544 
00545         template< class T> static void save ( const shared_ptr<T> &instance, Setting &element, const string &name = "" ) {
00546                 save<T> ( instance.get(), element, name );
00547         }
00548 
00550         template<class T> static void save ( const Array<T> &array_to_save, Setting &element, const string &name = "" ) {
00551                 assert_type ( element, Setting::TypeGroup );
00552                 Setting &list = ( name == "" ) ? element.add ( Setting::TypeList )
00553                                 : element.add ( name, Setting::TypeList );
00554                 for ( int i = 0; i < array_to_save.length(); i++ )
00555                         save ( array_to_save ( i ), list );
00556         }
00557 
00559         static void save ( const mat &matrix, Setting &element, const string &name = "" );
00560 
00562         static void save ( const ivec &vec, Setting &element, const string &name = "" );
00563 
00565         static void save ( const vec &vector, Setting &element, const string &name = "" );
00566 
00568         static void save ( const string &str, Setting &element, const string &name = "" );
00569 
00571         static void save ( const int &integer, Setting &element, const string &name = "" );
00572 
00574         static void save ( const double &real, Setting &element, const string &name = "" );
00576 
00577 };
00578 
00579 
00582 template<typename T> class ParticularUI : private UI {
00583 public:
00585         ParticularUI<T> ( const string &class_name ) : UI ( class_name, &typeid ( T ) ) {};
00586 
00588         root* new_instance() const {
00589                 return new T();
00590         }
00591 };
00592 
00593 }
00594 
00604 #ifndef BDMLIB
00605 #define UIREGISTER(class_name) static bdm::ParticularUI<class_name> UI##class_name(#class_name)
00606 #else
00607 #define UIREGISTER(class_name)
00608 #endif
00609 
00611 #define QUOTEME(x) #x
00612 
00621 #ifndef BDMLIB
00622 #define UIREGISTER2(class_name, temp_name) static bdm::ParticularUI<class_name<temp_name> > UI##class_name##_##temp_name( QUOTEME(class_name<temp_name>) )
00623 #else
00624 #define UIREGISTER2(class_name,temp_name) 
00625 #endif
00626 
00627 #endif // #ifndef USER_INFO_H