/*

Copyright: All contributers to the Umple Project

This file is made available subject to the open source license found at:
http://umple.org/license

The main Umple metamodel.

 */

namespace cruise.umple.compiler;
external interface Runnable {}

/*
 * Class UmpleModel is the central class describing the system being compiled.
 * 
 * The model contains everything that was derived from an Umple file (.ump) when it was parsed such as 
 * the classes, attributes, associations, state machines, methods, etc that were in it.
 * 
 * Put another way, when an Umple file (.ump) is parsed an Umple model is populated with everything that was parsed from that file.
 * 
 * Because of this it is absolutely critical to understand the model since it is basically the "root" of everything.
 */
class UmpleModel
{
  depend cruise.umple.analysis.*;
  depend cruise.umple.util.*;
  depend cruise.umple.compiler.exceptions.*;
  isA Runnable;

  // The Umple file (.ump) that was used to populate the model.
  UmpleFile umpleFile;

  defaultPackage = null;
  GenerateTarget[] generates;
  Boolean shouldGenerate = true;
  Glossary glossary = new Glossary();
  String defaultNamespace = null;
  String code = null;
  Boolean debugMode = false;
  ParseResult lastResult = null;

  Map<String,String> generatedCode = new HashMap<String,String>();
  Map<String,Analyzer> analyzers = new HashMap<String,Analyzer>();

  // data for default class positioning
  internal Coordinate levelOffset = new Coordinate(200,100,0,0);
  internal Coordinate initialOffset = new Coordinate(50,30,0,0);
  internal Coordinate classSize = new Coordinate(0,0,109,45);
  internal int maxYLevels = 5;
  
  // Top level blocks code contained within a model.
  // extraCodes will be generated in a single file
  lazy CodeBlock[] extraCodes;

  // data for default association positioning
  internal Coordinate offsetFromEdge = new Coordinate(10,30,0,0);
  internal int reflexiveSegmentLength = 15;

  // The Associations contained within the model.
  1 -> * Association;

  // The Umple Classes contained within the model.
  1 -> * UmpleClass;
 
  // The Umple Traits contained within the model.
  1 -> * UmpleTrait;
 
  // The Umple Templates contained within the model.
  1 -> * UmpleTemplate;
 
  // The State Machines contained within the model.
  1 -> * StateMachine stateMachineDefinitions;

  // The Umple interfaces contained within the model.
  1 -> * UmpleInterface;
}

/*
 * An UmpleElement is one of the top-level items found in an Umple model
 * Currently it has one subclass, UmpleClassifier
 */
class UmpleElement
{
  depend cruise.umple.compiler.Position;

  // The name of the Umple element.
  name;
  
  // The position(s) of the element in the source code, used in debugging
  //  may have multiple positions in the case of mixins
  1 -> 0..* Position positions;
  1 -> 0..* Position endPositions; // Kept aligned with positions

  // The modifier associated with the Umple element.
  modifier = null;
  
  Boolean hasMainMethod = false;

  String[] namespaces;

  packageName = "";

  // The code associated with the Umple element.
  internal ExtraCode extraCode = new ExtraCode();

  // Specifies whether or not the Umple element is internal.
  Boolean isInternal = false;

  // Specifies the position of this Umple element (ex. The UmpleOnline diagram).
  Coordinate coordinates = new Coordinate(-1,-1,-1,-1);
  // Specifies the display color of this element
  String displayColor = "";

  before setPackageName { if (aPackageName == null) { return false; } }  
}

/*
 * A method in an Umple class or interface
 * Umple Methods are coded by the programmer in the language(s) of their choice
 */
class Method
{
  depend cruise.umple.compiler.Position;

  // Specifies whether or not the Method is abstract.
  Boolean isAbstract = false;
  
  // The modifier associated with the method.
  modifier;

  // The name of the method. 
  name;
  
  lazy Position position;
  lazy Position codePosition;
  lazy Position endPosition;

  // The type of the method.
  type;

  // Specifies whether or not the method is implemented.
  Boolean isImplemented;

  // The method parameters.
  1 -> 0..* MethodParameter;

  // The body of the method (such as the code within).
  1 -> 0..1 MethodBody;

  // The comments associated with the method (such as the Javadoc above it).
  1 -> * Comment;
  
}

 /*
 * The contents of a method, such as the code within it.
 */
class MethodBody
{

  depend java.util.*;
  
  // The code within the method body.
  extraCode = {codeblock.getCode() != null ? codeblock.getCode() : ""}
  CodeBlock codeblock;
  Map<String,Position> implementationPositions = new HashMap<String,Position>();
}

/*
 * Represents a constant.
 */
class Constant
{
  // The name of the constant.
  name;

  // The type of the constant.
  type;

  // The modifier of the constant.
  modifier; 

  // The value of the constant.
  value;

  class UniqueIdentifier { } 
}

/*
 * Represents a parameter in a method and its various forms.
 */
class MethodParameter
{
  isA UmpleVariable;

  // Specifies whether or not the method parameter is auto unique.
  Boolean isAutounique; // TODO: should default to false, but constructors would need updating

  // Specifies whether or not the method parameter is a list.
  Boolean isList = false;

  // Specifies whether or not the method parameter is derived.
  Boolean isDerived = false;

  // Specifies whether or not the method parameter is lazy.
  Boolean isLazy = false;
}

/*
 * Under Development --> commited code needs Specs, Andrew and Miguel not happy!
 */
class ConstraintVariable{
  type;//NOT USED: One order of parsing list each type of Umple Variable (Including the Constrained Variable).
  value;
  1 -> 0..1 Constraint subConstraint;

  boolean isAttribute = {!"SYNTAX".equals(type)&&!"OPERATOR".equals(type)};
  boolean isOperator = {"OPERATOR".equals(type)};
  boolean isAssociation = false;
  Integer index = -1;
  boolean isPrimitive = true;
  boolean isStateMachine = false;
  boolean isState = false;
  boolean isNotPrimitive = { !isPrimitive };
  boolean isNumeric = {"integer".equals(type.toLowerCase())||
    "float".equals(type.toLowerCase())||
     "double".equals(type.toLowerCase())};
  UmpleVariable foundAttribute = null;
  State state = null;
  StateMachine stateMachine = null;
  
  attributeType = { (getFoundAttribute() == null) ? null : getFoundAttribute().getType() }

  key { value, subConstraint }

}

/*
 * The Constraint object related to Umple Classes
 */
class Constraint {
  depend cruise.umple.util.*;
  isA CodeBlock;
  
  format = "allParameterClosed";
  String inject = "";
  CodeTranslator gen = null;
  boolean negated = false;
  String code = { StringFormatter.format(getGen().translate((getNegated()?"Not":"")+getFormat(),this),getInject()) };
  ConstraintVariable[] expressions;  
}

/*
 * The Precondition object (special Constraint) related to Umple Classes
 */
class Precondition{  
  isA Constraint;
   * -> 1 Method ; // The method precondition belongs to
   
}

/*
 * The Postcondition object (special Constraint) related to Umple Classes
 */
class Postcondition{  
  isA Constraint;
   * -> 1 Method ; // The method postcondition belongs to
   lazy Position position;
}

/*
 * A block of code in an arbitrary language to be injected into generated code
 */
class CodeBlock
{
  depend java.util.*;

  internal HashMap<String,String> codes = new HashMap<String,String>();
  public static String languageUsed = "";
  lazy String name;
}

/*
 * A block of code that can be injected into one or more methods, constructor, etc.
 */
class CodeInjection
{
  depend cruise.umple.compiler.Position;
  depend cruise.umple.util.*;
  
  type;
  operation;
  CodeBlock snippet;
  * -> 1 UmpleClassifier;
  1 -> 0..1 Constraint;
  lazy Position position;
  Boolean isInternal = false;
}

class ExtraCode
{
 internal CodeBlock[] code;
}

/*
 *
 * A key in a class is a set of attributes associations used to uniquely identify an object
 */
class Key
{
  Boolean isDefault = false;
  String[] members;
}

/*
 * Represents an Umple classifier: a Class or Interface
 */
class UmpleClassifier
{
  isA UmpleElement;
  // The methods contained within the Umple Classifier.
  1 -> 0..* Method;

  * -> * Depend;  

  // The constants contained within the Umple Classifier.
  1 -> 0..* Constant;
  1 -> 0..* ModelConstraint;
  * -> 0..1 Token extendsToken;
}

/*
 * Represents a interface.
 * Like a class, but can't have any concrete methods, attributes or associations.
 */
class UmpleInterface
{
  isA UmpleClassifier;

  * -> 0..* UmpleInterface extendsInterface;


  before setPackageName { if (aPackageName == null) { return false; } }
  before addDepend { if (depends.contains(aDepend)) { return false; } }  
}

/*
 * An UmpleClass can contain attributes, associations, state machines and methods.
 * It can also have various other information such as a key (to identify uniqueness),
 * code to inject into generated code, and comments. It can be tagged with various
 * patterns, such as 'singleton', meaning that there can only be one instance,
 * and abstract, meaning it can't have any instances.
 */
class UmpleClass
{
  depend cruise.umple.util.*;

  isA UmpleClassifier;

  // Specifies whether or not the Umple class is an abstract class.
  Boolean isAbstract = false;

  // Specifies whether or not the Umple class is a singleton.
  Boolean isSingleton = false;

  Association[] associations;

  // List of candidate methods that were not added to the class
  Method[] unimplementedMethods;

  Key key = new Key();

  // Specifies whether or not the Umple class is immutable.
  internal Boolean iAmImmutable = false;
  internal Boolean ancestorIsImmutable = false;

  1 -> * CodeInjection;
  
  //The possible Preconditions related to the Umple Class
  1 -> 0..* Precondition;
  
  //The possible Preconditions related to the Umple Class
  1 -> 0..* Postcondition;

  // The possible Constraints related to the Umple Class
  1 -> 0..* Constraint;

  // The Umple Class's super class (if there is one).
  * subclasses -- 0..1 UmpleClass extendsClass;

  * subClasses -- * UmpleTrait extendsTraits;
  
  * subClasses -- * UmpleTemplate extendsTemplates;

  * -> 0..* UmpleInterface parentInterface;

  1 -> 0..1 UniqueIdentifier;

  // The attributes contained within the Umple class.
  1 -- * Attribute;

  // The associations contained within the Umple class.
  0..1 -- * AssociationVariable;

  // The comments associated with the Umple Class (such as the Javadoc above it).
  1 -> * Comment;
  
  UmpleModel sourceModel;

  //This is used to assign inheritance parameters.
  1 -> * GeneralTPApplied;	
  	
  before addDepend { if (depends.contains(aDepend)) { return false; } }  

  before setImmutable { if (!canBeImmutable()) { return false; } }

  before addAssociationVariable { if (!immutabilityAssociationRulesSatisfied(aAssociationVariable, this.isImmutable())) { return false; } }
  
  before setExtendsClass { if (!enforceImmutabilityInheritanceRules(aExtendsClass)) { return false; } }
  
  before addStateMachine { if (isImmutable()) { return false; } }
}



/*
 * An UmpleTrait can contain attributes, associations, state machines and methods.
 * It can also have various other information such as a key (to identify uniqueness),
 * code to inject into generated code, and comments. It can be tagged with various
 * patterns.
 */

class UmpleTrait {
  depend cruise.umple.util.*;

  isA UmpleClassifier;

  // Specifies whether or not the Umple class is an abstract class.
  Boolean isAbstract = false;
  
  // Specifies whether or not the Umple trait is a singleton.
  Boolean isSingleton = false;

  Association[] associations;

  // List of candidate methods that were not added to the Trait
  Method[] unimplementedMethods;

  Key key = new Key();

  // Specifies whether or not the Umple trait is immutable.
  internal Boolean iAmImmutable = false;
  internal Boolean ancestorIsImmutable = false;

  1 -> * CodeInjection;
  
  //The possible Preconditions related to the Umple Trait
  1 -> 0..* Precondition;
  
  //The possible Preconditions related to the Umple Trait
  1 -> 0..* Postcondition;

  // The possible Constraints related to the Umple Trait
  1 -> 0..* Constraint;
  
  // The Umple Trait's super Traits (if there are ones).
  * subTraits -- 0..* UmpleTrait extendsTraits;

  1 -> 0..1 UniqueIdentifier;

  // The attributes contained within the Umple trait.
  0..1 -- * Attribute;

  // The associations contained within the Umple trait.
  0..1 -- * AssociationVariable;

  // The comments associated with the Umple Trait (such as the Javadoc above it).
  1 -> * Comment;
  
  UmpleModel sourceModel;
  
  //The template parameters which are specified when traits are defined.
  1 -> * GeneralTemplateParameter;

  //This is used to assign inheritance parameters.
  1 -> * GeneralTPApplied;	
  
  //This is used to assign required interfaces
  1 -> * UmpleInterface requiredInterfaces;
  
  //--- before addDepend { if (depends.contains(aDepend)) { return false; } }  

  before setImmutable { if (!canBeImmutable()) { return false; } }

  //--- before addAssociationVariable { if (!immutabilityAssociationRulesSatisfied(aAssociationVariable, this.isImmutable())) { return false; } }
 
  before setExtendsTrait { if (!enforceImmutabilityInheritanceRules(aExtendsClass)) { return false; } }
  
  before addStateMachine { if (isImmutable()) { return false; } }
  
}

//This class is used to specify parameters for traits.
//TODO : when can also apply this to support formal template concepts for classes.
class GeneralTemplateParameter {
	name;
	type;
	String[] interfaces;
	defaultValue = "";

}

//This class is used to assign parameters in classes and traits.
class GeneralTPApplied {
	inheritanceName;
	String[] parameters;
	1 -> 0..1 Position positions;	
	1 -> * MethodTemplateSignature;
	
}

class MethodTemplateSignature{
	modifier;
	1 -> 1 Method;
	alias;
}

/*
 * A depend relationship indicates a package on which this class depends
 */
class Depend
{
  name;
  Boolean isInternal = false;

  key { name }
}

/* 
 * A combination of Class and Association (as defined in UML)
 * An AssociationClass is a full-fledged class, but at the same time
 * It associates two other classes that would otherwise have a many-many
 * relationship. Instances of the AssociationClass represent data 
 * held by the links between those two classes.
 */
class AssociationClass
{
  isA UmpleClass;
  1 -> 0..2 Association associatedTo;
}

/*
 * Superclass for tracking member variables in all target languages
 * TODO: Code smell because we have both an association variable and also an association
 * This class should go and instead AssociationEnd should be the member variable
 */
class UmpleVariable
{
  // The name of the Umple variable.
  name;

  // The type of the Umple variable.
  type;

  // The modifier associated with the Umple variable.
  modifier; // potential enum, 'settable'

  // The value of the Umple variable.
  value;
    
  before setName { if (aName == null) { throw new RuntimeException("Name must be set, cannot be null"); } }
  before getModifier { if (modifier == null) { return "settable"; } }

  class UniqueIdentifier { }  
}

/*
 * Represents an attribute.
 * An attribute is more abstract than an instance variable / property in that
 * it can be derived, and have various other modifiers such as being
 * initialized, lazy (does not appear in constructor and must be initialized
 * after construction), etc.
 */
class Attribute
{
  isA UmpleVariable;

  // Specifies whether or not the method parameter is auto unique.
  // TODO: should default to false, but constructors would need updating
  Boolean isAutounique; 

  // Specifies whether or not the attribute is unique.
  Boolean isUnique = false;

  // Specifies whether or not the method parameter is a list.
  Boolean isList = false;

  // Specifies whether or not the method parameter is derived.
  Boolean isDerived = false;
  
  CodeBlock codeblock = new CodeBlock();

  after constructor { codeblock.setCode(normalizeValue(aType,aValue)); }
  before setType { codeblock.setCode(normalizeValue(aType,getValue())); }

  // Specifies whether or not the method parameter is lazy.
  Boolean isLazy = false;
  Boolean isRefinement = false;

  // The comments associated with the attribute (such as the Javadoc above it).
  1 -> * Comment;
  
  // In case this attribute needs to have error handling preformed
  1 -> 0..1 Position;
  1 -> 0..1 Position endPosition;
}

/*
 * Represents an association, typically between two Umple classes (1-1, 1-*, *-1, etc).
 * An association in UML/Umple represents a relationship that exists at run time
 * where instances of one class reference the other, and (if bidirectional) instance
 * of the other class reference the first cass.
 * The number of references is governed by the Multiplicity at each AssociationEnd
 */
class Association
{
  // The name of the association.
  name = null;
  Boolean isLeftNavigable;
  Boolean isRightNavigable;
  Boolean isLeftComposition;
  Boolean isRightComposition;
  Coordinate[] positions;
  0..1 -- 2 AssociationEnd ends;
  Position tokenPosition = null;
  Position tokenEndPosition = null;
  internal Boolean immutable = false;
  Boolean named = { name != null && !"".equals(name) }

  before getName { if (!isNamed()) { return this.deriveName(); } }
  after constructor { this.setLeftAndRight(); }
}

/* 
 * An association end represents one logical end of an association
 * 
 * See also AssociationVariable
 * TODO: Code smell referenceToClassName is a duplication, can access via the association 
 * Create a derived attribute otherend (the other AssociationEnd)
 */
class AssociationEnd
{
  roleName;
  className;
  modifier; // potential enum 'internal'
  referenceToClassName;
  Multiplicity multiplicity;
  Boolean isDefaultRoleName = false;
  String priority = "";

  key { multiplicity, roleName, className, modifier, referenceToClassName }
  //modifier { Settable, Immutable, Internal, Defaulted, Constant }

  before getRoleName { if (roleName == null) { return ""; } }
  before getClassName { if (className == null) { return ""; } }
  before getModifier { if (modifier == null || "".equals(modifier)) { return "internal"; } }
  before getReferenceToClassName { if (referenceToClassName == null) { return ""; } }
}

/*
 * An association variable represents one of the variables used to represent
 * an association. In a two-directional association (navigable) there would
 * be one of these in each associated class.
 *
 * See also AssociationEnd
 *
 * TODO: Code smell. Should be replaced by the 'otherEnd' of the AssociationEnd
 */
class AssociationVariable
{
  isA UmpleVariable;
  Multiplicity multiplicity;
  immutable Boolean isNavigable;
  String priority = "";
  
  0..1 self relatedAssociation;

  // The comments associated with the association (such as the Javadoc above it).
  1 -> * Comment;

  before setUmpleClass { if ((aUmpleClass != null) && !aUmpleClass.immutabilityAssociationRulesSatisfied(this, aUmpleClass.isImmutable())) { return false; } }

  before setRelatedAssociation { if(!canBeRelatedAssociation(aNewRelatedAssociation)) { return false; }}
}

/*
 * A multplicity constrains the number of linked objects at one end of an
 * association
 *
 * TODO: extract derived attributes from Umple_Code.ump (getLowerBound etc.)
 */
class Multiplicity
{
  depend cruise.umple.util.*;

  lazy bound; // used when minimum=maximum; 
  lazy minimum;
  lazy maximum;

  parserable = { getBound() != null ? getBound() : getMinimum().equals("0") && getMaximum().equals("*") ? "*" : getMinimum() + ".." + getMaximum() }

  key { bound, minimum, maximum } 

}

// TODO: Code smell: This duplicates the structure of the class from UmpleClass
// This is a problem for model-to-model transformations
// Should be abolished
class GeneratedElement
{
  depend java.util.*;
}

/*
 * Represents a class that is generated from an Umple class, such as a Java or Cpp class.
 */
class GeneratedClass
{
  isA GeneratedElement;

  // Generated classes come from an Umple model (which comes from an Umple file), hence many generated classes to one model.
  * -> 1 UmpleModel model;

  // Generated classes are translated from an Umple class, hence the relation.
  0..1 -> 1 UmpleClass uClass;

  // Generated classes may have a parent class/super class.
  0..1 -> 0..1 GeneratedClass parentClass;
}

//class GeneratedInterface
//{
//  isA GeneratedElement;
//  //code = null;
//  * -> 1 UmpleModel model;
//  0..1 -> 1 UmpleInterface uInterface;
//}

/*
 * A point in cartesian coordinates, used in representing the layout of a
 * diagram in Umple
 */
class Point
{
  Integer x;
  Integer y;

  key { x, y }
}

/*
 * A Coordinate is used in  the layout of classes
 * It represents the shape of a class box in a diagram
 */
class Coordinate
{
  Integer x;
  Integer y;
  Integer width;
  Integer height;
  status {Explicit, Undefined, Defaulted}

  after constructor { updateStatus(); }
  after setX { if(wasSet) updateStatus(); }
  after setY { if(wasSet) updateStatus(); }
  after setWidth { if(wasSet) updateStatus(); }
  after setHeight { if(wasSet) updateStatus(); }

  key { x, y, width, height }
}

/*
 * Represents a comment, such as those found around classes, methods, attributes and associations.
 */
class Comment
{
  depend java.util.*;

  // The text associated with the comment.
  text;
}

class UmpleTemplate {
  depend cruise.umple.util.*;
  isA UmpleClass;
}

/*
 * Represents the generation target, such as what the generated output language will be.
 */
class GenerateTarget
{
  // The target language, such as Java, Cpp, Php or Ruby.
  language;

  path;

  Boolean override = false;
  Boolean overrideAll = false;
  lazy String[] suboptions;
  
  before getPath{if(path == null) path = ""; }
  key{language}
}

use UmpleVersion.ump;
use UmpleDiagram.ump;
use StateMachine.ump;
use Umple_Code.ump;
