/*
*  Example of Model to Text transformation using the 
*  "MOF Script" Language
*  UML 2 Java generation
*/

//import "uml_std.m2t"
access library aName "uml_std.m2t"
texttransformation UML2Java (in uml:"http://www.eclipse.org/uml2/1.0.0/UML") {

property package_name = "org.modelware"
property package_dir = "org/modelware/"
property ext = ".java"
property author = "MOFScript generator 'UML2Java'"

	uml.Model::main () {    
	  property a1="" 
	  self.ownedMember->forEach(p:uml.Package) {
	    p.mapPackage()
	  }
	}
  
  /*
  * mapPackage 
  */
  
	uml.Package::mapPackage ()  {
      var pName = self.getFullName()	  
	  log ("mapPackage:" + self.name)
	  self.ownedMember->forEach(c:uml.Class)
	  	c.mapClass(pName)
	
	  self.ownedMember->forEach(p:uml.Package) {
	    p.mapPackage()
	  }
	  
	  self.ownedMember->forEach(interface:uml.Interface) {
	    interface.interfaceMapping(pName)
	  }  
	}

  /* 
  * mapClass
  */
  
  uml.Class::mapClass(packageName:String) {  

    var pLocation = packageName.replace ("\\.", "/")    
    log ("stereotype in annotation:" + self.getStereotypeFromAnnotation())
    log ("real stereotype: " + self.getAppliedStereotypes())
//     stdout.println ("Class: " + self.name +  ", fullpackage: " + pName)
    file (package_dir + pLocation + "/" + self.name + ext)
    <%package %> package_name + "." + packageName <%;%>
    self.standardClassImport ()
    self.standardClassHeaderComment ()

    <%
public class %> self.name <% implements Serializable { %>
	<% 	
	/*
     * Attributes
    */
    %>
    <%   
    private String __id = null;
	%>
	self.ownedAttribute->forEach(p : uml.Property | p.association = null) {
		p.classPrivateAttribute()
	}
	nl(2)		
	self.ownedAttribute->forEach(p : uml.Property | p.association != null){
	    p.classPrivateAssociations()
	}
	nl(2)		
	self.classConstructor()
	nl(2)
	<%
    public String _getId() {
       return __id;
    }
    %>
	self.ownedAttribute->forEach(p : uml.Property | p.association = null)
		p.attributeGettersSetters()
	nl(2)	
	
	self.classAssociationMethods()	
	self.ownedAttribute->forEach(assoc : uml.Association) {	  	  
	}
	
	self.ownedOperation->forEach(op:uml.Operation) {
	  op.operationMapping();
	}

	<%
} // End of class %> self.name
  }
  
  /**
   * Mapping of interfaces
   */
  uml.Interface::interfaceMapping (packageName:String) {
    var pLocation = packageName.replace ("\\.", "/")    
    file (package_dir + pLocation + "/" + self.name + ext)
    <%
package %> package_name + "." +packageName <%;
    
public interface %> self.name <% {%>
    self.ownedOperation->forEach(op:uml.Operation) {
      <%\n\tpublic %> 
      if (op.returnResult.isEmpty())
        'void'
      else 
        '' + op.returnResult.first().type.name
        
      <% %> self.name <% (%>
      op.ownedParameter->forEach(param:uml.Parameter) {
        '' + param.type.name + ' ' + param.name 
        if (param != op.ownedParameter.last() && op.ownedParameter.size() > 1)
        	', '
      }
      ');'
    }
    <%
}
    %>
  }


	/**
	 * Returns a full package name on the form p1.p2.p3
	 * Replaces occurrences of ' ' with '_'
	 */
	uml.Package::getFullName (): String {
	  if (self.owner != null)
	    result = self.owner.getFullName() + "."
	//  else if (self.ownerPackage != null)
	//    result = self.ownerPackage.getFullName() + "."
	
	  result += self.name.toLower().replace(" ", "_");  
	}


	//
	// class Contructor
	//
	uml.Class::classConstructor() {
	  <% 
	  // Default constructor
	  public %> self.name <% () {
	      __id = String.valueOf(Math.random() * Math.random() * Calendar.getInstance().getTimeInMillis());
	    %>    
		self.ownedAttribute->forEach(p : uml.Property | p.association != null){
		  <%\n      %>p.propertyPrivateName() <% = new Hashtable (); %>
		}
		<%
	  }%>
	  newline
	}
 
  //
  // classPrivateAttribute
  //
  uml.Property::classPrivateAttribute () {
    <% 
    private %> self.type.name <% %> self.propertyPrivateName() <% ; %>
  }
  
  // classPrivateAssociations
  uml.Property::classPrivateAssociations () {
    println ("    private Hashtable " + self.propertyPrivateName() + ";")
  }
  
  // attributeGetterSetters
  uml.Property::attributeGettersSetters () {
    <%
    public %> self.type.name <% get%> self.name.firstToUpper() <% () {
        return %> self.propertyPrivateName() <%;
    }

    public void set%> self.name.firstToUpper() <%(%> self.type.name <% __input ) {
        %> self.propertyPrivateName()  <% = __input;
    }
	%>    
  }
  
  
  /*
  * Class Association Implementation
  */
  uml.Class::classAssociationMethods ()  {
	self.ownedAttribute->forEach(p : uml.Property | p.association <> null) {
	  p.associationAddMethod()
	  p.associationRemoveMethod()
	 }
   }
   /*
    * Add Method for Association
    */
   uml.Property::associationAddMethod ()  {
	  <%    public void add%> self.type.name <% ( %> self.type.name <% obj) {
          %> self.propertyPrivateName() <%.put(obj._getId(), obj);
      }%>     
      newline(2)
   }
   /*
   * Association Remove
   */
   uml.Property::associationRemoveMethod () {
	  <%    public void remove%> self.type.name <% ( String id) {
          %> self.propertyPrivateName() <%.remove(id);
      }%>     
      newline(2)     
   }
   
   /*
    * Association get
    */
    uml.Property::associationGetMethod () {
	  <%    public %> self.type.name <% get%> self.type.name <% ( String id ) {
              return %> self.propertyPrivateName() <%.get(id);
      }%>     
      newline(2)           
    }
    
   /*
    * Association get all
    */
    uml.Property::associationGetAllMethod () {
	  <%    public Collection get%> self.type.name <% ( ) {
              return %> self.propertyPrivateName() <%.values();
      }%>     
      newline(2)           
    }           
    
   /*
    * Association create
    */
    uml.Property::associationCreateMethod () {
	  <%    public %> self.type.name <% create%> self.type.name <% () {
              %> self.type.name <% newObject = new %> self.type.name <% ();
              return newObject;
      }%>     
      newline(2)           
    }
    
   /*
    * Association update
    */
    uml.Property::associationUpdateMethod () {
	  <%    public void update%> self.type.name <% (%> self.type.name <% obj) {
               %> self.propertyPrivateName() <%.remove(obj._getId()); 
               %> self.propertyPrivateName() <%.put(obj._getId(), obj); 
      }%>     
      newline(2)           
    }    

   /**
    * Private properties
    */   
   uml.Property::propertyPrivateName () : String {
     result = "_" + self.name.toLower()
   }
   
   /**
    * Plural property names
    */
   uml.Property::propertyPluralName () : String {
     var pName = self.type.name.toLower();
     if (pName.endsWith("s"))
        result = pName + "es";
     else if (pName.endsWith("y"))
        result = pName.substring(0, pName.size() - 1) + "ies"
     else
        result = pName + "s";
   }

  // standardClassImport  
  uml.Class::standardClassImport ()  {
    <%
import java.util.Vector;
import java.util.Hashtable;
import java.io.Serializable;
	%>
  }
  
  // standardClassHeaderComment
  uml.Class::standardClassHeaderComment ()  {
    <%
/**
 *
 *  Generated class %> self.name <%
 *  @author %> <%
 *  @date %> date () <%
 */
	%>
  }
  
  /**
   * Gets the owner package
   */  
  uml.PackageableElement::getOwnerPackage ():Object { 
//    if (self.ownerPackage != null)
//      result=self.ownerPackage
//    else 
      result=self.owner
  }
  
  /**
   * Operation mapping
   */
  uml.Operation::operationImplMapping () {
    stdout.println ("Operation " + self.name)
    <%
    	// Operation %> self.name <%
    %>
  }
  
  
  uml.Operation::operationInterfaceMapping () {
    stdout.println ("Operation: " + self.name)
    <% 
    	// operation %> self.name <%
    %>
   }
   
}