/*
    listPM list files under Presentation Manager. Uses Open Class Libarary.
    Copyright (C) 1998, 1999  Paul Elliott

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

    Paul Elliott
    PMB # 181
    11900 Metric Blvd Ste. J
    Austin Tx 78758-3117
    pelliott@io.com
*/
#ifndef LTPER
#define LTPER
// This Abstract Base Class define a mechinism to
// move raw memory to and from some sort of abstract
// external memory store.

class ToStorage
{
  public:
     virtual void read ( char * buf,int count) = 0;
     virtual void write (const char * buf,int count) = 0;
     virtual Boolean isInStorage(void) = 0;
     virtual ~ToStorage() {};
};

// In order for an "object" to be light weight persistant,
// it must be mapable to "essance" of just plain data. That is something
// that can be copied bytewise (without loosing underlying meaning
// if any) and having no pointers (including vtbl pointers from
// virtual members) or other connection to the world outside.


// In what follows, it must be possible to construct "object"
// from its essance (Just Plain Data). Also, "object" must
// return a reference to its essance. Or construct an essance
// from an from an object

// Aessance is a type that must be constructable from an object
// by conversion operator or constructable it must be possible
// to assign a const essance& to an Aessance
// I have used Aessance = const essance&
// for cases where an object will return a reference to an essance
// and used Aessance = essance in cases where essance is constructable
// from an object.

template<class object,class essance, typename Aessance=const essance& >
class ExternalExistance
{
     private:
        // reference to raw storage interface.
        ToStorage& storage;

        // returns a essance read from external.
        operator essance()
        {
            essance essance_instance;

            // cast the essance to raw characters & read it in.
            char * str = (char*) &essance_instance;
            storage.read( str, sizeof(essance_instance) );
            return essance_instance;
        };

     public:
        // true if indicated object exists externally.
        // use storage to determine if exists.
        Boolean ExistsExternally()
        {
            return storage.isInStorage();
        };

        // construct self from a ToStorage
        // save the passed in storage which will really a derived object.
        ExternalExistance(ToStorage& stor) : storage(stor)
        {};

        // destructor.
        virtual ~ExternalExistance() {};

        // write the indicated object to external storage.
        ExternalExistance<object,essance,Aessance> &
                     operator<<(const object& obj_instance)
        {
            // get the essance of the object. (As a reference to a constant essance)
            // choose Aessance so that this statement works!
            const essance& essance_instance = ( Aessance )obj_instance;

            // convert the essance to bytes.
            const char * str = (const char*) &essance_instance;

            // write the essance bytes to external.
            storage.write(str,sizeof(essance) );

            // done.
            return *this;
        };

        // The class Created is identical to object except it can be
        // created from external storage. Works because object
        // can be created from essance.
        class Created : public object
        {
          public:
            // constructor. Create essance from external store.
            // create object=Created from essance.
            Created(ExternalExistance<object,essance,Aessance> & exist)  :
               object( essance(exist) )
            {};
        };
        // Created constructor can use ExternalStorage to construct
        // an essance.
        friend Created::Created(ExternalExistance<object,essance,Aessance> & exist);
};


// In the above template object must be a class.
// otherwise compile error. To get around this for builtin types
// such as int or char, we provide the following template.
// which creates a class=struct really which embodies a builtin
// type for the purpose of ExternalExistance.
template <class X>
struct BuiltIn
{
      X   built_in;
      operator X() const { return built_in; };
      BuiltIn(const X& built_in) : built_in(built_in) {};
};


#endif // LTPER
