/* graphs.h -- C++ source file for KSI Constraint Graphs
*/
/*
 *
 * 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 GRAPHS_H
#define GRAPHS_H

#ifndef __CSTRING_H
#include 
#endif

#ifndef MAP_H
#include 
#endif

#ifndef SET_H
#include 
#endif

#ifndef VECTOR_H
#include 
#endif

#ifndef FUNCTION_H
#include 
#endif

#ifndef __IOSTREAM_H
#include 
#endif

#ifndef MREF2_H
#include 
#endif

#ifndef MERROR_H
#include 
#endif

#ifndef REFCOUNT_H
#include 
#endif

#ifndef MOBSERVER_H
#include 
#endif

#ifndef MLEXER_H
#include 
#endif

#ifndef GLOBALS_H
#include 
#endif

class TypedGraph;
typedef	unsigned long ID_type;

class GenException
  {
  public:
    GenException(const string& msg): Msg(msg) {}
    string& msg() {return Msg;}
  protected:
    string Msg;
  };


#define ASSERT_MSG(x) "ASSERTION FAIURE: '"\
		      #x\
		      "' in file '"\
		      __FILE__\
		      "'"
#define MASSERT(x) ((x)?1:(error(0,'a',ASSERT_MSG(x)", line %d",__LINE__),0))
#define MASSERT_THROW(x,verbose) if (verbose?!MASSERT(x):!(x)) throw GenException(ASSERT_MSG(x))
#define MASSERT_COMPONENT(x) if (!MASSERT(x)) { \
        error(0,'-',"in Component '%s' (level %d)",getName().c_str(),getLevel()); \
	throw GenException(ASSERT_MSG(x));}

#define NOTHING

/*
  Z spec,
  implementation */
class Attribute
  {
  public:
    typedef string 	ATTRBUTE_NAME;
    enum		Attr_Flags_t {Constant=0x1,Private=0x2};
    typedef		unsigned int Attr_Flags;
			Attribute(const ATTRBUTE_NAME& s, unsigned int prio, Attr_Flags flags)
				: Name(s),Priority(prio),Flags(flags)
				{/*cout << "constructing Attribute " << (unsigned long)this << endl;*/}
			Attribute(const Attribute& a)
				: Name(a.Name),Priority(a.Priority),Flags(a.Flags)
				{/*cout << "copy constructing Attribute " << (unsigned long)this << endl;*/}
    virtual		~Attribute()
				{/*cout << "destructing Attribute " << (unsigned long)this << endl;*/}
    string		getName() const {return Name;}
    unsigned int	getPriority() const {return Priority;}
    Attr_Flags		getFlags() const {return Flags;}
    virtual int		operator<(const Attribute& a) const {return Name < a.Name;}
    virtual Attribute*	clone() const {return new Attribute(*this);}
    virtual void*	getValueAddr() {return NULL;}
    virtual ostream&	printOn(ostream& o) const;
    virtual istream&	readFrom(istream& i);
  private:
    ATTRBUTE_NAME	Name;
    unsigned int	Priority;
    Attr_Flags		Flags;
  };

ostream& operator<<(ostream& o, const Attribute&  t) {return t.printOn(o);}
istream& operator>>(istream& i, const Attribute&  t) {return t.readFrom(i);}

template 
class AttributeValuePair : public Attribute
  {
  public:
			AttributeValuePair(const ATTRBUTE_NAME& s, const T& t, unsigned int prio, Attr_Flags flags)
				: Attribute(s,prio,flags), Value(t) {}
			AttributeValuePair(const AttributeValuePair& x)
				: Attribute(x), Value(x.Value) {}
    virtual AttributeValuePair* clone() const {return new AttributeValuePair(*this);}
    const T&		getValue() const {return Value;}
    const T&		setValue(const T& t) {Value = t; return Value;}
    virtual ostream&	printOn(ostream& o) const
    				{Attribute::printOn(o);
                                 Lexer::writeDelim(o);
                                 o << Value;
                                 return o;}
    virtual istream&	readFrom(istream& i)
    				{Attribute::readFrom(i);
                                 Lexer::readDelim(i);
                                 i >> Value;
                                 return i;}
    virtual void*	getValueAddr() {return &Value;}
  private:
    T			Value;
  };

/*
  Z spec */
template 
AttributeValuePair* MakeAttribute(const Attribute::ATTRBUTE_NAME& s, const T& t, unsigned int prio, Attribute::Attr_Flags flags) {
  return new AttributeValuePair(s,t,prio,flags);
  };

/*
  Z spec,
  implementation */
class Component0 : public Subject //inherit for the Observer/Subject pattern
  {
  friend class TypedGraph;
  public:
    typedef		set, less > PolySetOfAttributes;
    typedef		PolySetOfAttributes::iterator AttrIterator;
			Component0(const string& s, unsigned int level, const PolySetOfAttributes& as=PolySetOfAttributes())
				: Name(s),Level(level),Attributes(as) {};
			Component0(const Component0& c)
				: Subject(c),Name(c.Name),Level(c.Level),Attributes(c.Attributes),Id(c.Id) {};
    virtual void	verify() {}
    Component0&		operator=(const Component0& c);
    virtual int		operator==(const Component0& c) const;
    virtual int		operator<(const Component0& c) const;
    virtual Component0* clone() const {return new Component0(*this);}
    ID_type	getID() const {return Id;}
    const string&	getName() const {return Name;}
    const string&	setName(const string& s) {Name = s; notify(); return Name;}
    unsigned int	getLevel() const {return Level;}
    unsigned int	setLevel(unsigned int level) {Level = level; notify(); return Level;}
    virtual bool	setAttr(Attribute* a);
    virtual AttrIterator getAttr(const string& name) const;
    virtual bool	eraseAttr(const string& name);
    AttrIterator	beginAttr() const {return Attributes.begin();}
    AttrIterator	endAttr() const   {return Attributes.end();}
    virtual int		addConstraint(const string& constraintName);
    //PolySetOfAttributes* getAttributes() {return &Attributes;}
    virtual ostream&	printOn(ostream&) const;
    virtual istream&    readFrom(istream&);
  protected:
    ID_type	Id;
    string		Name;
    unsigned int	Level;
    PolySetOfAttributes	Attributes; //this needs to be ref objects because it's polymorphic
  };

ostream& operator<<(ostream& o, const Component0& t) {return t.printOn(o);}
istream& operator>>(istream& i, const Component0* t) {return t->readFrom(i);}
istream& operator>>(istream& i, const Component0& t) {return t.readFrom(i);}

/*
  Z spec */
class Node0
  {
  public:
    typedef int CONTENTS;
    Node0(const CONTENTS& t) : Contents(t) {}
  protected:
    CONTENTS Contents;
  };

/*
  Z spec */
class NodeComponent: public Component0, public Node0
  {
  public:
    NodeComponent(const string& s, unsigned int level, const CONTENTS& t=CONTENTS(), const PolySetOfAttributes& as=PolySetOfAttributes())
	: Component0(s,level,as), Node0(t) {}
    NodeComponent(const NodeComponent& x)
	: Component0(x), Node0(x.Contents) {}
    virtual NodeComponent* clone() const {return new NodeComponent(*this);}
  };

/*
  Z spec,
  implementation */
class Terminal //Terminals have pointers to Anchors, but they never delete them.
  {
  public:
    typedef enum {TO=0x1,FROM=0x2,BIDIRECT=0x3,NONE=0x0} DIRECTION;
    Terminal(ID_type anchor, DIRECTION dir): Anchor(anchor), Direction(dir) {}
    Terminal(): Anchor(0), Direction(BIDIRECT) {}
    int operator==(const Terminal& t) const {return (Direction==t.Direction)?Anchor==t.Anchor:false;}
    int operator<(const Terminal& t) const {return (Direction==t.Direction)?Anchor>(istream& i, const Terminal* t) {return t->readFrom(i);}
istream& operator>>(istream& i, const Terminal& t) {return t.readFrom(i);}

/*
  Z spec,
  implementation */
class Arc0
  {
  public:
    typedef vector terminals_type;
    typedef terminals_type::iterator TerminalIterator;
    Arc0(const vector& terminals): Terminals(terminals) {}
    virtual void verify() {MASSERT_THROW(Terminals.size()>0,true);}
    void putAnchor(int n, ID_type c, Terminal::DIRECTION dir);
    ID_type getTerminalID(unsigned int n)
	{return n
  Z spec,
  implementation */
class ArcComponent: public Component0, public Arc0
  {
  public:
    ArcComponent(const string& s, unsigned int level, const vector& terminals, const PolySetOfAttributes& as=PolySetOfAttributes())
	: Component0(s,level,as), Arc0(terminals) {}
    ArcComponent(const ArcComponent& x)
	: Component0(x), Arc0(x.Terminals) {}
    virtual void  verify();
    virtual ArcComponent* clone() const {return new ArcComponent(*this);}
    virtual ostream& printOn(ostream&) const;
    virtual istream& readFrom(istream&);
  };

/*
  Z spec,
  implementation */
class IsaComponent: public ArcComponent
  {
  public:
    IsaComponent(const string& s, unsigned int level, const vector& terminals, const PolySetOfAttributes& as=PolySetOfAttributes() )
      : ArcComponent(s,level,terminals) {}
    IsaComponent(const IsaComponent& x)
      : ArcComponent(x) {}
    virtual IsaComponent* clone() const {return new IsaComponent(*this);}
    virtual void  verify();
    static void setPrototype (IsaComponent* x) {Prototype = x;}
    static IsaComponent* getPrototype () {return Prototype;}
    virtual AttrIterator getAttr(const string& name) const;
  protected:
    static IsaComponent* Prototype; //used to get "inherited" attributes from the "prototype" isa component
  };

//TypeGraph is a combination of GRAPH0 and TYPED_GRAPH in the specification (Z
//cannot handle the pre-declaration of VALIDATOR, so GRAPH0 and TYPED_GRAPH had to
//be split).
/*
  Z spec (GRAPH0),
  Z spec (TYPED_GRAPH),
  implementation */
class TypedGraph : public RefCountingObject
  {
  public:
    typedef map< unsigned int, Ref2, less > contents_type;
    typedef contents_type::value_type content_element_type;
    typedef contents_type::iterator ContentsIterator;
    typedef enum {checking=0x1} Flags_type;
    DECL_EXCEPT_CLASS(NOTHING,BadIDException,ErrorMsgException,"Bad ID");
    TypedGraph();
    virtual void verify(unsigned long flags=0/*from Validator::Flags*/);
    virtual void verify(Component0& c, unsigned long flags=0/*from Validator::Flags*/);
    bool parentof(ID_type p, ID_type c) const;
    bool ancestorof(ID_type p, ID_type c) const;
    bool isa(ID_type c, ID_type p) const;

    Attribute* getAttr(ID_type c, const string& attrName);
    //(The GetValue() function is a global template function)
    int setAttr(ID_type c, Attribute* attr);
    int removeAttr(ID_type c, const string& attrName);
    int insertComponent(Component0& c); //this is a low-level method, no checks are done -- you must set its type, etc
    int addNode(NodeComponent& node, ID_type type);
    int addArc(ArcComponent& arc, ID_type type);
    int setComponentType(ID_type c, ID_type type);
    int remove(ID_type c);
    const ID_type getNodeType() {return _node.getID();}
    const ID_type getArcType() {return _arc.getID();}
    const ID_type getIsaType() {return _isa.getID();}
    const ID_type getTopType() {return _top.getID();}
    virtual ostream& printOn(ostream&) const;
    virtual istream& readFrom(istream&);
    Component0& operator[](ID_type id) const;
    virtual long makeNode(string& name, unsigned int level, ID_type type);
    virtual long makeArc(string& name, unsigned int level, ID_type type, vector* terminals=NULL);
    virtual long makeDirArc2(string& name, unsigned int level, ID_type type, ID_type from, ID_type to);
    virtual void flush(); //deletes all contents except for the "fundamental" ones -- arc, node, top, and isa
    virtual bool contains(ID_type id) const;
    virtual void notifyDependents(ID_type id);
    virtual long redirectArcTerminal(ID_type arc, unsigned int index, ID_type target,
	Terminal::DIRECTION* dir=NULL,unsigned long flags=0/*Validator flags*/);
    ContentsIterator beginContents() {return Contents.begin();}
    ContentsIterator endContents() {return Contents.end();}
    virtual bool setChecking(bool b) {bool ret = getChecking(); if (b) Flags |= checking; else Flags &= ~checking; return ret;}
    virtual bool getChecking() {return !!(Flags&checking);}
  protected:
    virtual void verifyPrimative(Component0& c, unsigned long flags=0/*from Validator::Flags*/);
    ID_type getNextID() {return NextID++;}
    IsaComponent makeIsaRelation(ID_type c, ID_type type);
    contents_type Contents;
    Component0 _top;
    NodeComponent _node;
    ArcComponent _arc;
    IsaComponent _isa;
    IsaComponent _nodeIsa;
    IsaComponent _arcIsa;
    IsaComponent _isaIsa;
    ID_type LastFundamentalObject;
    unsigned long Flags;
  private:
    ID_type NextID;
  };

ostream& operator<<(ostream& o, const TypedGraph& t) {return t.printOn(o);};
istream& operator>>(istream& i, TypedGraph& t) {return t.readFrom(i);};

/*
  Z spec,
  implementation */
class FirstOrderTypedGraph: public TypedGraph
  {
  public:
    FirstOrderTypedGraph();//: TypedGraph() {}
    //virtual void verify();
  };

//a utility function -- this one isn't really needed by the spec
template 
int getAttributeValue(const Component0& c, const string& s, T& value)
  { //returns 0 on success, 1 if wrong type, -1 if no matching attribute
  int ret;
  Component0::AttrIterator i = c.getAttr(s);
  if (i==c.endAttr())
    ret = -1; //failed to find the Attribute name
  else { // found the name anyway...
    AttributeValuePair* ap = dynamic_cast*>(&**i);
    if (ap) {
      value = ap->getValue();
      ret = 0; //success
      }
    else ret = 1; //we at least have a matching attribute, but its type may not comform...
    }
  return ret;
  };

//a utility function template
template 
int getValue(TypedGraph& g, ID_type c, const string& s, T& value)
  { //returns 0 on success, 1 if wrong type, -1 if no matching attribute
  int ret;
  Attribute* i = g.getAttr(c,s);
  if (!i)
    ret = -1; //failed to find the Attribute name
  else { // found the name anyway...
    AttributeValuePair* ap = dynamic_cast*>(i);
    if (ap) {
      value = ap->getValue();
      ret = 0; //success
      }
    else ret = 1; //we at least have a matching attribute, but its type may not comform...
    }
  return ret;
  };

//a utility function template
template 
int getValueIndirect(TypedGraph& g, ID_type c, const string& s, T*& value)
  { //returns 0 on success, 1 if wrong type, -1 if no matching attribute
  int ret;
  Attribute* i = g.getAttr(c,s);
  if (!i)
    ret = -1; //failed to find the Attribute name
  else { // found the name anyway...
    AttributeValuePair* ap = dynamic_cast*>(i);
    if (ap) {
      value = &(T&)ap->getValue();
      ret = 0; //success
      }
    else ret = 1; //we at least have a matching attribute, but its type may not comform...
    }
  return ret;
  };

template 
ostream& operator<<(ostream& o, const Ref2&    t) {return t.printOn(o);};
template 
istream& operator<<(istream& i, const Ref2&    t) {return t.readFrom(i);};

#endif
/*


*/