package KR {

	// some forward declarations 

	class IntRange;

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

	// now to begin for real

	abstract class KRElt {
		reference creator to creator of Creates;
	};

	abstract class OntologyElt : KRElt {
	};

	abstract class Term: OntologyElt {
		reference binding to binding of NameBinds;
		reference mutex1 to mutex1 of Mutex;
		reference mutex2 to mutex2 of Mutex;
		reference comp1 to comp1 of Complement;
		reference comp2 to comp2 of Complement;
		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;
	};

	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 single Term members;
		end set [0..*] of Term member;
	};

	association WholePart {
		end single Term whole;
		end set [0..*] of Term part;
	};

	association CombinedSubstance {
		end single Term combined;
		end set [0..*] of Term substance;
	};

	abstract class Type : Term {
		reference supertype to supertype of Generalises;
		reference subtype to subtype of Generalises;
		reference instance to instance of IsOfType;
	};

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

	class ConceptType : Type {
		reference role1 to relnsig of Role1Type;
		reference role2 to relnsig of Role2Type;
	};

	class RelnType: Type {
	};

	class RelnSig: RelnType {
		attribute Number lower1;
		attribute Number upper1;
		attribute Number lower2;
		attribute Number upper2;
		reference type1 to concept1type of Role1Type;
		reference type2 to concept2type of Role2Type;
	};

	association Role1Type {
		end set [0..*] of  RelnSig relnsig;
		end single ConceptType concept1type;
	};
		
	association Role2Type {
		end set [0..*] of RelnSig relnsig;
		end single ConceptType concept2type;
	};

	abstract class Instance : Term {
		reference type to type of IsOfType;
	};

	association IsOfType {
		end set [0..*] of  Type type;
		end set [0..*] of Instance instance;
	};

	class ConceptInstance: Instance {
	};

	class NameSpace: Term {
		reference my_binding to binding of AssignsName;
	};

	class User: NameSpace {
		reference elt to elt of Creates;
	};

	class Alias : Term {
		// not really sure what this is for
	};

	class Undefined : Term {
	};

	class Partition: OntologyElt {
	};

	abstract class Value: OntologyElt {
	};

	class IntValue: Value {
		attribute Number v1;
	};

	class IntRange: IntValue {
		attribute Number v2;
	};

	class StringValue: Value {
		attribute string s1;
	};

	class StringRange: StringValue {
		attribute string s2;
	};

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

	// orginally Date was a struct but it broke HUTN

	class Date {
		attribute Number year;
		attribute Number month;
		attribute Number day;
		attribute Number hour;
		attribute Number minute;
		attribute Number second;
		attribute boolean absolute;
	};

	class DateValue: Value {
		attribute Date d1;
	};

	class DateRange: DateValue {
		attribute Date d2;
	};

	class TermValue: Value {
		reference term to term of TermRef;
	};

	association Creates {
		end single User creator;
		end set [0..*] of KRElt elt;
	};

	// I would like a ternary assocation (NameSpace, Name, KRElt)
	// 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; 
	};

	association TermRef {
		end single TermValue termvalue;
		end single Term term;
	};

	enum QuantifierKind { a_an, the, few, some, majority, most, all, atmost, atleast, exactly, about };

	class Quantifier {
		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 Node: ConceptInstance {
		attribute boolean negate;
		attribute string text;
		attribute Quantifier quantifier;
		attribute Qualifier qualifier;
		reference src_of to src_of of IsSrcOf;
		reference dest_of to dest_of of IsDestOf;
		reference collection to members of HasMember;
		reference is_subject to is_subject of HasSubject;
	};

	class RelnInstance : Instance {
		attribute boolean converse;
		attribute Modality modality;
		reference src to src of IsSrcOf;
		reference dest to dest of IsDestOf;
	};

	association IsSrcOf {
		composite end single Node src;
		end set [0..*] of RelnInstance src_of;
	};

	association IsDestOf {
		end single Node dest;
		composite end single RelnInstance dest_of;
	};

	// 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 CollectionNode : Node {
		attribute CollectionKind kind;
		attribute Aggregator agg;
		attribute Distributes dist;
		reference node_member to member of HasMember;
	};

	abstract class Stmt : Node {
		reference subject to subject of HasSubject;
	};

	association HasSubject {
		composite end single Stmt is_subject;
		end single Node subject;
	};

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

	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 {
		// a DefnNode is only allowed to be used by Defn
		attribute list [0..*] of Parameter formal; 
	};

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

	typedef string ConflictKind;

	class Conflict : KRElt {
		attribute ConflictKind 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;
	};

	// how to fix incorrect assertions

	typedef string CorrectionKind;

	class Correction : 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;
	};

	association Fixes {
		end set [0..*] of Correction correction;
		end set [0..*] of Conflict conflict;
	};

	// specialised assertions can elaborate more general assertions

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

	class Elaboration : 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
		
};