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