package PM {

//----------------------- Forward declarations -------------------------

	class IntRange;  class Date;  class User;
        abstract class Term;  class Type;
        abstract class ConceptNode; class QNode;

	// by representing numbers as strings, we can apply default values
	// to them, which is convenient until we upgrade HUTN to handle
	// default values on numbers
	typedef string Number;
	typedef string Natural; //positive (or null) integer


//------------------------------ KRelt ---------------------------------

	abstract class KRElt {
	};

	abstract class EltWithCreator {
		attribute string comment; //comment stored with the object
		attribute bag [0..1] of Date creationDate;
		reference creator to creator of HasCreator;
	}; //direct subclasses: Term, Partition, Node and Correction

	abstract class EltWithoutCreator : KRElt {
	}; //direct subclasses: Collection, Value, NameSpace, Quantifier
           //                   and ConflictResolution

	//A node is not a term (named category), it is a structure
	//aggregating a term, a quantifier (implicit/null if the term 
	//is an individual) and other stuff.
	//Similarly, values and name spaces are not terms; they won't 
	//be related by links (e.g. partOf links) like terms arewill.

	association HasCreator { //pm: was called HasCreatedElts
		end set [0..*] of EltWithCreator creatorOf;
		end single User creator;
	};


//-------------------- Link (between named categories) ---------------------

	abstract class Link: EltWithCreator {
		//attribute string name; //instance, subtype, sameAs,
                                  //differentFrom, exclusion, complement, inverse,
                                  //member, part, substance, location, object, url
                attribute boolean isReversed;
		attribute Natural minDomain;
		attribute Natural maxDomain;
		attribute Natural minRange;
		attribute Natural maxRange;
		reference source to source of HasLinkSourceTerm;
		reference dest to dest of HasLinkDestTerm;
	};
	class InstanceOf: Link {};  class Supertype: Link {};
        class Instance: Link {};  class Subtype: Link {};
        class SameAs: Link {}; class DifferentFrom:Link{}; class Exclusion:Link{};
	class Inverse: Link {};   class Complement: Link {};
	class Member: Link {};    class Part: Link {};   class Substance: Link{};
	class Location: Link {};  class Object: Link{};  class Url: Link{};

	//class LinkBetweenTypes: Link {
	//	reference source to source of HasLinkSourceType;
	//	reference dest to dest of HasLinkDestType;
	//};
        //class Subtype:LinkBetweenTypes {};  class Exclusion: LinkBetweenTypes {};
	//class Inverse:LinkBetweenTypes {};  class Complement:LinkBetweenTypes {};

	//association HasLinkSourceType {
	//	end set [0..*] of Link sourceOf;
	//	end single Type source;
	//};
	//association HasLinkDestType {
	//	end set [0..*] of Link destOf;
	//	end single Type dest;
	//};

	//class LinkBetweenTerms: Link {
	//	reference source to source of HasLinkSourceTerms;
	//	reference dest to dest of HasLinkDestTerms;
	//};
        //class Instance: LinkBetweenTerms {};  class SameAs: LinkBetweenTerms {};
	//class DifferentFrom: LinkBetweenTerms {}; 
        //class Member: LinkBetweenTerms {};    class Part: LinkBetweenTerms {};
        //class Substance: LinkBetweenTerms {}; class Location: LinkBetweenTerms{};
        //class Object: LinkBetweenTerms {};    class Url: LinkBetweenTerms {};

	association HasLinkSourceTerm {
		end set [0..*] of Link sourceOf;
		end single Term source;
	};
	association HasLinkDestTerm {
		end set [0..*] of Link destOf;
		end single Term dest;
	};


//------------------------ Term (named category) -----------------------

	abstract class Term: EltWithCreator {
		reference identifier to identifier of HasIdentifier;
		reference name to name of HasName;

		reference sourceOf to sourceOf of HasLinkSourceTerm;
		reference destOf to destOf of HasLinkDestTerm;
		//reference sourceTypeOf to sourceOf of HasLinkSourceType;
		//reference destTypeOf to destOf of HasLinkDestType;


		//to refer to nodes (and hence statements) using this term
		//WITHOUT QUANTIFIER; if "this" is a type, the node is either
		//connected to a second-order relation or is an embedding node
		reference directTNode to termOf of HasConceptNodeTerm;

		//to refer to the user represented by this term
		reference representationOf to representationOf
		                           of HasRepresentation;
	};

	class Indiv: Term { //Individual/type0: term that cannot have instances,
	};                  //                    subtypes or supertypes

	abstract class Type : Term {
		//reference instance to instance of HasInstance;
		//reference subtype to subtype of HasSubtype;
		//reference supertype to subtypeOf of HasSubtype;
		reference subtypePartition to subtypePartitionEltOf
		                           of HasSubtypePartitionElt;
		reference partPartition to partPartitionEltOf
		                        of HasPartPartitionElt;
		reference domainOf to domainOf of HasDomain; //default: any
		reference rangeOf to rangeOf of HasRange;    //default: any

		//to refer to definitions of this type
		reference definition to definition of HasDefinedType;

		//to refer to concept nodes and relations using this type
		//WITH a QUANTIFIER
		reference directQNode to typeOf of HasConceptNodeType;
		reference relation to typeOf of HasRelationType;
	};

	class MetaType : Type { //pm: not used below but Type is abstract
	};

	class CType : Type { //pm: not used below but Type is abstract
	};

	class RType : Type {
//pm: We may want to accept non binary relations even though we also want
//pm: to discourage their use. With the following, relations are only binary. 
		attribute Natural minDomain;
		attribute Natural maxDomain; //if =1, this is a function type?
		attribute Natural minRange; //always 0 (optional to use)!
		attribute Natural maxRange;
		reference domain to domain of HasDomain;
		reference range to range of HasRange;
	};

//pm:	class Alias : Term { //Term that is the destination of an '=' link
//pm:	}; //Can probably be removed (it is an implementation issue).

//pm:	class Undefined : Term { //temporary and not mandatory since Term
//pm:	};                       //can be used instead


	//...... A few links between categories (2nd-order relations)
//pm: can creators be associated to links when represented this way?

	association HasDomain { //for the signature of binary relation
		end single RType domainOf;
		end single Type domain;
	};
	association HasRange { //for the signature of binary relation
		end single RType rangeOf;
		end single Type range;
	};

//--------------------------- Partition --------------------------------

	//a partition is a set of exclusive types or statements

	abstract class Partition : EltWithCreator {
		attribute boolean isClosed; //if not, it is redundant since
		//its elements can be automatically found
	};
	abstract class TypePartition : Partition {
	};
	class SubtypePartition : TypePartition {
		reference subtype to subtype of HasSubtypePartitionElt;
	};
	class PartPartition : TypePartition {
		reference partType to partType of HasPartPartitionElt;
	};

	association HasSubtypePartitionElt {
		end set [0..*] of SubtypePartition subtypePartitionEltOf;
		end set [0..*] of Type subtype;
	};
	association HasPartPartitionElt {
		end set [0..*] of PartPartition partPartitionEltOf;
		end set [0..*] of Type partType;
	};


//----------------------------- Value  ---------------------------------

	abstract class Value: EltWithoutCreator { //it was OntologyElt
	};

	class Time : Value { //originally Time was a struct but it broke HUTN
		attribute Natural year;
		attribute Natural month;
		attribute Natural day;
		attribute Natural hour;
		attribute Natural minute;
		attribute Natural second;
	};
	class Date : Time { 
	};
	class Duration : Time  { 
	};
	class TimeValue: Value {     //pm: not yet used
		attribute Time t;
	};
	class TimeRange: TimeValue { //pm: not yet used
		attribute Time t2;
	};

	class IntValue: Value {     //pm: not yet used
		attribute Natural v;
	};
	class StringValue: Value {
		attribute string s;
	};

	typedef string Variable;




//---------------------- User/NameSpace and Name ----------------------

	// Names, like identifiers, include a reference to a
	// name space and to a name. In fact identifiers are names, the
	// only difference is that two terms may share the same name but
	// cannot share the same identifier. How is this issue dealt above?

	class Name: StringValue {
		reference nameSpace to nameSpace of HasNameSpace;
		reference nameOf to nameOf of HasName;
	};
	class Identifier: Name {
		reference identifierOf to identifierOf of HasIdentifier;
	};
	class NameSpace: EltWithoutCreator { //pm: not Term 
		attribute string name;
		attribute string password;
		//the term representing this namespace is likely to be an URL
		reference term to representation of HasRepresentation;
		reference nameSpaceOf to nameSpaceOf of HasNameSpace;
	};
	class User: NameSpace {
		reference creatorOf to creatorOf of HasCreator;
	};
	association HasRepresentation { //"has a term representing it"
		end single NameSpace representationOf;
		end set [0..*] of Term representation; //most likely only 1
	};
	association HasName {
		end set [0..*] of Term nameOf;
		end set [0..*] of Name name;
	};
	association HasIdentifier {
		end single Term identifierOf; //uniquely identified term
		end set [0..*] of Name identifier; //possibly many identifiers
	};
	association HasNameSpace {
		end ordered set [0..*] of Name nameSpaceOf;
		end set [0..*] of NameSpace nameSpace;
	};



//-------------------------- Collection --------------------------------

	typedef string CollKind; //enum CollKind {cSet,cBag,cList,cSequence};

	typedef string CollAggregation;	//enum CollAggregation {and,or,xor};
	// enum CollInterpretation { distributive, collective, cumulative };
	typedef string CollInterpretation;  //default: distributive

	abstract class Collection : EltWithoutCreator {
		attribute CollKind kind;
		attribute boolean isOpenColl;
		attribute CollAggregation aggregation;
		attribute CollInterpretation interpretation;
	//pm:   attribute Number size; //number of elems: not all may be given
	};


//----------------------------- Node -----------------------------------

	abstract class Node : EltWithCreator {
	};

	abstract class ConceptNode : Node {
		reference sourceOf to sourceOf of HasSourceNode;
		reference destOf to destOf of HasDestNode;
		reference destRefOf to destOf of HasReferredDestNode;
		reference collEltOf to collEltOf of HasCollectionElt;

		//a class EmbeddedNode could be created for the next 2 lines
		//but multi-instantiation would be needed to permit instances
		//of subclasses of Node to be also instance of EmbeddedNode
		attribute boolean isNegated;
		reference embeddingNode to embeddedNodeOf of HasEmbeddedNode;

		//Using variables is one of the ways to
		//1) connect this node to a definition parameter,
		//2) specify that this connect is identical to another node.
		//In both cases, if multi-instantiation is possible,
		//an association could also be used.
		attribute Variable var;
	};

//	enum Modality { noneM, must, may, can }; //default: none
	typedef string Modality;
	class Relation : Node {
                attribute boolean isReversed;
  		attribute Modality modality;
		reference rType to rType of HasRelationType;
		reference source to source of HasSourceNode;
		reference dest to dest of HasDestNode;
		reference destRef to dest of HasReferredDestNode;
	};
	association HasRelationType {
		end set [0..*] of Relation typeOf;
		end single Type rType; //not always RelationType
	};
	association HasSourceNode { //pm: I have reversed the order/direction
		end set [0..*] of Relation sourceOf; //normally 1
		composite end single ConceptNode source;
	};
	association HasDestNode { //pm: I have reversed the order/direction
		composite end single Relation destOf;
		end single ConceptNode dest;         //pm: composite??
	};
	association HasReferredDestNode { //pm: I have reversed the order/direction
		end set [0..*] of Relation destOf;
		end single ConceptNode dest;         //pm: EmbeddingNode?
	};


	//.................. VNode (ConceptNodeForValue) ......................

	// Concept node with just a value (number or time) or an interval of
	// value. Nno term, no quantifier.

	class VNode : ConceptNode {
	};
	//	enum Precision { exact, about, around, atLeast,atMost,between };
	typedef string Precision; //default: exact

	class NodeForNumber : VNode {
		attribute Precision precision;
		attribute Number num;   attribute Number toNumber;
	};
	class NodeForTime : VNode { //point in time or duration
		attribute Time aTime;   attribute Time toTime;
	};


	//................. QNode (QuantifiedConceptNode) .....................

	//enum QuantifierKind { some, few, most, several,
	//                      all, percent, local_any, local_percent };
	typedef string QuantifierKind; //default: some

	class Quantifier : EltWithoutCreator {
		attribute QuantifierKind kind;
		attribute Number num;  //Number HUTNs better than Value
		attribute Number toNumber;
		attribute Precision precision;
	};
	//enum Qualifier {noneQ,small,important,big,great, good,bad};
	typedef string Qualifier; //default: noneQ

	class QNode : ConceptNode {
		reference cType to cType of HasConceptNodeType;
		attribute boolean isNegatedType; //NEW!
		attribute bag [0..1] of Quantifier quantifier;
		attribute Qualifier qualifier;
	};                     //a type may also be used without quantifier 
	association HasConceptNodeType {
		end set [0..*] of Node typeOf;
		end single Type cType;
	};


	//...................... NodeCollection ..........................

	class NodeCollection : QNode, Collection {
		reference collElt to collElt of HasCollectionElt;
	};

	association HasCollectionElt {
		composite end single NodeCollection collEltOf;
		end set [0..*] of ConceptNode collElt;
	};



	//................. TNode (ConceptNodeForTerm) ..................

	//the term may be a type if a second-order relation is connected
	//or, in the case this node is an embedding node (see below), if a
	//statement type (e.g. hypothesis or proof) is given instead of an 
	//individual (if neither is given, the statement type is "statement")

	class TNode : ConceptNode {
		reference term to term of HasConceptNodeTerm;
	};
	association HasConceptNodeTerm {
		end set [0..*] of TNode termOf;
		end single Term term;
	};


	//.................... EmbeddingNode (statement) ......................

	//an embedding node may or may not be quantified.

	abstract class EmbeddingNode : TNode { //assertion/defin./query
		attribute string text; //text used for asserting the node
		                 //or application-dependant place of storage
		reference embeddedNode  to embeddedNode of HasEmbeddedNode;
		reference embeddedNode1 to firstEmbeddedNode
		                           of HasFirstEmbeddedNode;
	};
//pm:	class EmbeddedNode : ConceptNode { //replaced by ENode below
//pm:		reference embeddingNode to embeddedNodeOf of HasEmbeddedNode;
//pm:	};
	association HasEmbeddedNode {
		composite end single EmbeddingNode embeddedNodeOf;
		end set [0..*] of Node embeddedNode; //Node or EmbeddedNode
	};
	association HasFirstEmbeddedNode { //the first node of the statement
		composite end single Node embeddedNodeOf;
		end single Node firstEmbeddedNode; //pm: composite??
	};


	class KRQuery : EmbeddingNode { //to query statements
	};

	class LNode : EmbeddingNode { //a node defining And using a lambda
	};                     //e.g. [most (cat, chrc: a great hapiness)]

	//enum DefKind { NC, SC, NSC }; //necessary and/or sufficient conditions
	typedef string DefKind;
	class Definition : EmbeddingNode {
		reference dType to definedType of HasDefinedType;
		attribute DefKind kind;
		attribute ordered set [0..*] of Variable parameter;
	};
	association HasDefinedType {
		end set [0..*] of Definition definition;
		end single Type definedType;
	};


	class Assertion : EmbeddingNode { //to assert stuff
		reference sourceCorrectionOf to sourceCorrectionOf
		                             of HasSourceCorrection;
		reference destCorrectionOf to destCorrectionOf
		                           of HasDestCorrection;
		reference conflictingNodeOf to conflictingNodeOf
		                            of HasConflictingNode;
	};

	class ENode : EmbeddingNode { //for embedded and embedding statements
	};


//----------------- Correction between assertions  -------------------

	//To permit a user to record conflicting between 2 statements/beliefs.
	typedef string CorrectionKind; //e.g. corrective_specialization,
	   //corrective_generalization, correction (if previous don't apply),
	   //correction (if the previous do not apply; e.g. "counterexample"),
	   //overriding_specialization (e.g. "instantiation")

	class Correction : EltWithCreator {
		attribute CorrectionKind kind;
		reference source to sourceCorrection of HasSourceCorrection;
		reference dest to destCorrection of HasDestCorrection;
		reference correctionOf to correctionOf of HasCorrection;
	};
	association HasSourceCorrection {
		end single Correction sourceCorrectionOf;
		end set [1..1] of Assertion sourceCorrection;
	};
	association HasDestCorrection {
		end single Correction destCorrectionOf;
		end set [1..1] of Assertion destCorrection;
	};

	//Simple elaborations are automatically detected or should be stored
	//using rhetorical/argumentation relations between assertions.



//-------------------- ConflictResolution ----------------------------

	//To record that two (or more?) assertions are in conflict
	//and the corrections that have been made to solve that conflict.

	typedef string ConflictResolutionStrategy;

	class ConflictResolution : EltWithoutCreator {//Correction has creator
		attribute ConflictResolutionStrategy strategy;
		reference input to conflictingNode of HasConflictingNode;
		reference output to correction of HasCorrection;
	};
	association HasConflictingNode {
		end single ConflictResolution conflictingNodeOf;
		end set [2..*] of Assertion conflictingNode;
	};
	association HasCorrection {
		end set [0..*] of ConflictResolution correctionOf;
		end set [0..*] of Correction correction;
	};

};