00001 #ifndef UI_H
00002 #define UI_H
00003 
00004 #include <sstream>
00005 #include <iostream>
00006 #include <stdio.h>
00007 #include <string>
00008 #include <typeinfo>
00009 #include <map>
00010 #include <utility>
00011 #include <vector>
00012 #include <xercesc/dom/DOM.hpp>
00013 #include <xercesc/util/PlatformUtils.hpp>
00014 #include <xercesc/util/XMLString.hpp>
00015 #include <iostream>
00016 #include <xercesc/framework/LocalFileFormatTarget.hpp>
00017 #include <xercesc/framework/LocalFileInputSource.hpp>
00018 #include <xercesc/dom/DOMWriter.hpp>
00019 #include <xercesc/parsers/XercesDOMParser.hpp>
00020 
00021 #ifdef XERCES_CPP_NAMESPACE_USE
00022 XERCES_CPP_NAMESPACE_USE
00023 #endif
00024 
00025 using std::string;
00026 using namespace std;
00027 
00040 class AssertXercesIsAlive
00041 {
00042 private:
00044         class XercesConnector
00045         {
00046         private:
00049                 XercesConnector()
00050                 {
00051                         
00052                         XMLPlatformUtils::Initialize();
00053                 }
00054 
00055                 ~XercesConnector()
00056                 {
00057                         
00058                         XMLPlatformUtils::Terminate();
00059                 }
00060 
00061         public:
00068                 static void StayAlive()
00069                 {
00070                         static XercesConnector xc;              
00071                 };
00072         };
00073 
00074 
00075 public:
00077         AssertXercesIsAlive()
00078         {
00079                 XercesConnector::StayAlive();
00080         }
00081 };
00082 
00086 class BindingFrame
00087 {
00088 private:
00092         AssertXercesIsAlive dummy;
00093 
00094 protected:
00096         BindingFrame();
00097 
00099         string XMLCh2str( const XMLCh* const  XMLCh_str );
00100 
00101         string removeSpaces(const string &str) 
00102         {
00103                 std::string temp;
00104                 for (unsigned int i = 0; i < str.length(); i++)
00105                         if (str[i] == ' ') temp += '_';
00106                         else temp += str[i];
00107                 return temp;
00108         }
00109 
00110 public: 
00112         virtual void AssemblyComponentsFromXML( DOMElement &element ) = 0;
00113 
00115         virtual void ReleaseMemory() {}
00116 
00119         virtual bool DisassemblyComponentsToXML( DOMElement &element ) = 0;             
00120 };
00121 
00125 class Attribute 
00126 {               
00127 private:
00131         AssertXercesIsAlive dummy;
00132 
00134         const XMLCh* const transcodedAttributeName;
00135 
00136 public:
00138         Attribute( string attributeName );
00139 
00140         ~Attribute();
00141 
00143         string& Get( DOMElement &element ) const;
00144 
00146         void Set( DOMElement &element, const string &str ) const;       
00147 
00149         static const Attribute help;
00150 
00152         static const Attribute type;
00153 
00155         static const Attribute value;
00156 };
00157 
00158 
00159 
00167 class UserInfo : protected BindingFrame
00168 {
00169 private:
00171         typedef UserInfo* const pUserInfo;
00172 
00177         class StringToUIMap
00178         {
00179         private:
00181                 typedef map< const string, pUserInfo > MappedString2UI;
00182 
00184                 static MappedString2UI& privateMap();
00185 
00186         public:
00188                 static void Add( string key, pUserInfo pInstance );
00189 
00191                 static pUserInfo Retrieve( string key );
00192         };
00193                                 
00195         virtual void* AssemblyTypelessInstance() = 0;
00196         
00198         virtual bool DisassemblyTypelessInstance(void* pInstance) = 0;
00199 
00201         const string userFriendlyTypeName;
00202 
00204         const string typeNameByRTTI;
00205 
00206 protected:
00207 
00209         UserInfo( const string& userFriendlyTypeName, const string& typeNameByRTTI )
00210                 : userFriendlyTypeName ( removeSpaces( userFriendlyTypeName ) ), 
00211                   typeNameByRTTI( typeNameByRTTI )
00212         {       
00213                 StringToUIMap::Add( userFriendlyTypeName, this );
00214 
00215                 if( userFriendlyTypeName != typeNameByRTTI )
00216                         
00217                         
00218                         StringToUIMap::Add( typeNameByRTTI, this );
00219         }
00220 
00221 public: 
00225         template<class T>
00226         static T* Assembly( DOMElement &element, const string tagName )
00227         {       
00228                 XMLCh* transcodedTagName = XMLString::transcode( tagName.c_str() );             
00229                 XMLString::upperCase( transcodedTagName );
00230 
00231                 DOMNodeList* const nodeList = element.getElementsByTagName( transcodedTagName );
00232                 XMLString::release( (XMLCh**)&transcodedTagName );
00233                 if( !nodeList || nodeList->getLength() == 0 )
00234                 {
00235                         cerr << "Warning: there is not any tag named """ << tagName << """ in the passed DOM element of a XML docmument!";
00236                         return NULL;
00237                 }
00238 
00239                 if( nodeList->getLength() > 1 )
00240                 {
00241                         cerr << "Warning: there is to many elements named """ << tagName << """ in the passed DOM element of a XML docmument. But the tag name has to be unique!";
00242                         return NULL;
00243                 }
00244 
00245                 
00246                 DOMElement* pTheOnlyElement = (DOMElement*) nodeList->item(0);
00247 
00248                 
00249                 string userFriendlyTypeName = Attribute::type.Get( *pTheOnlyElement );
00250         
00251                 
00252                 pUserInfo pRelatedUI = StringToUIMap::Retrieve( userFriendlyTypeName );
00253                 if( !pRelatedUI )
00254                 {
00255                         cerr << "Warning: there is not any UserInfo related to type named """ << userFriendlyTypeName << """, instance assembling terminated!";
00256                         return NULL;
00257                 }
00258 
00259                 
00260                 pRelatedUI->AssemblyComponentsFromXML( *pTheOnlyElement );              
00261 
00262                 
00263                 void* pTypelessInstance = pRelatedUI->AssemblyTypelessInstance();
00264 
00265                 
00266                 pRelatedUI->ReleaseMemory();
00267 
00268                 if( pTypelessInstance == NULL )
00269                 {
00270                         cerr << "Warning: there was some error when parsing a XML document, instance assembling terminated!";
00271                         return NULL;
00272                 }
00273 
00274                 T* pInstance = NULL;
00275                 try
00276                 {
00277                         
00278                         pInstance = (T*) pTypelessInstance;
00279                         string resultingTypeNameByRTTI = typeid( *pInstance ).name();
00280                         if( resultingTypeNameByRTTI != pRelatedUI->typeNameByRTTI )
00281                                 pInstance = NULL;
00282                 }
00283                 catch(...)
00284                 {
00285                         pInstance = NULL;
00286                 }               
00287                 if( pInstance == NULL )
00288                         cerr << "Warning: UserInfo related to type """ << userFriendlyTypeName << """ have just returned instance of a different type! Instance assembling terminated!";
00289 
00290                 return pInstance;
00291         }       
00292 
00296         template<class T>
00297         static bool Disassembly( T& instance, DOMElement &element, const string tagName, const string help)
00298         {       
00299                 pUserInfo pRelatedUI = StringToUIMap::Retrieve( typeid(instance).name() );
00300                 if( !pRelatedUI )
00301                         return false;
00302 
00303                 
00304                 XMLCh* transcodedTagName = XMLString::transcode( tagName.c_str() );             
00305                 XMLString::upperCase( transcodedTagName );
00306                 DOMDocument* pDoc = element.getOwnerDocument();
00307                 DOMElement* pCreatedElement = pDoc->createElement( transcodedTagName );         
00308                 element.appendChild( pCreatedElement );
00309                 XMLString::release( (XMLCh**)&transcodedTagName );
00310                         
00311                 
00312                 Attribute::type.Set( *pCreatedElement, pRelatedUI->userFriendlyTypeName );              
00313                 Attribute::help.Set( *pCreatedElement, help );
00314                 
00315                 
00316                 bool result =  pRelatedUI->DisassemblyTypelessInstance( (void*) &instance );
00317                 if( result )
00318                         
00319                         result = pRelatedUI->DisassemblyComponentsToXML( *pCreatedElement );            
00320                 return result;
00321         }       
00322 
00326         template<class T>
00327         static bool Disassembly( T &instance, DOMElement &element, const string tagName )
00328         {
00329                 return Disassembly( instance, element, tagName, "" );
00330         }
00331 };
00332 
00344 template<typename T> class TypedUserInfo : public UserInfo
00345 {
00346 private:
00347 
00348         bool DisassemblyTypelessInstance(void* pInstance)
00349         {
00350                 try
00351                 {
00352                         return DisassemblyInstance( *(T*) pInstance );
00353                 }
00354                 catch (...)
00355                 {
00356                         return false;
00357                 }
00358         }
00359 
00360         void* AssemblyTypelessInstance()
00361         {
00362                 return (void*) AssemblyInstance( );
00363         }
00364 
00366         virtual T* AssemblyInstance() = 0;
00367 
00369         virtual bool DisassemblyInstance(T& instance) = 0;
00370 
00371 protected:
00372 
00374         TypedUserInfo<T>( const string &userFriendlyTypeName) 
00375                 : UserInfo( userFriendlyTypeName, typeid(T).name() ) 
00376         {       
00377 
00378         };
00379 
00381         ~TypedUserInfo<T>()
00382         {
00383         }
00384 
00387         static const TypedUserInfo<T>& instance;
00388 };
00389 
00390 
00420 template<typename T> class CompoundUserInfo : public TypedUserInfo<T>
00421 {
00422 private:
00424         vector<BindingFrame*> bindedElements;
00425 
00426 protected:
00427 
00432         template<typename U> class BindedElement: public BindingFrame
00433         {
00434         private:
00435                 string name;
00436                 string help;                            
00437                 bool release;
00438 
00439                 U* pValue;
00440 
00441                 const U defaultValue;
00442                 
00443  
00444         public:
00445                 U value;
00446 
00447                 BindedElement<U>( CompoundUserInfo<T> *parent, string name, U defaultValue, string help ) 
00448                         : name( removeSpaces( name )), help(help), defaultValue( defaultValue )
00449                 {
00450                         parent->bindedElements.push_back( this );
00451                         pValue = NULL;
00452                         value = defaultValue;
00453                 }
00454 
00455                 BindedElement<U>( CompoundUserInfo<T> *parent, string name, U defaultValue ) 
00456                         : name( removeSpaces( name )), help(""), defaultValue( defaultValue ), value( defaultValue)
00457                 {
00458                         parent->bindedElements.push_back( this );
00459                         pValue = NULL;
00460                         value = defaultValue;
00461                 }
00462 
00463                 ~BindedElement<U>()
00464                 {
00465                 }
00466 
00467                 void AssemblyComponentsFromXML( DOMElement &element )
00468                 {
00469                         pValue = UserInfo::Assembly<U>( element, name );
00470                         if( pValue ) value = *pValue;                   
00471                 }
00472 
00473                 void ReleaseMemory()
00474                 {
00475                         if( pValue != NULL )
00476                                 delete pValue;
00477                 }
00478 
00479                 bool DisassemblyComponentsToXML( DOMElement &element )
00480                 {
00481                         return UserInfo::Disassembly( value, element, name, help );
00482                 }
00483         };
00484 
00485 private:
00486 
00487         void AssemblyComponentsFromXML( DOMElement &element )
00488         {
00489                 for( unsigned int ind = 0; ind < bindedElements.size(); ind++ )
00490                         bindedElements[ind]->AssemblyComponentsFromXML( element );
00491         }
00492 
00493         void ReleaseMemory()
00494         {                       
00495                 for( unsigned int ind = 0; ind < bindedElements.size(); ind++ )
00496                         bindedElements[ind]->ReleaseMemory();
00497         }
00498 
00499         bool DisassemblyComponentsToXML( DOMElement &element )
00500         {
00501                 for( unsigned int ind = 0; ind < bindedElements.size(); ind++ )
00502                         if( !bindedElements[ind]->DisassemblyComponentsToXML( element ) )
00503                                 return false;
00504                 return true;
00505         }
00506 
00507 protected:
00508 
00509         CompoundUserInfo<T>( string userFriendlyTypeName )
00510                 : TypedUserInfo<T>( userFriendlyTypeName )
00511         {
00512         }
00513 
00514 };
00515 
00516 
00527 template<typename T> class ValuedUserInfo : public TypedUserInfo<T>
00528 {
00529 private:
00530         void AssemblyComponentsFromXML( DOMElement &element )
00531         {               
00532                 value = Attribute::value.Get( element );
00533         }
00534 
00535         bool DisassemblyComponentsToXML( DOMElement &element )
00536         {
00537                 Attribute::value.Set( element, value );
00538                 return true;
00539         }
00540 
00541 protected:
00542         ValuedUserInfo<T>( string userFriendlyTypeName )
00543                 : TypedUserInfo<T>( userFriendlyTypeName )
00544         {
00545         }
00546 
00547         ~ValuedUserInfo<T>()
00548         {
00549         }
00550 
00552         string value;
00553 };
00554 
00576 class RootElement 
00577 {
00578 private:
00582         const AssertXercesIsAlive dummy;
00583 
00585         DOMDocument* pDoc;
00586 
00587         const XMLCh* const transcodedFileName;
00588 
00590         DOMImplementation *pImplementation;
00591 
00593         DOMWriter *pSerializer;
00594 
00595         void Clean();
00596 
00597 public:
00599         RootElement(const char* fileName );
00600 
00601         ~RootElement();
00602 
00604         bool Load( void ) ;
00605 
00607         void Save ( void );
00608 
00610         operator DOMElement&();
00611 };
00612 
00613 
00617 
00618 class BoolUI: public ValuedUserInfo<bool>
00619 {
00620 private:
00621 
00622         bool* AssemblyInstance()
00623         {               
00624                 if( value == "true" )
00625                         return new bool( true );
00626                 else if( value == "false" )
00627                         return new bool( false );
00628                 else return NULL;
00629         }
00630 
00631         bool DisassemblyInstance(bool &instance)
00632         {
00633                 if( instance )
00634                         value = "true";
00635                 else
00636                         value = "false";
00637                 return true; 
00638         }
00639 
00640 public:
00641 
00642         BoolUI()
00643                 : ValuedUserInfo<bool>("bool")
00644         {
00645         }
00646 };
00647 
00648 
00649 class IntUI: public ValuedUserInfo<int>
00650 {
00651 private:
00652 
00653         int* AssemblyInstance()
00654         {
00655                 return new int( atoi( value.c_str()) );
00656         }
00657 
00658         bool DisassemblyInstance(int &instance)
00659         {
00660                 char buff[30];
00661                 sprintf(buff, "%d", instance );
00662                 value = buff;
00663                 return true; 
00664         }
00665 
00666 public:
00667         IntUI():ValuedUserInfo<int>("int")
00668         {
00669         }
00670 };
00671 
00672 
00673 
00674 class DoubleUI: public ValuedUserInfo<double>
00675 {
00676 private:
00677 
00678         double* AssemblyInstance()
00679         {
00680                 return new double( atof( value.c_str()) );
00681         }
00682 
00683         bool DisassemblyInstance(double &instance)
00684         {
00685                 char buff[30];
00686                 sprintf(buff, "%f", instance );
00687                 value = buff;
00688                 return true; 
00689         }
00690 
00691 public:
00692         DoubleUI():ValuedUserInfo<double>("double")
00693         {
00694         }
00695 };
00696 
00697 
00698 class StringUI: public ValuedUserInfo<string>
00699 {
00700 private:
00701         string* AssemblyInstance()
00702         {
00703                 return new string( value );
00704         }
00705 
00706         bool DisassemblyInstance(string &instance)
00707         {
00708                 value = instance;
00709                 return true;
00710         }
00711 
00712 public:
00713         StringUI():ValuedUserInfo<string>("string")
00714         {
00715         }
00716 };
00717 
00718 
00719 #endif // #ifndef UI_H