MCommand.h
/*
 *
 * Copyright (c) 1996
 * Knowledge Science Institute, University of Calgary
 *
 * Permission to use, copy, modify, distribute and sell this software
 * and its documentation for any purpose is hereby granted without fee,
 * provided that the above copyright notice appear in all copies and
 * that both that copyright notice and this permission notice appear
 * in supporting documentation.  The Knowledge Science Institute makes no
 * representations about the suitability of this software for any
 * purpose.  It is provided "as is" without express or implied warranty.
 *
 */

#ifndef MCOMMAND_H
#define MCOMMAND_H

#ifndef VECTOR_H
#include 
#endif

#ifndef STACK_H
#include 
#endif

#ifndef LIST_H
#include 
#endif

#ifndef MLEXER_H
#include 
#endif

#ifndef MOBJLIB_H
#include 
#endif

#ifndef MOBJECT_H
#include 
#endif

#ifndef __TIME_H
#include 
#endif

class Command;
class ObjectLocator;

extern  ObjectLibrary < CloneableObject,
        0 > *CloneableLibrary;          // instance declaration is left up to the outer program

#ifndef DONTDECLARECOMMANDLIBRARY
extern  ObjectLibrary < Command,
        0 > *CommandLibrary;            // the instance is declared in MCommand.cpp
extern  ObjectLibrary < ObjectLocator,
        0 > *ObjectLocatorLibrary;      // the instance is declared in MCommand.cpp
#endif

class Command;
class CompositeCommand;

//
class CommandReceiverContainer
    {
 public:
    virtual int executeOnBehalf( Command * ) = 0;
    virtual int undoOnBehalf( Command * ) = 0;
    };

//
class CommandReceiver
    {
 public:
    virtual int execute( Command * ) = 0;
    virtual int undo( Command * ) = 0;
    };

//
class ObjectLocator
    {
 public:
    virtual CommandReceiver *getObject(  ) const = 0;
    virtual CommandReceiverContainer *getSuper(  ) const
        {
        return NULL;
        }                               // reasonable default
    virtual ObjectLocator *clone(  ) = 0;
    virtual void printOn( ostream & o ) = 0;
    virtual void readFrom( istream & i ) = 0;
    virtual void setRoot( void *p ) = 0;
    };

//
class NullObjectLocator : public ObjectLocator
    {
 public:
    virtual CommandReceiver *getObject(  ) const
        {
        return NULL;
        }
    virtual CommandReceiverContainer *getSuper(  ) const
        {
        return NULL;
        }                               // reasonable default
    virtual ObjectLocator *clone(  )
        {
        return new NullObjectLocator;
        }
    virtual void printOn( ostream & o )
        {
        Lexer::writeDelim( o, '(' );
        Lexer::writeDelim( o, ')' );
        }
    virtual void readFrom( istream & i )
        {
        Lexer::scanPastDelim( i, ')' );
        }
    virtual void setRoot( void *p )
        {
        }
    };

//
/*Command on a stream is:
  FULL_COMMAND	-> COMMAND \n
  COMMAND	-> COMMAND_PREF SUBTYPE_INFO
  COMMAND_PREF	-> ,,,,,
*/
class Command
    {
    friend  ostream & operator << ( ostream &, Command & );
    friend  istream & operator >> ( istream &, Command * );
    friend class CompositeCommand;
 public:
            Command( const ObjectLocator & obj, unsigned int id );
            Command(  );                // use only as an intermediate step!!
            Command( const Command & c );
    virtual ~Command(  )
        {
        delete  Locator;
        }
    virtual Command *clone(  )
        {
        return new Command( *this );
        }
    virtual Command & operator = ( const Command & c );
    virtual unsigned int getCommandID(  )
        {
        return ID;
        }
    virtual time_t getTimeStamp(  )
        {
        return TimeStamp;
        }
    virtual string getUser(  )
        {
        return User;
        }
    virtual unsigned long getPID(  )
        {
        return PID;
        }
    virtual unsigned long getThread(  )
        {
        return Thread;
        }
    virtual ObjectLocator *peekObjectLocator(  )
        {
        return Locator;
        }
    virtual void setLocatorRoot( void *p )
        {
        if ( Locator )
            Locator->setRoot( p );
        }
    virtual int execute(  );
    virtual int undo(  );
    virtual unsigned int id(  )
        {
        return ID;
        }
    virtual unsigned int setID( unsigned int newId )
        {
        unsigned int ret = ID;
                ID = newId;
                return ret;
        }
    virtual int operator < ( Command & c );
    virtual int operator == ( Command & c );
    virtual void emptyTheTrash(  )
        {
        }
    static Command *readCommand( istream & i );
    virtual int isMine(  );             // returns true iff the command originated with this process/thread
 protected:
    virtual void printOn( ostream & o );
    virtual void readFrom( istream & i );
    unsigned int ID;
    ObjectLocator *Locator;
    string  User;
    time_t  TimeStamp;
    unsigned long PID;
    unsigned long Thread;               // need a thread because a multithread processes (like Netscape)
    // will have the same PID for different instances
    };

ostream & operator << ( ostream & o, Command & c )
    {
    c.printOn( o );
    Lexer::writeDelim( o, '\n' );
    return o;
    }

/*
istream& operator>>(istream& i, Command* c) {
  *c = Command::readCommand(i);
  Lexer::scanPastDelim(i,'\n');
  return i;
  }
*/

//
class CommandHandler
    {
 public:
    CommandHandler(  )
        {
        HistoryPtr = 0;
        }
    virtual ~CommandHandler(  );
    virtual int handleCommand( Command * c );
    virtual int undo( void );
    virtual int redo( void );
    virtual int undoable( void ) {return HistoryPtr;}
    virtual int redoable( void ) {return HistoryPtr < HistoryList.size(  );}
    virtual int resetHistoryList( void );
    /* Batch mode works differently than one might expect: */
    virtual int beginBatch(unsigned int id);
    virtual int endBatch( void );
    virtual int AbortBatch(int undoIt=0);
 protected:
    vector HistoryList;
    unsigned long HistoryPtr;
    stack > BatchStack;
    virtual int doPostCommandProcessing(Command *c);
    virtual int AppendToHistoryList(Command *c);
    };

//The following are useful templates for subtypes of class Command

//
/*Command1 on a stream is (see Command)
  SUBTYPE_INFO	-> ,,
*/
template < class T >
class Command1 : public Command
    {
 public:
    Command1( const ObjectLocator & obj, unsigned int id, T & value, T & originalValue )
 :
    Command( obj, id )
        {
        Value = value;
        OriginalValue = originalValue;
        }
 Command1(  ):
    Command(  )
        {
        }                               // use only as an intermediate!!
         Command1( const Command1 < T > &c ):
            Command( c )
        {
        Value = c.Value;
        OriginalValue = c.OriginalValue;
        }
    virtual ~Command1(  )
        {
        }
    virtual Command *clone(  )
        {
        return new Command1 < T > ( *this );
        }
    virtual Command1 < T > &operator = ( const Command1 < T > &c )
        {Command::operator = ( c );
        Value = c.Value;
        OriginalValue = c.OriginalValue;
        }
    virtual void setValue( T & value )
        {
        Value = value;
        }
    virtual T & getValue(  )
        {
        return Value;
        }
    virtual void setOriginalValue( T & value )
        {
        OriginalValue = value;
        }
    virtual T & getOriginalValue(  )
        {
        return OriginalValue;
        }
 protected:
    virtual void printOn( ostream & o )
        {
        Command::printOn( o );
        Lexer::writeDelim( o );
        o << Value;
        Lexer::writeDelim( o );
        o << OriginalValue;
        }
    virtual void readFrom( istream & i )
        {
        Command::readFrom( i );
        Lexer::readDelim( i );
        i >> Value;
        Lexer::readDelim( i );
        i >> OriginalValue;
        }
    T       Value,
            OriginalValue;
    };

//
/*CommandPtr1 on a stream is (see Command)
  SUBTYPE_INFO	-> ,,[],[],
*/
template < class T >
class CommandPtr1 : public Command
    {
 public:
    CommandPtr1( const ObjectLocator & obj, unsigned int id, T * value = NULL, T * originalValue = NULL )
 :
    Command( obj, id )
        {Value = value;
        OriginalValue = originalValue;
        }
 CommandPtr1(  ):
    Command(  )                         // use only as an intermediate!!
        {
        Value = NULL;
        OriginalValue = NULL;
        }
         CommandPtr1( const CommandPtr1 < T > &c ):
            Command( c )
        {
        Value = c.Value;
        OriginalValue = c.OriginalValue;
        }
    virtual ~CommandPtr1(  )
        {
        }
    virtual Command *clone(  )
        {
        return new CommandPtr1 < T > ( *this );
        }
    virtual CommandPtr1 < T > &operator = ( const CommandPtr1 < T > &c )
        {Command::operator = ( c );
        Value = c.Value;
        OriginalValue = c.OriginalValue;
        return *this;
        }
    virtual void setValue( T * value )
        {
        Value = value;
        }
    virtual T *getValue(  )
        {
        return Value;
        }
    virtual void setOriginalValue( T * value )
        {
        OriginalValue = value;
        }
    virtual T *getOriginalValue(  )
        {
        return OriginalValue;
        }
    virtual void emptyTheTrash(  )
        {
        if ( Value )
            delete  Value;
        if      ( OriginalValue )
            delete  OriginalValue;
        }
 protected:
    virtual void printOn( ostream & o )
        {
        Command::printOn( o );
        Lexer::writeDelim( o );
        if ( Value )
            Lexer::writeQuotedString( o, typeid( *Value ).name(  ) );
        Lexer::writeDelim( o );
        if ( Value )
            o << *Value;
        Lexer::writeDelim( o );
        if ( OriginalValue )
            Lexer::writeQuotedString( o, typeid( *OriginalValue ).name(  ) );
        Lexer::writeDelim( o );
        if ( OriginalValue )
            o << *OriginalValue;
        Lexer::writeDelim( o );
        }
    virtual void readFrom( istream & i )
        {
        ObjectLibrary < CloneableObject, 0 > *ol = CloneableLibrary;    /* ObjectLibrary::getInstance(); */
        Command::readFrom( i );
        Lexer::readDelim( i );
        string  typeName( typeid( T ).name(  ) );
                Lexer::readQuotedString( i, typeName );
                Lexer::readDelim( i );
        if      ( !Lexer::readDelim( i ) )
            {
            if ( Value )
                delete  Value;
                    Value = NULL;
            }
        else
            {
            if ( !Value )
                Value = dynamic_cast < T * >( ol->makeCopy( typeName ) );
            if ( Value )
                i >> *Value;
            else
                error( 0, 'E', "Can't find %s in ObjectLibrary", typeName.c_str(  ) );
            Lexer::readDelim( i );
            }
        Lexer::readQuotedString( i, typeName );
        Lexer::readDelim( i );
        if ( !Lexer::readDelim( i ) )
            {
            if ( OriginalValue )
                delete  OriginalValue;
            OriginalValue = NULL;
            }
        else
            {
            if ( !OriginalValue )
                OriginalValue = dynamic_cast < T * >( ol->makeCopy( typeName ) );
            if ( OriginalValue )
                i >> *OriginalValue;
            else
                error( 0, 'E', "Can't find %s in ObjectLibrary", typeName.c_str(  ) );
            Lexer::readDelim( i );
            }
        }
    T      *Value,
           *OriginalValue;
    };

//
/*CommandPtr2 on a stream is (see Command)
  SUBTYPE_INFO	-> ,,[],[],[],[],
*/
template < class T1,
class T2 >
class CommandPtr2 : public CommandPtr1 < T1 >
    {
 public:
    CommandPtr2( const ObjectLocator & obj, unsigned int id, T1 * value1 = NULL, T1 * originalValue1 = NULL,
                 T2 * value2 = NULL, T2 * originalValue2 = NULL )
 :
    CommandPtr1 < T1 > ( obj, id, value1, originalValue1 )
        {Value2 = value2;
        OriginalValue2 = originalValue2;
        }
 CommandPtr2(  ):
    CommandPtr1 < T1 > (  )             // use only as an intermediate!!
        {
        Value2 = NULL;
        OriginalValue2 = NULL;
        }
         CommandPtr2( const CommandPtr2 < T1, T2 > &c ):
            CommandPtr1 < T1 > ( c )
        {
        Value2 = c.Value2;
        OriginalValue2 = c.OriginalValue2;
        }
    virtual ~CommandPtr2(  )
        {
        }
    virtual Command *clone(  )
        {
        return new CommandPtr2 < T1, T2 > ( *this );
        }
    virtual CommandPtr2 < T1,
            T2 > &operator = ( const CommandPtr2 < T1, T2 > &c )
        {CommandPtr1 < T1 > ::operator = ( c );
        Value2 = c.Value2;
        OriginalValue2 = c.OriginalValue2;
        return *this;
        }
    virtual void setValue2( T2 * value )
        {
        Value2 = value;
        }
    virtual T2 *getValue2(  )
        {
        return Value2;
        }
    virtual void setOriginalValue2( T2 * value )
        {
        OriginalValue2 = value;
        }
    virtual T2 *getOriginalValue2(  )
        {
        return OriginalValue2;
        }
    virtual void emptyTheTrash(  )
        {
        CommandPtr1 < T1 > ::emptyTheTrash(  );
        if ( Value2 )
            delete  Value2;
        if      ( OriginalValue2 )
            delete  OriginalValue2;
        }
 protected:
    virtual void printOn( ostream & o )
        {
        CommandPtr1 < T1 > ::printOn( o );
        Lexer::writeDelim( o );
        if ( Value2 )
            Lexer::writeQuotedString( o, typeid( *Value2 ).name(  ) );
        Lexer::writeDelim( o );
        if ( Value2 )
            o << *Value2;
        Lexer::writeDelim( o );
        if ( OriginalValue2 )
            Lexer::writeQuotedString( o, typeid( *OriginalValue2 ).name(  ) );
        Lexer::writeDelim( o );
        if ( OriginalValue2 )
            o << *OriginalValue2;
        Lexer::writeDelim( o );
        }
    virtual void readFrom( istream & i )
        {
        ObjectLibrary < CloneableObject, 0 > *ol = CloneableLibrary;    /* ObjectLibrary::getInstance(); */
        CommandPtr1 < T1 > ::readFrom( i );
        Lexer::readDelim( i );
        string  typeName( typeid( T2 ).name(  ) );
                Lexer::readQuotedString( i, typeName );
                Lexer::readDelim( i );
        if      ( !Lexer::readDelim( i ) )
            {
            if ( Value2 )
                delete  Value2;
                    Value2 = NULL;
            }
        else
            {
            if ( !Value2 )
                Value2 = dynamic_cast < T2 * >( ol->makeCopy( typeName ) );
            if ( Value2 )
                i >> *Value2;
            else
                error( 0, 'E', "Can't find %s in ObjectLibrary", typeName.c_str(  ) );
            Lexer::readDelim( i );
            }
        Lexer::readQuotedString( i, typeName );
        Lexer::readDelim( i );
        if ( !Lexer::readDelim( i ) )
            {
            if ( OriginalValue2 )
                delete  OriginalValue2;
            OriginalValue2 = NULL;
            }
        else
            {
            if ( !OriginalValue2 )
                OriginalValue2 = dynamic_cast < T2 * >( ol->makeCopy( typeName ) );
            if ( OriginalValue2 )
                i >> *OriginalValue2;
            else
                error( 0, 'E', "Can't find %s in ObjectLibrary", typeName.c_str(  ) );
            Lexer::readDelim( i );
            }
        }
    T2     *Value2,
           *OriginalValue2;
    };

//
/*CommandPtr1Obj1 on a stream is (see Command)
  SUBTYPE_INFO	-> ,,[],[],[],[],
*/
template < class T1,
class T2 >
class CommandPtr1Obj1 : public CommandPtr1 < T1 >
    {
 public:
    CommandPtr1Obj1( const ObjectLocator & obj, unsigned int id, T1 * value1 = NULL, T1 * originalValue1 = NULL,
                     T2 value2 = T2(  ), T2 originalValue2 = T2(  ) )
 :
    CommandPtr1 < T1 > ( obj, id, value1, originalValue1 )
        {Value2 = value2;
        OriginalValue2 = originalValue2;
        }
 CommandPtr1Obj1(  ):
    CommandPtr1 < T1 > (  )             // use only as an intermediate!!
        {
        Value2 = T2(  );
        OriginalValue2 = T2(  );
        }
         CommandPtr1Obj1( const CommandPtr1Obj1 < T1, T2 > &c ):
            CommandPtr1 < T1 > ( c )
        {
        Value2 = c.Value2;
        OriginalValue2 = c.OriginalValue2;
        }
    virtual ~CommandPtr1Obj1(  )
        {
        }
    virtual Command *clone(  )
        {
        return new CommandPtr1Obj1 < T1, T2 > ( *this );
        }
    virtual CommandPtr1Obj1 < T1,
            T2 > &operator = ( const CommandPtr1Obj1 < T1, T2 > &c )
        {CommandPtr1 < T1 > ::operator = ( c );
        Value2 = c.Value2;
        OriginalValue2 = c.OriginalValue2;
        return *this;
        }
    virtual void setValue2( T2 value )
        {
        Value2 = value;
        }
    virtual T2 & getValue2(  )
        {
        return Value2;
        }
    virtual void setOriginalValue2( T2 value )
        {
        OriginalValue2 = value;
        }
    virtual T2 & getOriginalValue2(  )
        {
        return OriginalValue2;
        }
 protected:
    virtual void printOn( ostream & o )
        {
        CommandPtr1 < T1 > ::printOn( o );
        o << Value2;
        Lexer::writeDelim( o );
        o << OriginalValue2;
        Lexer::writeDelim( o );
        }
    virtual void readFrom( istream & i )
        {
        CommandPtr1 < T1 > ::readFrom( i );
        Lexer::readDelim( i );
        i >> Value2;
        Lexer::readDelim( i );
        i >> OriginalValue2;
        }
    T2      Value2,
            OriginalValue2;
    };

//
/*CommandPtr1Obj2 on a stream is (see Command)
  SUBTYPE_INFO	-> ,,[],[],[],[],[],[],
*/
template < class T1,
class T2,
class T3 >
class CommandPtr1Obj2 : public CommandPtr1Obj1 < T1,
        T2 >
    {
 public:
    CommandPtr1Obj2( const ObjectLocator & obj, unsigned int id, T1 * value1 = NULL, T1 * originalValue1 = NULL,
                     T2 value2 = T2(  ), T2 originalValue2 = T2(  ),
                     T3 value3 = T3(  ), T3 originalValue3 = T3(  ) )
 :
    CommandPtr1Obj1 < T1, T2 > ( obj, id, value1, originalValue1, value2, originalValue2 )
        {
        Value3 = value3;
        OriginalValue3 = originalValue3;
        }
 CommandPtr1Obj2(  ):
    CommandPtr1Obj1 < T1, T2 > (  )     // use only as an intermediate!!
        {
        Value3 = T3(  );
        OriginalValue3 = T3(  );
        }
         CommandPtr1Obj2( const CommandPtr1Obj2 < T1, T2, T3 > &c ):
            CommandPtr1Obj1 < T1, T2 > ( c )
        {
        Value3 = c.Value3;
        OriginalValue3 = c.OriginalValue3;
        }
    virtual ~CommandPtr1Obj2(  )
        {
        }
    virtual Command *clone(  )
        {
        return new CommandPtr1Obj2 < T1, T2, T3 > ( *this );
        }
    virtual CommandPtr1Obj2 < T1,
            T2,
            T3 > &operator = ( const CommandPtr1Obj2 < T1, T2, T3 > &c )
        {CommandPtr1Obj1 < T1, T2 > ::operator = ( c );
        Value3 = c.Value3;
        OriginalValue3 = c.OriginalValue3;
        return *this;
        }
    virtual void setValue3( T3 value )
        {
        Value3 = value;
        }
    virtual T3 & getValue3(  )
        {
        return Value3;
        }
    virtual void setOriginalValue3( T3 value )
        {
        OriginalValue3 = value;
        }
    virtual T3 & getOriginalValue3(  )
        {
        return OriginalValue3;
        }
 protected:
    virtual void printOn( ostream & o )
        {
        CommandPtr1Obj1 < T1, T2 > ::printOn( o );
        o << Value3;
        Lexer::writeDelim( o );
        o << OriginalValue3;
        Lexer::writeDelim( o );
        }
    virtual void readFrom( istream & i )
        {
        CommandPtr1Obj1 < T1, T2 > ::readFrom( i );
        Lexer::readDelim( i );
        i >> Value3;
        Lexer::readDelim( i );
        i >> OriginalValue3;
        }
    T3      Value3,
            OriginalValue3;
    };

//
/*Command2 on a stream is (see Command)
  SUBTYPE_INFO	-> ,,,,
*/
template < class T1,
class T2 >
class Command2 : public Command1 < T1 >
    {
 public:
    Command2( const ObjectLocator & obj, unsigned int id, T1 value1 = T1(  ), T2 value2 = T2(  ),
              T1 originalValue1 = T1(  ), T2 originalValue2 = T2(  ) )
 :
    Command1 < T1 > ( obj, id, value1, originalValue1 )
        {Value2 = value2;
        OriginalValue2 = originalValue2;
        }
 Command2(  ):
    Command1 < T1 > (  )
        {
        }                               // use only as an intermediate!!
         Command2( const Command2 < T1, T2 > &c ):
            Command1 < T1 > ( c )
        {
        Value2 = c.Value2;
        OriginalValue2 = c.OriginalValue2;
        }
    virtual ~Command2(  )
        {
        }
    virtual Command *clone(  )
        {
        return new Command2 < T1, T2 > ( *this );
        }
    virtual Command2 < T1,
            T2 > &operator = ( const Command2 < T1, T2 > &c )
        {Command1 < T1 > ::operator = ( c );
        Value2 = c.Value2;
        OriginalValue2 = c.OriginalValue2;
        }
    virtual void setValue2( T2 & value )
        {
        Value2 = value;
        }
    virtual T2 & getValue2(  )
        {
        return Value2;
        }
    virtual void setOriginalValue2( T2 & value )
        {
        OriginalValue2 = value;
        }
    virtual T2 & getOriginalValue2(  )
        {
        return OriginalValue2;
        }
 protected:
    virtual void printOn( ostream & o )
        {
        Command1 < T1 > ::printOn( o );
        Lexer::writeDelim( o );
        o << Value2;
        Lexer::writeDelim( o );
        o << OriginalValue2;
        }
    virtual void readFrom( istream & i )
        {
        Command1 < T1 > ::readFrom( i );
        Lexer::readDelim( i );
        i >> Value2;
        Lexer::readDelim( i );
        i >> OriginalValue2;
        }
    T2      Value2,
            OriginalValue2;
    };

#ifdef DEFINE_DESTROY_COMMAND //??don't know why this is different for different compilations -- rck
inline void destroy(Command**) {}
#endif

//
/*CompositeCommand on a stream is (see Command)
  SUBTYPE_INFO	-> ( COMMAND { , COMMAND }* )
*/
class CompositeCommand : public Command
    {
 public:
 CompositeCommand( unsigned int id ):
    Command( NullObjectLocator(  ), id ) {}
    CompositeCommand( const CompositeCommand & c );
 CompositeCommand(  ):Command(  ) {}                               // use only as an intermediate step
    virtual ~CompositeCommand(  ){emptyTheTrash();}
    virtual CompositeCommand *clone(  ) {return new CompositeCommand( *this );}
    virtual CompositeCommand & operator = ( const CompositeCommand & c );
    virtual int execute(  );
    virtual int undo(  );
    virtual void emptyTheTrash(  );
    int     append( Command * c ) {Commands.push_back( c ); return 0;}                               // this 'owns' c!!!
    virtual void setLocatorRoot( void *p );
protected:
    virtual void printOn( ostream & o );
    virtual void readFrom( istream & i );
    typedef vector < Command * >Commands_type;
    Commands_type Commands;
    };

#endif