public class Class {
    public attribute Native: Boolean;
    public attribute Abstract:Boolean;
    public attribute Public: Boolean;
    public attribute Private: Boolean;
    public attribute Protected: Boolean;
    public attribute Name: String;
    public attribute Documentation:String?;
    public attribute Superclasses: Class* inverse Class.Subclasses;
    public attribute Subclasses: Class* inverse Class.Superclasses;
    public attribute Attributes: Attribute* inverse Attribute.Scope;
    public attribute Operations: Operation* inverse Operation.Target;
    public function getAllAttributes(): Attribute*;
    public function getAllSuperclasses(): Class*;
    public function instantiate():*;
}

function Class.getAllSuperclasses() = 
   select distinct [c, c.getAllSuperclasses()] from c in Superclasses;

function Class.getAllAttributes() =
   select distinct c.Attributes from c in this.getAllSuperclasses();

public class Operation extends Class {
    public attribute Target: Class? inverse Class.Operations;
}

public class Attribute {
    public attribute Public: Boolean;
    public attribute Private: Boolean;
    public attribute Protected: Boolean;
    public attribute Name: String;
    public attribute Documentation:String?;
    public attribute Scope: Class? inverse Class.Attributes;
    public attribute Type: Class?;
    public attribute Inverse: Attribute* inverse Attribute.Inverse;
    public attribute OneToOne: Boolean;
    public attribute ManyToOne: Boolean;
    public attribute OneToMany: Boolean;
    public attribute ManyToMany: Boolean;
    public attribute Optional: Boolean;
    public attribute Part: Boolean;      
    public attribute Readonly: Boolean;
}

public class Assertion {
    public attribute description: String*;
    public attribute sourceURL: String?;
    public attribute lineNumber: Number;
    public attribute assertion: String;
    public attribute result: Boolean;
}

trigger on (Attribute.ManyToMany = value) {
    this.OneToMany = not value;
    this.OneToOne = not value;
    this.ManyToOne = not value;
}

trigger on (Attribute.OneToMany = value) {
    this.ManyToMany = not value;
    this.OneToOne = not value;
    this.ManyToOne = not value;
}

trigger on (Attribute.ManyToOne = value) {
    this.OneToMany = not value;
    this.OneToOne = not value;
    this.ManyToMany = not value;
}

trigger on (Attribute.OneToOne = value) {
    this.OneToMany = not value;
    this.ManyToOne = not value;
    this.ManyToMany = not value;
}


