//The corrections (and some additions) by Ph. M. are prefixed by "//pm: ".


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;


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

	abstract class KRElt {
	};

	abstract class EltWithCreator {
		attribute string comment; //comment stored with the object
		attribute Date creationDate;
		reference creator to creator of Creates;
	}; //pm: direct subclasses: Term, Partition, Node,
	   //pm:                    Elaboration, Correction

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

	//A node is not a term (named categories), 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 are.

	association Creates {
		end single User creator;
		end set [0..*] of EltWithCreator elt; //pm: not KRElt
	};



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

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

	abstract class Term: EltWithCreator {
		reference instanceOf to instanceOf of HasInstance;
//pm: any term (type or individual) can be instance of a higher-order type
//pm: the association IsOfType has been renamed HasInstance

		reference binding to binding of NameBinds;
		reference type to instanceOf of HasInstance;
		reference mutex1 to mutex1 of Mutex;
	//pm:	reference mutex2 to mutex2 of Mutex; 
	//pm: removed since mutex1=mutex2 (exclusion links are symmetric)
		reference comp1 to comp1 of Complement;
	//pm:	reference comp2 to comp2 of Complement;
	//pm: removed since comp1=comp2 (complement links are symmetric)
		reference members to members of HasMember;
		reference member to member of HasMember;
		reference whole to whole of WholePart;
		reference part to part of WholePart;
		reference combined to combined of CombinedSubstance;
		reference substance to substance of CombinedSubstance;

		//to refer to nodes (and hence statements) using this term:
		reference directNode to termOf of HasConceptNodeTerm;
	};

//pm: any term can be an instance, so this class is replaced by the next
//pm:	abstract class Instance : Term {
//pm:		reference type to instanceOf of HasInstance;
//pm:	};
	class Individual: Term {//or type0: term that cannot have instances,
	};                      //                    subtypes or supertypes

	abstract class Type : Term {
		reference instance to instance of HasInstance;
		reference supertype to supertype of Generalises;
		reference subtype to subtype of Generalises;
//pm: any type may be used in a relation signature
//the next two lines replace the ones in ConceptType
		reference domainOf to domainOf of HasDomain;
		reference rangeOf to rangeOf of HasRange;

		//to refer to relations using this type
		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
//pm:		reference role1 to relnsig of Role1Type;
//pm:		reference role2 to relnsig of Role2Type;
	};

	class RelnType: Type { //pm: RelnSig removed (see below)
/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. 
//pm: The next 4 lines are the lines of RelnSig but with better names.
		attribute Number minDomain;
		attribute Number maxDomain;
		attribute Number minRange;
		attribute Number maxRange;
		reference domain to domain of HasDomain;
		reference range to range of HasRange;
	};
//pm:	class RelnSig: RelnType { //A signature is not a relation type.
//pm:	                          //A relation type HAS a signature.
//pm:		attribute Number lower1;
//pm:		attribute Number upper1;
//pm:		attribute Number lower2;
//pm:		attribute Number upper2;
//pm:		reference type1 to concept1type of Role1Type;
//pm:		reference type2 to concept2type of Role2Type;
//pm:	};


//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 { //pm: was called Role1Type
		end single RelationType domainOf; //pm: not RelnSig relnsig
		end single Type domain; //pm: not ConceptType concept1type
	};
	association HasRange { //pm: was called Role2Type
		end single RelationType rangeOf; //pm: not RelnSig relnsig
		end single Type range; //pm: not ConceptType concept2type
	};

	association HasInstance { //pm: it was called IsOfType
		end set [0..*] of Type instanceOf; //pm: was called type
		end set [0..*] of Term instance;//pm: Instance -> Term
	};     //since types too can be instance of higher-order types

	association Generalises {
		end set [0..*] of Type supertype;
		end set [0..*] of Type subtype;
	};

	association Mutex {
		end set [0..*] of Term mutex1;
		end set [0..*] of Term mutex2;
	};
	association Complement {
		end set [0..*] of Term comp1;
		end set [0..*] of Term comp2;
	};
	association HasMember {
		end set [0..*] of Term members;   //pm: not single
		end set [0..*] of Term member;
	};
	association WholePart {
		end set [0..*] of Term whole;     //pm: not single
		end set [0..*] of Term part;
	};
	association CombinedSubstance {
		end set [0..*] of Term combined;  //pm: not single
		end set [0..*] of Term substance;
	};


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

	class Partition: EltWithCreator { //pm: it was OntologyElt
	};



//---------------------- Value (e.g. Name) ----------------------

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

	class Time : Value { //originally Time was a struct but it broke HUTN
		attribute Number year;
		attribute Number month;
		attribute Number day;
		attribute Number hour;
		attribute Number minute;
		attribute Number second;
		attribute boolean absolute;
	};
	class Date : Time { 
	};
	class Duration : Time  { 
	};
	class TimeValue: Value {      //pm: not yet used
		attribute Time d1;
	};
	class TimeRange: TimeValue {  //pm: not yet used
		attribute Time d2;
	};


//pm:	class TermValue: Value {      //pm: not yet used
//pm:		reference term to term of TermRef;
//pm:	};
//pm:	association TermRef {
//pm:		end single TermValue termvalue;
//pm:		end single Term term;
//pm:	};

	class IntValue: Value {
		attribute Number v1;
	};
	class IntRange: IntValue {       //pm: not yet used
		attribute Number v2;
	};

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


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

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

	class NameSpace: EltWithoutCreator { //pm: not Term
		reference term to term of HasRepresentation;
		reference my_binding to binding of AssignsName;
	};
	class User: NameSpace {
		reference elt to elt of Creates;
		attribute string password;
	};
	association HasRepresentation { //pm: added this
		end single NameSpace representationOf;
		end set [0..*] of Term term; //most likely only 1
	};

	// I would like a ternary assocation (NameSpace, Name, Term)
	// so I need to create an intermediate class
	class NameBinding {
		reference namespace to namespace of AssignsName;
		reference name to name of NameIs;
		reference named to named of NameBinds;
	};
	association AssignsName {
		composite end single NameSpace namespace;
		end ordered set [0..*] of NameBinding binding;
	};
	association NameIs {
		end set [0..*] of NameBinding binding;
		end single Name name;
	};
	association NameBinds {
		end set [0..*] of NameBinding binding;
		end single Term named; 
	};



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

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

	// could use enums for the items below
	typedef string CollectionKind;	// "set", "bag", "list" etc 
	typedef string Aggregator; 	// "and", "or", "xor"
	typedef string Distributes; 	// "yes", "no", "cumulative", ...

	class Collection : EltWithoutCreator { //not ConceptNode
		attribute CollectionKind kind;
		attribute Aggregator agg;
		attribute Distributes dist;
	};
	class NodeCollection : Collection {
//pm:		reference node_member to member of HasMember; //node!=term
		reference collElt to collElt of HasCollectionElt;
	};
	association HasCollectionElt {
		composite end single NodeWithCollection collEltOf;//composite?
		end set [0..*] of Node collElt; //Node or EmbeddedNode
	};



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

	class Node : EltWithCreator { //pm: this is a new class
	};


	enum QuantifierKind { a_an_the_some, few, most_majority, all,
                              atMost, atLeast, about };
	//pm: quantifiers modified to reflect equivalences
	//pm: "exactly" removed since implicit

	class Quantifier : EltWithoutCreator {
		attribute QuantifierKind kind;
		// should use Value below but this HUTNs better
		attribute string num;
		attribute string to_num;
		attribute boolean percent;
	};
	typedef string Qualifier;	// "good", "bad", ...
	typedef string Modality;	// "must", "may" ...

	class ConceptNode: Node { //pm: ConceptInstance replaced by Node
		attribute boolean negate;
		attribute string text;
		attribute Quantifier quantifier;
		attribute Qualifier qualifier;
		reference term to term of HasConceptNodeTerm; //node not a term
		reference src_of to src_of of IsSrcOf;
		reference dest_of to dest_of of IsDestOf;

//pm:		reference collection to members of HasMember; //node not a term
		reference collEltOf to collEltOf of HasCollectionElt;

		reference is_subject to is_subject of HasSubject;
	};
	association HasConceptNodeTerm {
		end set [0..*] of Node termOf;
		composite end single Term term;
	};


	class Relation : Node { //pm: not "RelnInstance : Instance"
 		attribute boolean converse;
		attribute Modality modality;
		reference type to type of HasNodeType; //a node is not a term
		reference src to src of IsSrcOf;
		reference dest to dest of IsDestOf;
	};
	association HasRelationType {  //pm: new association
		end set [0..*] of ConceptNode typeOf;
		composite end single Type type; //not always RelationType
	};
	association IsSrcOf {
		composite end single ConceptNode src; //pm: not just Node
		end set [0..*] of Relation src_of;
	};
	association IsDestOf {
		end single ConceptNode dest; //pm: not just Node
		composite end single Relation dest_of;
	};


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

	abstract class Stmt : Node {
		reference subject to subject of HasSubject;
	};
	association HasSubject {
		composite end single Stmt is_subject;
		end single Node subject;
	};

	class KRQuery : Stmt {
		// this is where we ask about what we've said
	};

	typedef string Parameter;
	typedef string Condition;	//"necessary", "sufficient", "both"
	class Defn : Stmt {
		attribute ordered set [0..*] of Parameter formal;
		attribute Condition cond;	
	};
	class DefnNode : Node { //pm: is this class useful?
		// a DefnNode is only allowed to be used by Defn
		attribute list [0..*] of Parameter formal; 
	};

	class Assertion : Stmt { // this is where we say stuff
		reference conflict to conflict of Conflicts;
		reference superseded_by to correction of BeforeCorrection;
		reference supersedes to correction of AfterCorrection;
	};


//------------------ Elaboration between assertions  -------------------

	// specialised assertions can elaborate more general assertions

	typedef string ElaborationKind; // "example", "counterexample" ...

	class Elaboration : EltWithCreator { //not KRElt
		attribute ElaborationKind kind;
		reference general to general of HasGeneralisation;
		reference special to special of HasSpecialisation;
	};

	association HasGeneralisation {
		end single Elaboration elaboration;
		end set [1..*] of Assertion general;
	};

	association HasSpecialisation {
		end single Elaboration elaboration;
		end set [1..*] of Assertion special;
	};

	// we could define Example as a specialisation of Elaboration
	// but I don't think we gain much from doing so
	// if the ontology could have abstract/concrete types
	// then an Example would only have instances of concrete types


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

	typedef string CorrectionKind;

	class Correction : EltWithCreator { //pm: not KRElt
		attribute CorrectionKind kind;
		reference before to before of BeforeCorrection;
		reference after to after of AfterCorrection;
		reference fixes to conflict of Fixes;
	};

	association BeforeCorrection {
		end single Correction correction;
		end set [1..*] of Assertion before;
	};
	association AfterCorrection {
		end single Correction correction;
		end set [0..*] of Assertion after;
	};


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

	// how to record that two or more assertions are in conflict

	typedef string ConflictResolutionKind;

	//the next class was called Conflict
	class ConflictResolution : EltWithoutCreator { //pm: not KRElt
		attribute ConflictResolutionKind kind;
		reference conflicting to conflicting of Conflicts;
		reference correction to correction of Fixes;
	};

	association Conflicts {
		end single Conflict conflict;
		end set [2..*] of Assertion conflicting;
	};
	association Fixes {
		end set [0..*] of Correction correction;
		end set [0..*] of ConflictResolution conflict;
	};
};