//////////////////////////////////////////////////////////////////////
//
// MMemory.h: Declaration of the Morphic Memory classes
//
//////////////////////////////////////////////////////////////////////
/* 
This is FREE software  

Permission is hereby granted, free of charge,  to any person obtaining  a copy 
of this software and associated documentation files (the "Software"),  to deal 
in the Software without restriction, including without limitation  the  rights 
to use,  copy,  modify,  merge,  publish,  distribute, sublicense, and/or sell 
copies  of  the  Software,   and  to  permit  persons  to  whom  the  Software 
is furnished to do so, subject to the following conditions: 

There are no conditions imposed on the use of this software. 

THE SOFTWARE IS PROVIDED "AS IS",  WITHOUT  WARRANTY  OF ANY KIND,  EXPRESS OR 
IMPLIED,  INCLUDING  BUT  NOT  LIMITED  TO  THE  WARRANTIES OF MERCHANTABILITY, 
FITNESS  FOR  A  PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
AUTHORS  OR  COPYRIGHT  HOLDERS  BE  LIABLE  FOR  ANY CLAIM,  DAMAGES OR OTHER 
LIABILITY,  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,  ARISING FROM, 
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN  THE 
SOFTWARE. 
*/


#ifndef _MMEMORY_H_
#define _MMEMORY_H_


#include "MTypes.h"

//Standard Morphic Memory file
#ifdef _DEBUG
    #define MEMORY_FILE "\\Projects\\_Builds\\Memory\\Runtest\\WegaLink.mem"
    #define BACKUP_FILE "\\Projects\\_Builds\\Memory\\Runtest\\WegaLink.bak"
    #define ASCII_FILE  "\\Projects\\_Builds\\Memory\\Runtest\\ascii.txt"
    #define WORDS_FILE  "\\Projects\\_Builds\\Memory\\Runtest\\words.txt"
    #define DEBUG_FILE  "\\Projects\\_Builds\\Memory\\Runtest\\debug.txt"
#else
    #define MEMORY_FILE "WegaLink.mem"
    #define BACKUP_FILE "WegaLink.bak"
    #define ASCII_FILE  "ascii.txt"
    #define WORDS_FILE  "words.txt"
#endif

#define NEW_LINE     "\x0D\x0A"
#define FILE_HEADER1 "** This file was generated by WegaLink <erac@wegalink.org>"
#define FILE_HEADER2 "**   WegaLink is OSI Certified Open Source Software."
#define FILE_HEADER3 "**   OSI Certified is a certification mark of the Open Source Initiative."

//Default item for user management
#define URI_USER    "user"

//Debug file available only in debug mode
#ifdef _DEBUG
    static FILE* pDebugFile;
#endif

//Run-time node types
//
// ATTENTION!!!
// Changing any enumerated value will make existing memory files useless!!!
//
// One file should not contain more than 10 classes. 
//
enum MNodeType{
        //MMemory components
        M_NODE           =   0,  //2000-07-15
        M_ROOT           =   1,  //2000-07-15
        M_TAIL           =   2,  //2000-07-15
        M_ROOT_MEMORY    =   3,  //2000-08-11
        M_TAIL_MEMORY    =   4,  //2000-08-11
        M_VAL            =   5,  //2000-08-11
        M_REF            =   6,  //2000-08-11
        M_ITEM           =   7,  //2001-11-24

        //MLanguage components
        M_DICTIONARY     =  10,  //2000-07-25 

        //MState components
        M_SYSTIME        =  20,  //2001-11-24
        M_SESSION        =  21,  //2001-11-24
        M_CONCEPT        =  22,  //2001-11-24
        M_SPECIAL        =  23,  //2001-11-24
        M_STATE          =  24,  //2001-11-24
        M_LINK           =  25,  //2001-11-24

        //MDisk components
        M_DISK           =  30,  //2001-11-24
        M_BLOB           =  31,  //2001-11-24
        M_LOOP           =  32,  //2001-11-24

        //MConnection components
        M_CONNECTION     =  40,  //2001-08-17
        M_SERIAL         =  41,  //2000-11-12

        //MDisplay components
        M_POS            =  50,  //2000-07-15
        M_VIEW           =  51,  //2000-07-15
        M_SCREEN         =  52,  //2000-07-15
        M_COLOR          =  53,  //2001-09-26

        //MRadioAstronomy components
        M_QUANTITY       =  60,  //2001-09-26
        M_FIELD          =  61,  //2001-09-14
        M_FLUX           =  62,  //2001-08-17
        M_TIME           =  63,  //2001-08-17
        M_FREQUENCY      =  64,  //2001-08-17
        M_OBSERVER       =  65,  //2001-08-17
        M_RIGHTASCENSION =  66,  //2001-08-17
        M_DECLINATION    =  67,  //2001-08-17

        //The following value has to be greater than all enumerated values
        MaxMNodeType     =  70
};


#define NODE_ARRAY_SIZE 128   //This value fills one memory page (4096 byte)
                               //assuming an effective node size of 32 bytes

//Collection of characters that function as delimiters in path strings
#define M_PATH_DELIMITERS             "\\/"


//////////////////////////////////////////////////////////////////////
//
// MMemory's class declaration
//
//////////////////////////////////////////////////////////////////////
class MItem;
class MVal;
class MRef;

//Exception class used in all MMemory and derived modules
class MException
{
private:
    void* pData;
    char* pError;

public:
    //Constructors and destructor
    MException();
    MException(void* _pData);
    MException(char* _pError);
    MException(void* _pData,char* _pError);
    MException(const MException &E);
    ~MException();

    void putError(char* _pError);
    char* showError();
    void* getData();
};




//MNode is the basic class whereof other MMemory classes are derived from.
class MNode
{
public:
    //Generate nodes in memory as well as all classes derived from this one
    MNode* createNode(MNodeType);
    //Generate URI
    virtual void generateURI(MString&,const MString&,unsigned*);
    //Report runtime type 
    virtual inline MNodeType getNodeType();
protected:
    //Methods used when working on binary trees
    bool expandBTree(MNode**,unsigned, MNodeType, MNode**);
    virtual inline void setWeight(unsigned uWeight);
    virtual inline unsigned getWeight();
    virtual inline unsigned getCentre();
    //Hash function, e.g. for assigning a hash value to a chain of nodes
    unsigned getHashValue(MNode*);
    //Have a node become alive at start time (if applicable)
    virtual void go();
    //Report if a member variable is used as a pointer (and has to be adjusted on memory restore)
    virtual inline bool isBackPtr();
    virtual inline bool isLessPtr();
    virtual inline bool isMorePtr();
    virtual inline bool isPrevPtr();
    virtual inline bool isNextPtr();
    virtual inline bool isDataPtr();
    //Direct write functions of all member variables
    virtual inline MNode*  setChain(MNode* pNode);
    virtual inline MNode*  setBack(MNode* pNode);
    virtual inline MNode*  setLess(MNode* pNode);
    virtual inline MNode*  setMore(MNode* pNode);
    virtual inline MNode*  setPrev(MNode* pNode);
    virtual inline MNode*  setNext(MNode* pNode);
    virtual inline unsigned setData(unsigned _uData);
    //Direct read functions of all member variables
    virtual inline MNode*  getChain();
    virtual inline MNode*  getBack();
    virtual inline MNode*  getLess();
    virtual inline MNode*  getMore();
    virtual inline MNode*  getPrev();
    virtual inline MNode*  getNext();
    virtual inline unsigned getData();
    //Direct access to adresses of all member variables
    virtual inline MNode**  getAddrChain();
    virtual inline MNode**  getAddrBack();
    virtual inline MNode**  getAddrLess();
    virtual inline MNode**  getAddrMore();
    virtual inline MNode**  getAddrPrev();
    virtual inline MNode**  getAddrNext();
    virtual inline unsigned* getAddrData();
    //Report special features
    virtual inline bool isRoot();
    virtual inline bool isQuantity();
    //Constuctors and destructor
    MNode(MNode* const);
    MNode();
    virtual ~MNode();

    MNode*   pChain;    //Connecting all nodes in one long chain
    MNode*   pBack;     //Parent node in a binary tree
    MNode*   pLess;     //Less valuable node in a binary tree
    MNode*   pMore;     //More valuable node in a binary tree
    MNode*   pPrev;     //Previous element in a binary tree
    MNode*   pNext;     //Next element in a binary tree
    unsigned uData;     //Value represented by current node, e.g a Unicode character

    //Give access to protected member variables to the following classes
    friend class MRoot;
    friend class MTail;
    friend class MRootMemory;
    friend class MTailMemory;
    friend class MVal;
    friend class MRef;
    friend class MRefDelimit;
    friend class MItem;

    friend class MDictionary;

    friend class MSysTime;
    friend class MSession;
    friend class MConcept;
    friend class MSpecial;
    friend class MState;
    friend class MLink;

    friend class MDisk;
    friend class MBlob;
    friend class MLoop;

    friend class MConnection;
    friend class MSerial;

    friend class MPos;
    friend class MView;
    friend class MScreen;

    friend class MQuantity;
    friend class MField;
    friend class MTime;
    friend class MFlux;
    friend class MFrequency;
    friend class MObserver;
    friend class MRightAscension;
    friend class MDeclination;
};

#include "MState.h"


//MRoot is the starting point for building up a dictionary.
//A dictionary is made of nodes (MVal) arranged in a binary tree. At each end point of an
//item made of MVal nodes a MItem node will be placed as a direct successor of the 
//last MVal node in the chain generated by the pChain pointers.
class MRoot : public MNode
{
public:
    //MDictionary(MRoot) provides high-performance access to any collection of items.
    //The items can be accessed by a binary tree search as well as a binary sorted list.  
    //During expansion of the binary tree with new items the applied algoritms ensure that
    //the binary tree never exceeds the optimal depth, that is 32 levels given a 32-bit 
    //compiler. This feature provides to an outstanding performance. At the same time this 
    //performance applies to all items ever put into the dictionary. No extra index is 
    //required since the storage of all items is done as content and full index at the 
    //same time.
    //MDictionary is similar to MRoot except the sorting procedure. Instead of a binary
    //sorting a sorting based on an alphabet is performed in MDictionary.

    //Constructor and destructor
    MRoot();
    virtual ~MRoot();
    //Add a new item to current dictionary (if non-existent)
    virtual MItem* getItem(MVal*);
    //Obtain item for specified string from root memory and 
    //generate in current dictionary a item based on that reference (if non-existent)
    virtual MItem* getItem(const MString&);
    //Find the first item in current dictionary and return it's last MVal
    virtual MVal* getFirstItem();
    //Find the next item in current dictionary and return it's last MVal
    virtual MVal* getNextItem(MNode*);
    //Get the total number of items in current dictionary
    unsigned getDictionaryItems();

    //Generate (if non-existent) and return a reference to specified string
    MRef* getRef(const MString&);
    //Take reference to specified string and make a root upon a MItem
    MRoot* getRoot(const MString&);
    //Report delimiter's number of bytes and return MItem
    virtual MItem* reportLength(unsigned*,const MString&);
    //Generate URI
    virtual void generateURI(MString&,const MString&,unsigned*);
    //Obtain URI up to current root
    MString& getURI(MString&,const MString&);
    //Add a new node
    MNode* addNode(MNodeType);
    //Create a new couple of MRoot/MTail 
    MRoot* addRoot(const MString&,MNodeType);
    static MNode* createRoot(MNodeType);
protected:
    //Find first item in current branch of the binary tree and return it's last MVal
    virtual MVal* getFirstItem(MNode*);
    //Obtain tail
    MNode* getTail();
    //Remove weight and return original value
    virtual unsigned getData();
    //Add a weight to uData's upper part used later for sorting purposes
    virtual unsigned addSortWeight(unsigned uVal);
    //Report special features and runtime type 
    bool isRoot();
    MNodeType getNodeType();

    friend class MDictionary;
    friend class MItem;
};


//MTail is the last node in a dictionary with MRoot as starting point.
//All nodes in the dictionary except MRef are links in a chain connecting MRoot and MTail.
class MTail : public MNode
{
public:
    //No public interface
protected:
    //Report if a member variable is used as a pointer (and has to be adjusted on memory restore)
    bool isPrevPtr();
    //Report runtime type information
    MNodeType getNodeType();
    //Constructor and destructor
    MTail();
    virtual ~MTail();
    friend class MNode;       //Allow MNode access to protected constructor
};


//MRootMemory allows for transparent persistence of all classes derived from MNode.
//Since all nodes are connected in one long chain, MRootMemory saves and restores that 
//chain. Additionally, all addresses have to be adjusted after a restore from disk into RAM.
class MRootMemory : public MRoot
{
public:
    //INTERFACE SUMMARY
    //The MMemory interface provides access to a Morphic Memory in the RAM of a computer.
    //Functions are available for making the Morphic Memory persistent on disk and to
    //restore a previously saved Morphic Memory from disk into RAM. Additionally, some
    //statistic functions are available related to memory maintainance.
    //Furthermore, dictionary roots can be obtained based on a given path string. Those
    //roots are the entry points to more sophisticated functionality implemented in the
    //root as well as the dictionary's elements.

    //Generate URI
    void generateURI(MString&,const MString&,unsigned*);
    //Report delimiter's number of bytes and return MItem
    MItem* reportLength(unsigned*,const MString&);
    //Access functions
    MNode* getChain1();
    //Statistic functions related to nodes, items and dictionaries in the Morphic Memory
    unsigned getTotalNodes();
    unsigned getNodeSize();
    unsigned getTotalItems();
    unsigned getTotalDictionaries();
    unsigned getDictionaryLemmas(char*);
    unsigned getDictionaryItems(char*);
    //Backup and restore a Morphic Memory
    void backupMMemory(char*);
    static MRootMemory* createTop();
    static MRootMemory* initMMemory(char*);
    //Managing system time
    int64 getSysClock();
    MSysTime* getSysTime();
    MSysTime* adjustSysTime(int64);
    MSysTime* attachSession(MSession*);
    //Add a new item for specified string to current dictionary (if non-existent)
    MItem* getStringItem(const MString&);
    //Get a dictionary's root determined by given path string
    MRoot* getDictionary(char*);
    //Report runtime type information
    MNodeType getNodeType();
    //Constructor and destructor
    MRootMemory();
    virtual ~MRootMemory();
    friend class MNode;       //Allow MNode access to protected constructor

private:
    //Data structur written to and restored from disk
    struct MBackup{
        MNodeType mNodeType;
        MNode*    pThis;
        MNode*    pBack;
        MNode*    pLess;
        MNode*    pMore;
        MNode*    pPrev;
        MNode*    pNext;
        unsigned   uData;
    };
};

//Pointer to the root of the Morphic Memory
class MRootMemory;
#ifdef _CREATE_MEMORY_ROOT_
    MRootMemory* pRootMemory = new MRootMemory;
#else
    extern MRootMemory* pRootMemory;
#endif 


//MTailMemory is the last node in the linear chain reaching from MRootMemory to MTailMemory
class MTailMemory : public MTail
{
public:
    //No public interface
protected:
    //Report if a member variable is used as a pointer (and has to be adjusted on memory restore)
    bool isLessPtr();
    bool isMorePtr();
    bool isPrevPtr();
    //Report runtime type information
    MNodeType getNodeType();
    //Constructor and destructor
    MTailMemory();
    virtual ~MTailMemory();
    friend class MNode;       //Allow MNode access to protected constructor
    friend class MRootMemory;  //Allow MRootMemory access to protected constructor
};


//MVal is the building block of any dictionary.
//Usually MVal holds one Unicode character.
class MVal : public MNode
{
public:
    //All MVal elements found when travaling along the pPrev pointer until a MRoot element 
    //is reached represent a string but in opposite order. For regenerating the string all
    //values have to be collected and reassambled in opposite order. 

    //Report length of current MVal
    virtual void reportLength(unsigned*);
    //Put value chain's string representation into a MString object provided by the caller
    virtual void getString(MString*);
    //Obtain item's hash value
    unsigned getHash();

protected:
    //Report runtime type information
    MNodeType getNodeType();
    //Constructor and destructor
    MVal();
    virtual ~MVal();
    friend class MNode;       //Allow MNode access to protected constructor

#ifdef _DEBUG
public:
    talk(char*);
#endif
};



//MRef represents a complete item (chain of values) toward which it is pointing to.
//On one hand this provides for large memory savings by avoiding multiple storage of
//the same information. On the other hand it is a very fast back-reference from a first
//item to a second item where the first item is a part of the second item.
//(e.g. a word in a dictionary has references to all sentences where it is contained in).
class MRef : public MVal
{
public:
    //Generate (if non-existent) and return a reference to specified item
    MRef* getRef(const MString&);
    //Generate (if non-existent) and return a item based on current MRef node
    MItem* getItem();
protected:
    //Report length of referenced MItem
    void reportLength(unsigned*);
    //Generate URI of referenced MItem
    void generateURI(MString&,const MString&,unsigned*);
    //Weight is the hash value of referenced MItem
    unsigned getWeight();
    //Report if a member variable is used as a pointer (and has to be adjusted on memory restore)
    bool isDataPtr();
    //Report runtime type information
    MNodeType getNodeType();
    //Constructor and destructor
    MRef();
    virtual ~MRef();
    friend class MNode;       //Allow MNode access to protected constructor
};


//A chain of values in a dictionary can be an item. If this is the case then the last 
//MVal node will be followed by MItem (in the linear pChain of all nodes). 
//MItem allows for establishing the following links:
// pPrev - Item's last MVal element
// pNext - Features: Pointer to the last element in a collection of multiple features
//                   where each feature can be any item in current MMemory (e.g. 'noun')
// pMore, pLess - Binary tree (of items' hash values)
// uData - Item's hash value
//The binary hash value tree allows for fast addressing each item by it's hash value.
class MItem : public MNode
{
public:
    //MItem provides access to a single item in a dictionary.
    //An item is a chain of nodes where a node is capable of representing one value, 
    //e.g. a 32-bit value in case of a 32-bit compiler. 
    //Hence an item is a chain of those values. Usually each node will hold a Unicode 
    //value and an item can be treated as a string of Unicode values or simply as a string.
    //However, items are not restricted to strings but can play many other roles dependent 
    //on the application.

    //Access functions to state
    MItem*    getItem(const MString&);
    MConcept* getConcept();
    MString&  getReferent(MString&);
    MString&  getReferent(MString&,const MString&);
    MState*   getState();
    MState*   getState(const MString&);
    MSpecial* getSpecial(MNodeType);

    //Add MState objects
    MSession* addSession();
    MSession* getSession();
    MConcept* setReferent(MSession*,MItem*);
    MState*   setState(MSession*,int);
    MSpecial* addSpecial(MSession*,MNodeType);

    //Check if a MRoot/MTail couple exists and create it if not
    MRoot* getRoot();
    MRoot* getRoot(MNodeType);
    //Obtain next item in current dictionary and return it's last MVal
    MVal* getNextItem();
    //Add a MItem's reference to a dictionary
    MRef* addRef(MNode*);
    //Determine URI's number of bytes and return MRoot
    MRoot* reportLength(unsigned*);
    //Generate URI
    void generateURI(MString&,const MString&,unsigned*);
    //Put current item's string representation into a MString object provided by the caller
    void getString(MString&);

    //Report runtime type 
    MNodeType getNodeType();

protected:
    //Report special features 
    bool isAttachement();
    //Constructor and destructor
    MItem();
    virtual ~MItem();
    friend class MNode;       //Allow MNode access to protected constructor
};



#endif // ifndef _MMEMORY_H_