//Additions by Ph. Martin are prefixed by "//pm: ".
//All associations now use normalised names (this is a big help to me).
//All boolean attributes begin by "is".
//The Intercap style is always used.
//I don't know when using the keyword "composite" is appropriate or not.


package KR {

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

	class IntRange;  class Date;

	// 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 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;
	};



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

//pm:	abstract class OntologyElt : KRElt {
//pm: 	};  //removed since no difference between Term and OntologyElt

	abstract class Term: EltWithCreator {
#ifdef KerryNameBinding
		reference nameBinding to nameBinding of HasNameBinding;
#else
		reference identifier to identifier of HasIdentifier;
		reference name to name of HasName;
#endif

		reference type to instanceOf of HasInstance;

		//2 classic symmetric "links" (2nd-order relations):
		reference exclusion to exclusion of HasExclusion;
		reference complement to complement of HasComplement;

		//The following 6 kinds of "links" are only for convenience
		//and because lexical ontologies such as WordNet use them
		//(with unclear semantics). Here, we consider them as shorcuts
		//for statements using concept nodes and relation nodes,
		//as in the following example: "AirPlane part Wing" and
		//"Wing partOf AirPlane" are equivalent to the statement
		//"most Airplane have for part a Wing".
		reference member to member of HasMember;
		reference memberOf to memberOf of HasMember;
		reference part to part of HasPart;
		reference partOf to partOf of HasPart;
		reference substance to substance of HasSubstance;
		reference substanceOf to substanceOf of HasSubstance;
		reference object to object of HasObject;
		reference objectOf to objectOf of HasObject;
		reference location to location of HasLocation;
		reference locationOf to locationOf of HasLocation;
		reference url to url of HasUrl;
		reference urlOf to urlOf of HasUrl;

		//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 user that are represented by this term
		reference representationOf to representationOf
		                           of HasRepresentation;
	};

	class Individual: Term { //or 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 concept nodes and relations using this type
		reference directQNode to typeOf of HasConceptNodeType;
		reference relation to typeOf of HasRelationType;
	};

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

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

	class RelationType : 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;
		reference reverse to reverse of HasReverse;
	};

//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 RelationType domainOf;
		end single Type domain;
	};
	association HasRange { //for the signature of binary relation
		end single RelationType rangeOf;
		end single Type range;
	};

	association HasInstance { //the most common link; transitive
		end set [0..*] of Type instanceOf;
		end set [0..*] of Term instance;
	};
	association HasSubtype { //the second most common link; transitive
		end set [0..*] of Type subtypeOf;
		end set [0..*] of Type subtype;
	};
	association HasExclusion { //the third most common link; symmetric
		end set [0..*] of Term exclusionOf;
		end set [0..*] of Term exclusion;
	};
	association HasComplement { //symmetric 
		end set [0..*] of Term complementOf;
		end set [0..*] of Term complement;
	};
	association HasReverse { //symmetric 
		end set [0..*] of Term reverseOf;
		end set [0..*] of Term reverse;
	};

	//some shortcut links often used in lexical ontologies 
	association HasMember {
		end set [0..*] of Term memberOf;    //pm: not single
		end set [0..*] of Term member;
	};
	association HasPart {
		end set [0..*] of Term partOf;      //pm: not single
		end set [0..*] of Term part;
	};
	association HasSubstance {
		end set [0..*] of Term substanceOf; //pm: not single
		end set [0..*] of Term substance;
	};
	association HasObject { //process object or domain object
		end set [0..*] of Term objectOf;
		end set [0..*] of Term object;
	};
	association HasLocation { //place, region, ...
		end set [0..*] of Term locationOf;
		end set [0..*] of Term location;
	};
	association HasURL {
		end set [0..*] of Term urlOf;
		end set [0..*] of Term url;
	};


//--------------------------- 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 type to type of HasSubtypePartitionElt;
	};
	class PartPartition : TypePartition {
		reference type to type of HasPartPartitionElt;
	};

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


//----------------------------- 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;
		attribute boolean isAbsolute;
	};
	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;
	};
//pm:	class IntRange: IntValue {  //pm: not yet used
//pm:		attribute Natural v2;
//pm:	};

	class StringValue: Value {
		attribute string s;
	};
//pm:	class StringRange: StringValue { //pm: not yet used
//pm:		attribute string s2;
//pm:	};

#if 0
	class Variable: StringValue {
		attribute string sv;
	};
#else
	typedef string Variable;
#endif



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

#ifdef KerryNameBinding
	// Kerry would like a ternary assocation (NameSpace, Name, Term);
	// she uses the binary association HasNameBinding (previously
	// called NameBinds) from a term to an object of class NameBinding
	// which is also associated to objects of class NameSpace and Name
	// via the associations HasNameSpace and HasBindedName

	class Name: StringValue {
		reference binding to binding of HasName;
	};

	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 nameBinding to nameBinding of HasNameSpace;
	};
	class User: NameSpace {
		reference creatorOf to creatorOf of HasCreator;
	};
	association HasRepresentation {
		end single NameSpace representationOf;
		end set [0..*] of Term representation; //most likely only 1
	};

	class NameBinding {
		reference term to term of HasNameBinding;
		reference nameSpace to nameSpace of HasNameSpace;
		reference name to name of HasBindedName;
	};
	association HasNameBinding {
		end set [0..*] of NameBinding nameBinding;
		end single Term term;
	};
	association HasNameSpace {
		end ordered set [0..*] of NameBinding nameBinding;
		composite end single NameSpace nameSpace;
	};
	association HasBindedName {
		end set [0..*] of NameBinding nameBinding;
		end single Name name;
	};
#else
	// Philippe is MUCH more comfortable with the binary associations
	// - HasIdentifier which goes from a term to an identifier, and
	// - HasName which goes from a term to a name.
	// Here, 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 identifier; //possibly many identifiers
	};
	association HasNameSpace {
		end ordered set [0..*] of Name nameSpaceOf;
		end ordered set [0..*] of NameSpace nameSpace;
	};
#endif


//-------------------------- Collection --------------------------------
	//Not a node because a node with a collection may or may not be
	//quantified, so multi-inheritance would be required.

	enum CollKind { set, bag, list, sequence };
	enum CollAggregation { and, or, xor };
	enum CollInterpretation { collective, cumulative }; //default: distrib.

	class Collection : EltWithoutCreator {
		attribute CollectionKind kind;
		attribute boolean isClosedColl;
		attribute CollAggregation aggregation;
		attribute CollInterpretation interpretation;
	//pm:   attribute Number size; //number of elems: not all may be given
	};
	class NodeCollection : Collection {
		reference collOf to collOf of HasCollection;
		reference collElt to collElt of HasCollectionElt;
	};
	association HasCollection {
		end single ConceptNode collOf;
		end set [0..*] of NodeWithCollection coll;
	};
	association HasCollectionElt {
		end set [0..*] of NodeWithCollection collEltOf;
		end set [0..*] of ConceptNode collElt;
	};

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

	abstract class Node : EltWithCreator {
	};

	abstract class ConceptNode : Node {
		reference sourceOf to sourceOf of HasOriginNode;
		reference destOf to destOf of HasDestNode;
		reference coll to coll of HasCollection;
		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 { must, may, can }; //default: none
	class Relation : Node {
                attribute boolean isReversed;
  		attribute Modality modality;
		reference type to type of HasRelationType;
		reference source to source of HasSourceNode;
		reference dest to dest of HasDestNode;
	};
	association HasRelationType {
		end set [0..*] of ConceptNode typeOf;
		composite end single Type type; //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??
	};


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

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

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


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

	     //precision/approximation: by default "exact" (not specified)
	enum Precision { about, around, atLeast, atMost, between };
	enum QuantificationKind { few, most, several,    //default: some
                                  any, percent, local_any, local_percent };
	class Quantifier : EltWithoutCreator {
		attribute QuantifierKind kind;
		attribute Number number;  //Number HUTNs better than Value
		attribute Number toNumber;
		attribute Precision precision;
	};
	enum Qualifier {small, important,big,great, good,bad}; //default:none

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


	//................. 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 type to type of HasConceptNodeTerm;
	};
	association HasConceptNodeTerm {
		end set [0..*] of TNode termOf;
		composite 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 firstEmbeddedNode to firstEmbeddedNode
		                            of HasFirstEmbeddedNode;
	};
//pm:	class EmbeddedNode : ConceptNode {
//pm:		attribute boolean isNegated;
//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 EmbeddedNode embeddedNode; //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
	class Definition : EmbeddingNode {
		attribute DefKind kind;
		attribute ordered set [0..*] of Variable parameter;
	};

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


//----------------- 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;
	};

};