import com.sun.javadoc.*;
import java.util.Vector;

// v1.1 (19/07/99)
/**
<br>
Classe principale che contiene il metodo start, scrive su stdout il codice Xmi<br>
<br>
*/

public class JavaToXmiuml extends Doclet
{
/**
<br>
Memorizza le classi passate a Javadoc<br>
<br>
*/
  static ClassDoc[] classes;
/**
<br>
Memorizza i campi della classe che la doclet sta esaminando.<br>
<br>
*/
  static FieldDoc[] fields;
/**
<br>
Memorizza i metodi della classe che la doclet sta esaminando.<br>
<br>
*/
  static MethodDoc[] methods;
/**
<br>
Memorizza i costruttori della classe che la doclet sta esaminando.<br>
<br>
*/
  static ConstructorDoc[] constructors;
/**
<br>
Memorizza gli eventuali tag di un campo (viene considerato comunque solo
l'eventuale tag @explicit_association)<br>
<br>
*/
  static Tag[] tags;
/**
<br>
Memorizza i parametri di un metodo.<br>
<br>
*/
  static Parameter[] parameters;
/**
<br>
Vettore che memorizza istanze della classe ReturnCheckType, un'istanza per
ogni tipo di dato (primitivo o no) utilizzato.<br>
Il vettore usedType viene riempito progressivamente durante l'esecuzione del
doclet e utilizzato alla fine per creare le sezioni dataType.<br>
<br>
*/
  static Vector usedType;
/**
<br>
Vettore che memorizza tutte le classi che non sono foglia (ovvero che sono<br>
superclassi di un'altra classe).<br>
<br>
*/
  static Vector nonLeafClass;
/**
<br>
Variabile utilizzata per indentare l'output Xmi.<br>
<br>
*/
  static int indentlevel;
  static final String exporter = "Elmut";
  static final String exporterversion = "0.0.1";
//tell how many association there are
/**
<br>
Variabile ausiliaria.<br>
<br>
*/
  static int posAss;
//tell wich association there are
/**
<br>
Memorizza la classe associata con la classe correntemente esaminata.<br>
<br>
*/
  static FieldDoc[] assocFields;

/**
<br>
start()<br>
apre xmi<br>
scrive sezione xmi.header<br>
apre xmi.content<br>
Write_Model() -- scrive UML model<br>
Write_Datatypes() - scrive classi esterne e tipi di dati primitivi<br>
chiude xmi.content<br>
chiude xmi<br>
<br>
*/

  public static boolean start(RootDoc root)
  {
    indentlevel=0;
    classes = root.classes();
    usedType = new Vector();
    nonLeafClass = new Vector();

//fill in nonLeafClass vector
    fillLeafClass();

//open document
    Writeln("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>");
    Writeln("<!DOCTYPE XMI SYSTEM \"UML.dtd\">");
    Writeln("");
    Open_Level("<XMI>");
    Writeln("");
    Open_Level("<XMI.header>");
    Open_Level("<XMI.documentation>");
    Writeln("<XMI.exporter>" + exporter + "</XMI.exporter>");
    Writeln("<XMI.exporterVersion>" + exporterversion + "</XMI.exporterVersion>");
    Close_Level("</XMI.documentation>");
    Writeln("<XMI.metamodel xmi.name=\"uml\" xmi.version=\"1.1\"/>");
    Close_Level("</XMI.header>");
    Writeln("");
    Open_Level("<XMI.content>");

// write UML model
    Write_Model();

// write data types
    Write_DataTypes();

// close document
    Close_Level("</XMI.content>");
    Writeln("");
    Close_Level("</XMI>");

    return true;
  } //end of start method

/*
   Usage: Write_Model()
   Description: print the UML model
*/
/**
<br>
Write_Model()<br>
{<br>
apre UML model<br>
foreach(class)<br>
{<br>
Write_Class()<br>
foreach(explicit_association) Write_Association()<br>
if (isInternal(superclass)) Write_SuperClass()<br>
foreach(interface implementata) Write_Implements()<br>
}<br>
chiude UML model<br>
}<br><br>
*/

  static void Write_Model()
  {
// open model
    Remark("<!-- The UML Model begins -->");
    Open_Level("<Model_Management.Model xmi.id=\"idModel\">");
    Writeln("<Foundation.Core.ModelElement.name></Foundation.Core.ModelElement.name>");
    Writeln("<Foundation.Core.ModelElement.visibility xmi.value=\"public\"/>");
    Writeln("<Foundation.Core.GeneralizableElement.isRoot xmi.value=\"true\"/>");
    Writeln("<Foundation.Core.GeneralizableElement.isLeaf xmi.value=\"true\"/>");
    Writeln("<Foundation.Core.GeneralizableElement.isAbstract xmi.value=\"false\"/>");

// classes...
    Remark("");
    for (int i = 0; i < classes.length; ++i)
    {
      ClassDoc superClass = classes[i].superclass();
      ClassDoc[] interFaces = classes[i].interfaces();
      boolean isInterFace = classes[i].isInterface() ? true : false;

      Open_Level("<Foundation.Core.Namespace.ownedElement>");
      Write_Class(classes[i],false);
      Close_Level("</Foundation.Core.Namespace.ownedElement>");
      Remark("");

//association
      for (int curAss = 0 ; curAss < posAss ; curAss++)
      {
//if assocFields != primitive Type then write association
        if (assocFields[curAss].type().asClassDoc() != null)
        {
          Open_Level("<Foundation.Core.Namespace.ownedElement>");
          Write_Association(classes[i], assocFields[curAss]);
          Close_Level("</Foundation.Core.Namespace.ownedElement>");
          Remark("");
        }
      }

// generalizations
      if (!isInterFace && isInternal(superClass))
      {
        Open_Level("<Foundation.Core.Namespace.ownedElement>");
        Write_SuperClass(classes[i]);
        Close_Level("</Foundation.Core.Namespace.ownedElement>");
        Remark("");
      }
      for (int n = 0 ; n < interFaces.length ; n++)
       if (isInternal(interFaces[n]))
      {
        Open_Level("<Foundation.Core.Namespace.ownedElement>");
        Write_Implements(classes[i], interFaces[n]);
        Close_Level("</Foundation.Core.Namespace.ownedElement>");
        Remark("");
      }
    }

// close model
    Close_Level("</Model_Management.Model>");
    Remark("");
  }

/*
   Usage: Write_DataTypes()
   Description: print the data types
*/
/**
<br>
Write_Datatypes()<br>
{<br>
foreach(usedtype)<br>
{<br>
if (isPrimitive) Write_DataType()<br>
else Write_Class()<br>
}<br>
}<br><br>
*/
  static void Write_DataTypes()
  {
    returnCheckType currElement;

// open datatypes section
    Remark("<!-- DataTypes definition -->");

// datatypes...
// we're going to empty the usedType vector
    while (!(usedType.isEmpty()))
    {
      try
      { currElement = (returnCheckType) usedType.firstElement(); }
//unuseful caught, avoid propagating the 'throws' clause
      catch (java.util.NoSuchElementException e) { break; }
      usedType.removeElement(currElement);

      // primitive datatype or class/interface?
      if (currElement.isPrimitive) Write_DataType(currElement);
      else Write_Class(currElement.returnClass, true);
    }
  }

// -------------------
// HIGH LEVEL ROUTINES
// -------------------

/*
   Usage: Write_DataType(returnCheckType dataName)
   Description: print a single data type
*/
/**
<br>
Write_Datatype()<br>
{<br>
apre, descrive e chiuse un tipo primitivo<br>
}<br><br>
*/

  static void Write_DataType(returnCheckType dataName)
  {
// open
    Remark("<!-- " + dataName.returnType + " -->");
    Open_Level("<Foundation.Core.DataType xmi.id=\"" +
               getDatatypeId(dataName) +
               "\">");
// !? class name
    Writeln("<Foundation.Core.ModelElement.name>"+
            dataName.returnType +
            "</Foundation.Core.ModelElement.name>");
// class visibility
      Writeln("<Foundation.Core.ModelElement.visibility xmi.value=\"public\"/>");
// class is Root? (sempre false)
      Writeln("<Foundation.Core.GeneralizableElement.isRoot xmi.value=\"true\"/>");
// class is leaf?
      Writeln("<Foundation.Core.GeneralizableElement.isLeaf xmi.value=\"true\"/>");
// abstract class
      Writeln("<Foundation.Core.GeneralizableElement.isAbstract xmi.value=\"false\"/>");
// close
    Close_Level("</Foundation.Core.DataType>");
  }

/*
   Usage: Write_Class(ClassDoc curClass, boolean isaRef)
   Description: print to stdout all information about this class/interface
*/
/**
<br>
Write_Class()<br>
{<br>
apre e descrive una classe<br>
if (isInternal(classe)) Write_Features()<br>
chiude classe<br>
}<br><br>
*/
  static void Write_Class(ClassDoc curClass, boolean isaRef)
  {
    boolean isInterFace = curClass.isInterface() ? true : false;

// open
    if (isInterFace)
    {
      Remark("<!-- Interface \"" + curClass.typeName() + "\" -->");
      Open_Level("<Foundation.Core.Interface xmi.id=\"" + getClassId(curClass) + "\">");
    }
    else
    {
      Remark("<!-- Class \"" + curClass.typeName() + "\" -->");
      Open_Level("<Foundation.Core.Class xmi.id=\"" + getClassId(curClass) + "\">");
    }
// class name
    Writeln("<Foundation.Core.ModelElement.name>" +
            curClass.typeName() +
            "</Foundation.Core.ModelElement.name>");
// !! class visibility
    String visibility = "public";
    if (curClass.isPublic()) visibility = "public";
    if (curClass.isProtected()) visibility = "protected";
    if (curClass.isPrivate()) visibility = "private";
    Writeln("<Foundation.Core.ModelElement.visibility xmi.value=\"" +
            visibility +
            "\"/>");
// class is Root? (sempre false)
    Writeln("<Foundation.Core.GeneralizableElement.isRoot xmi.value=\"false\"/>");
// !! class is leaf?
    Writeln("<Foundation.Core.GeneralizableElement.isLeaf xmi.value=\"" +
            (isLeaf(curClass) ? "true" : "false") +
            "\"/>");
// abstract class
    Writeln("<Foundation.Core.GeneralizableElement.isAbstract xmi.value=\"" +
            (curClass.isAbstract() ? "true" : "false") +
            "\"/>");
// !? class is Active: cosa significa? (sempre false)
    if (!isInterFace)
    {
      boolean isActive = false;
      ClassDoc[] interfaces = curClass.interfaces();
      ClassDoc superClass = curClass.superclass();
      if (superClass.qualifiedTypeName().equals("java.lang.Thread")) isActive = true; 
      else
      {
	for (int y = 0 ; y < interfaces.length ; y++)
	{
		if (interfaces[y].qualifiedTypeName().equals("java.lang.Runnable"))
isActive = true;
	}
      }
      Writeln("<Foundation.Core.Class.isActive xmi.value=\"" + isActive + "\"/>");
    }

// solo se non è un riferimento, scrivi (eventualmente) le features
    if (!isaRef) Write_Features(curClass);

// close
    if (isInterFace) Close_Level("</Foundation.Core.Interface>");
    else Close_Level("</Foundation.Core.Class>");

  }

/*
   Usage: Write_Features(ClassDoc curClass)
   Description: print the class features
*/
/**
<br>
Write_Features()<br>
{<br>
apre sezione delle features<br>
foreach(field) Write_Attribute()<br>
foreach(constructor) Write_Constructor()<br>
foreach(method) Write_Method()<br>
chiude features<br>
<br>
}
*/
  static void Write_Features(ClassDoc curClass)
  {
    fields = curClass.fields();
    constructors = curClass.constructors();
    methods = curClass.methods();

    if (fields.length > 0 || methods.length > 0)
    {
// open features
      Remark("<!-- \"" + curClass.qualifiedTypeName() + "\" features -->");
      Open_Level("<Foundation.Core.Classifier.feature>");

// fields...
      posAss = 0;
      if (fields.length != 0) assocFields = new FieldDoc[fields.length];
      for (int j = 0 ; j < fields.length; j++)
      {
        Tag myTag[] = fields[j].tags("explicit_association");
        if (myTag.length != 0)
        {
          assocFields[posAss] = fields[j];
          posAss++;
        }
        Write_Attribute(curClass, fields[j]);
      }

// constructors...
      if (constructors.length == 1) // if there isn't overloading
      {
        Write_Constructor(curClass, constructors[0], "");
      }
      else for (int j = 0 ; j < constructors.length ; j++)
      {
        Write_Constructor(curClass, constructors[j], Integer.toString(j+1));
      }

// methods...
      for (int j = 0 ; j < methods.length ; j++)
      {
        if (methods[j] != null)
        {
          int[] position = allPosition(methods[j]);
          if (position[0] == 1) // se non c'è overloading
          {
            Write_Operation(curClass, methods[j], "");
            methods[j] = null;
          }
          else
          {
            for (int h = 1 ; h < position[0] + 1; h++)
            {
              Write_Operation(curClass, methods[position[h]], Integer.toString(h+1));
              methods[position[h]] = null;
            }
          } //end of if (position...
        } //end of if (methods[j] != null)
      } //end of foreach method...

// close features
      Close_Level("</Foundation.Core.Classifier.feature>");
    }
  }

/*
   Usage: Write_SuperClass(ClassDoc)
   Description: print the superclass generalization
*/
/**
<br>
Write_SuperClass()<br>
{<br>
apre, descrive e chiude la generalizzazione della superclass<br>
}<br><br>
*/

  static void Write_SuperClass(ClassDoc curClass)
  {
    ClassDoc superClass = curClass.superclass();

// open
    Remark("<!-- The generalization between '" + curClass.typeName() +
           "' and '" + superClass.typeName() + "' -->");
    Open_Level("<Foundation.Core.Generalization xmi.id=\"" +
               getGeneralizationId(curClass) +
               "\">");

// !! name: empty
    Writeln("<Foundation.Core.ModelElement.name/>");
// !! visibility: public
    Writeln("<Foundation.Core.ModelElement.visibility xmi.value=\"public\"/>");
// !! discriminator: empty
    Writeln("<Foundation.Core.Generalization.discriminator/>");
// subtype: type of the child class
    Open_Level("<Foundation.Core.Generalization.subtype>");
    Writeln("<Foundation.Core.Class xmi.idref=\"" +
            getClassId(curClass) +
            "\"/>");
    Close_Level("</Foundation.Core.Generalization.subtype>");
// supertype: type of the parent class
    Open_Level("<Foundation.Core.Generalization.supertype>");
    Writeln("<Foundation.Core.Class xmi.idref=\"" +
            getClassId(superClass) +
            "\"/>");
    Close_Level("</Foundation.Core.Generalization.supertype>");
// close
    Close_Level("</Foundation.Core.Generalization>");
  }

/*
   Usage: Write_Implements(ClassDoc curClass, ClassDoc curInterf)
   return,modify: nothing
   Description: print the generalization relative to an interface
*/

/**
<br>
Write_Implements()<br>
{<br>
apre, descrive e chiude la generalizzazione di un'interfaccia implementata<br>
}<br><br>
*/

  static void Write_Implements(ClassDoc curClass, ClassDoc curInterf)
  {
// open
    Remark("<!-- The generalization between '" + curClass.typeName() +
           "' and '" + curInterf.typeName() + "' -->");
    Open_Level("<Foundation.Core.Generalization xmi.id=\"" +
               getGeneralizeInterfaceId(curClass, curInterf) +
               "\">");

// name: empty
    Writeln("<Foundation.Core.ModelElement.name/>");
// visibility: public
    Writeln("<Foundation.Core.ModelElement.visibility xmi.value=\"public\"/>");
// discriminator: empty
    Writeln("<Foundation.Core.Generalization.discriminator/>");
// subtype: type of the child class
    Open_Level("<Foundation.Core.Generalization.subtype>");
    Writeln("<Foundation.Core.Class xmi.idref=\"" +
            getClassId(curClass) +
            "\"/>");
    Close_Level("</Foundation.Core.Generalization.subtype>");
// supertype: type of the parent class
    Open_Level("<Foundation.Core.Generalization.supertype>");
    Writeln("<Foundation.Core.Class xmi.idref=\"" +
            getClassId(curInterf) +
            "\"/>");
    Close_Level("</Foundation.Core.Generalization.supertype>");
// close
    Close_Level("</Foundation.Core.Generalization>");
  }

/*
   Usage: Write_Association(ClassDoc curClass, FieldDoc curField)
   Description: print the generalization relative to an interface
*/
/**
<br>
Write_Association()<br>
{<br>
apre e descrive una association<br>
scrive la prima AssociationEnd<br>
scrive la seconda AssociationEnd<br>
chiude la association<br>
}<br><br>
*/

  static void Write_Association(ClassDoc curClass, FieldDoc curField)
  {
    ClassDoc assocClass = curField.type().asClassDoc();

// open
    Remark("<!-- The association between '" + curClass.typeName() +
           "' and '" + assocClass.typeName() + "' -->");
    Open_Level("<Foundation.Core.Association xmi.id=\"" +
               getAssociationId(curClass, assocClass) +
               "\">");

// name
    Writeln("<Foundation.Core.ModelElement.name>" +
            curClass.typeName() + "-" + assocClass.typeName() + "Association" +
            "</Foundation.Core.ModelElement.name>");
// visibility: public
    Writeln("<Foundation.Core.ModelElement.visibility xmi.value=\"public\"/>");
// isRoot, isLeaf, isAbstract
    Writeln("<Foundation.Core.GeneralizableElement.isRoot xmi.value=\"false\"/>");
    Writeln("<Foundation.Core.GeneralizableElement.isLeaf xmi.value=\"false\"/>");
    Writeln("<Foundation.Core.GeneralizableElement.isAbstract xmi.value=\"false\"/>");

// first connection: begin
    Open_Level("<Foundation.Core.Association.connection>");
    Open_Level("<Foundation.Core.AssociationEnd xmi.id=\"" +
               getAssociationStartId(curClass, assocClass) +
               "\">");
// name: empty
    Writeln("<Foundation.Core.ModelElement.name/>");
// visibility: private
    Writeln("<Foundation.Core.ModelElement.visibility xmi.value=\"private\"/>");
// isNavigable: in the AssociationEnd start it must always be "false"
    Writeln("<Foundation.Core.AssociationEnd.isNavigable xmi.value=\"false\"/>");
// isOrdered: in the AssociationEnd start it must always be "false"
    Writeln("<Foundation.Core.AssociationEnd.isOrdered xmi.value=\"false\"/>");
// aggregation (none | aggregate | composite): this is a composition
    Writeln("<Foundation.Core.AssociationEnd.aggregation xmi.value=\"composite\"/>");
// multiplicity: always 1
    Writeln("<Foundation.Core.AssociationEnd.multiplicity>1</Foundation.Core.AssociationEnd.multiplicity>");
// ?? changeable: always none
    Writeln("<Foundation.Core.AssociationEnd.changeable xmi.value=\"none\"/>");
// ?? targetScope: always instance
    Writeln("<Foundation.Core.AssociationEnd.targetScope xmi.value=\"instance\"/>");
// type of role A
    Open_Level("<Foundation.Core.AssociationEnd.type>");
    Writeln("<Foundation.Core.Class xmi.idref=\"" +
            getClassId(curClass) +
            "\"/>");
    Close_Level("</Foundation.Core.AssociationEnd.type>");
// first connection: end
    Close_Level("</Foundation.Core.AssociationEnd>");
    Close_Level("</Foundation.Core.Association.connection>");

// second connection: begin
    Open_Level("<Foundation.Core.Association.connection>");
    Open_Level("<Foundation.Core.AssociationEnd xmi.id=\"" +
               getAssociationEndId(curClass, assocClass) +
               "\">");
// name: empty
    Writeln("<Foundation.Core.ModelElement.name/>");
// visibility: source field visibility
    String visibility = "public";
    if (curField.isPublic()) visibility = "public";
    if (curField.isProtected()) visibility = "protected";
    if (curField.isPrivate()) visibility = "private";
    Writeln("<Foundation.Core.ModelElement.visibility xmi.value=\"" +
            visibility +
            "\"/>");
// isNavigable (association direction): always true
    Writeln("<Foundation.Core.AssociationEnd.isNavigable xmi.value=\"true\"/>");
// !? isOrdered: always false
    Writeln("<Foundation.Core.AssociationEnd.isOrdered xmi.value=\"false\"/>");
// aggregation: in the AssociationEnd start it must always be "none"
    Writeln("<Foundation.Core.AssociationEnd.aggregation xmi.value=\"none\"/>");
// multiplicity: source field multiplicity
    Writeln("<Foundation.Core.AssociationEnd.multiplicity>" +
            umlMult(curField.type().dimension()) +
            "</Foundation.Core.AssociationEnd.multiplicity>");
// ?? changeable: always none
    Writeln("<Foundation.Core.AssociationEnd.changeable xmi.value=\"none\"/>");
// ?? targetScope: always instance
    Writeln("<Foundation.Core.AssociationEnd.targetScope xmi.value=\"instance\"/>");
// type of role B
    Open_Level("<Foundation.Core.AssociationEnd.type>");
    Writeln("<Foundation.Core.Class xmi.idref=\"" +
            getClassId(assocClass) +
            "\"/>");
    Close_Level("</Foundation.Core.AssociationEnd.type>");
// second connection: end
    Close_Level("</Foundation.Core.AssociationEnd>");
    Close_Level("</Foundation.Core.Association.connection>");

// close
    Close_Level("</Foundation.Core.Association>");
  }

/*
   Usage: Write_Attribute(ClassDoc, FieldDoc)
   return: nothing
   modify: usedType
   Description: print to stdout all information about a class field
*/
/**<br>
Write_Attribute()<br>
{<br>
apre, descrive e chiude un attributo<br>
}<br><br>
*/

static void Write_Attribute(ClassDoc curClass, FieldDoc curField)
{
  Type curType = curField.type(); // field type
  returnCheckType rCheckType = checkType(curType);

// open
  Remark("<!-- Attribute \"" + curField.name() + "\" begin -->");
  Open_Level("<Foundation.Core.Attribute xmi.id=\"" +
             getFieldId(curClass,curField) +
             "\">");
// name
  Writeln("<Foundation.Core.ModelElement.name>" +
          curField.name() +
          "</Foundation.Core.ModelElement.name>");
// !! visibility: PackagePrivate <-- "Public"
  String visibility = "Public";
  if (curField.isPublic()) visibility = "Public";
  if (curField.isProtected()) visibility = "Protected";
  if (curField.isPrivate()) visibility = "Private";
  Writeln("<Foundation.Core.ModelElement.visibility xmi.value=\"" +
          visibility +
          "\"/>");
// !! ownerScope: (instance | classifier) - se è globale per il classifier
  Writeln("<Foundation.Core.Feature.ownerScope xmi.value=\"" +
          (curField.isStatic() ? "classifier" : "instance") +
          "\"/>");
// ?? multiplicity: con un vettore a[7][5]: 0..7,0..5 oppure *,*
// per il momento è 1 o *
  Writeln("<Foundation.Core.StructuralFeature.multiplicity>" +
          umlMult(rCheckType.returnTypeDimension) +
          "</Foundation.Core.StructuralFeature.multiplicity>");
// !? changeable: none per le variabili, frozen per le costanti
  Writeln("<Foundation.Core.StructuralFeature.changeable xmi.value=\"" +
          (curField.isFinal() ? "frozen" : "none") +
          "\"/>");
// !? targetScope: cosa diavolo e'? - il mistero resta
  Writeln("<Foundation.Core.StructuralFeature.targetScope xmi.value=\"instance\"/>");
// !? initialValue: lasciarlo vuoto (in javadoc non si puo' prendere)
  Open_Level("<Foundation.Core.Attribute.initialValue>");
  Open_Level("<Foundation.Data_Types.Expression>");
  Writeln("<Foundation.Data_Types.Expression.language>Java</Foundation.Data_Types.Expression.language>");
  Writeln("<Foundation.Data_Types.Expression.body></Foundation.Data_Types.Expression.body>");
  Close_Level("</Foundation.Data_Types.Expression>");
  Close_Level("</Foundation.Core.Attribute.initialValue>");
// owner
  Open_Level("<Foundation.Core.Feature.owner>");
  Writeln("<Foundation.Core.Class xmi.idref=\"" +
          getClassId(curClass) +
          "\"/>");
  Close_Level("</Foundation.Core.Feature.owner>");
// ?? field type: datatype or class
  Open_Level("<Foundation.Core.StructuralFeature.type>");
  Writeln("<Foundation.Core.DataType xmi.idref=\"" +
          getDatatypeId(rCheckType) +
// ??       (rCheckType.isPrimitive ? getDatatypeId(rCheckType) : getClassId(curClass)) +
          "\"/>");
// ??      else Write_Class(currElement.returnClass, true);

  Close_Level("</Foundation.Core.StructuralFeature.type>");
// close
  Close_Level("</Foundation.Core.Attribute>");
  Remark("<!-- Attribute \"" +
         curField.name() +
         "\" end -->");
  Writeln("");
}

/*
   Usage: Write_Operation(ClassDoc, MethodDoc, String)
   return: nothing
   modify: usedType
   Description: print to stdout all information about this method
*/
/**
<br>
Write_Operation()<br>
{<br>
apre e descrive un'operazione<br>
foreach(parameter) Write_Parameter()<br>
Write_ReturnParameter()<br>
chiude l'operazione<br>
}<br><br>
*/
  static void Write_Operation(ClassDoc curClass, MethodDoc curMet, String progressive)
  {
// open
    Remark("<!-- Operation \"" +
           curMet.name() + progressive +
           "\" begin -->");
    Open_Level("<Foundation.Core.Operation xmi.id=\"" +
            getOperationId(curClass, curMet, progressive) +
          "\">");
// name
    Writeln("<Foundation.Core.ModelElement.name>" +
            curMet.name() + progressive +
            "</Foundation.Core.ModelElement.name>");
// method visibility
    String visibility = "Public";
          if (curMet.isPublic()) visibility = "Public";
          if (curMet.isProtected()) visibility = "Protected";
          if (curMet.isPrivate()) visibility = "Private";
    Writeln("<Foundation.Core.ModelElement.visibility xmi.value=\"" +
            visibility +
            "\"/>");
// !? ownerScope: (instance | classifier) - un metodo è sempre globale
    Writeln("<Foundation.Core.Feature.ownerScope xmi.value=\"classifier\"/>");
// !? isQuery: is this method a function?
    Type returnType = curMet.returnType();
    if (returnType.typeName().equals("void")) {
        Writeln("<Foundation.Core.BehavioralFeature.isQuery xmi.value=\"" +
            "false" +
            "\"/>");
    } else {
        Writeln("<Foundation.Core.BehavioralFeature.isQuery xmi.value=\"" +
            "true" +
            "\"/>");
    }
// !? specification: empty (it should be contain the body?)
    Open_Level("<Foundation.Core.Operation.specification>");
    Close_Level("</Foundation.Core.Operation.specification>");
// isPolymorphic: is there overloading?
    Writeln("<Foundation.Core.Operation.isPolymorphic xmi.value=\"" +
            (progressive.equals("") ? "true" : "false") +
            "\"/>");
// concurrency: (sequential | guarded | concurrent )
    Writeln("<Foundation.Core.Operation.concurrency xmi.value=\"" +
            (curMet.isSynchronized() ? "guarded" : "sequential") +
            "\"/>");
// abstract method
    Open_Level("<XMI.extension xmi.extender=\"" +
               exporter +
               "\" xmi.extenderID=\"" +
               exporterversion +
               "\">");
    Writeln("<Foundation.Core.GeneralizableElement.isAbstract xmi.value=\"" +
            (curMet.isAbstract() ? "true" : "false") +
            "\"/>");
    Close_Level("</XMI.extension>");
// owner
    Open_Level("<Foundation.Core.Feature.owner>");
    Writeln("<Foundation.Core.Class xmi.idref=\"" +
            getClassId(curClass) +
            "\"/>");
    Close_Level("</Foundation.Core.Feature.owner>");
// begin parameters
      Remark("<!-- \"" + curMet.name() + "\" parameters begin -->");
    Open_Level("<Foundation.Core.BehavioralFeature.parameter>");

// return parameter
    Write_ReturnParameter(curClass, curMet, progressive);

// parameters loop
    parameters = curMet.parameters();
    for (int k = 0 ; k < parameters.length ; k++)
    {
      Write_Parameter(curClass, curMet, progressive, parameters[k]);
    }

// end of parameters
    Close_Level("</Foundation.Core.BehavioralFeature.parameter>");
    Remark("<!-- \"" + curMet.name() + "\" parameters end -->");
// close
    Close_Level("</Foundation.Core.Operation>");
    Remark("<!-- Operation \"" + curMet.name() + progressive + "\" end -->");
    Writeln("");
}

/*
   Usage: Write_Constructor(ClassDoc, ConstructorDoc, String)
   return: nothing
   modify: usedType
   Description: print to stdout all information about this constructor
*/
/**
<br>
Write_Constructor()<br>
{<br>
apre e descrive un costruttore<br>
foreach(parameter) Write_Parameter()<br>
chiude il costruttore<br>
}<br><br>
*/
  static void Write_Constructor(ClassDoc curClass, ConstructorDoc curCon, String progressive)
  {
// open
    Remark("<!-- Constructor \"" +
           curCon.qualifiedName() + progressive +
           "\" begin -->");
    Open_Level("<Foundation.Core.Operation xmi.id=\"" +
            getConstructorId(curClass, curCon, progressive) +
          "\">");
// name
    Writeln("<Foundation.Core.ModelElement.name>" +
            curCon.qualifiedName() + progressive +
            "</Foundation.Core.ModelElement.name>");
// method visibility
    String visibility = "Public";
          if (curCon.isPublic()) visibility = "Public";
          if (curCon.isProtected()) visibility = "Protected";
          if (curCon.isPrivate()) visibility = "Private";
    Writeln("<Foundation.Core.ModelElement.visibility xmi.value=\"" +
            visibility +
            "\"/>");
// !? ownerScope: (instance | classifier) - un metodo è sempre globale
    Writeln("<Foundation.Core.Feature.ownerScope xmi.value=\"classifier\"/>");
// !? isQuery: always false (a constructor is not a function)
    Writeln("<Foundation.Core.BehavioralFeature.isQuery xmi.value=\"false\"/>");
// !? specification: empty (it should be contain the body?)
    Open_Level("<Foundation.Core.Operation.specification>");
    Close_Level("</Foundation.Core.Operation.specification>");
// isPolymorphic: is there overloading?
    Writeln("<Foundation.Core.Operation.isPolymorphic xmi.value=\"" +
            (progressive.equals("") ? "true" : "false") +
            "\"/>");
// concurrency: (sequential | guarded | concurrent )
    Writeln("<Foundation.Core.Operation.concurrency xmi.value=\"" +
            (curCon.isSynchronized() ? "guarded" : "sequential") +
            "\"/>");
// owner
    Open_Level("<Foundation.Core.Feature.owner>");
    Writeln("<Foundation.Core.Class xmi.idref=\"" +
            getClassId(curClass) +
            "\"/>");
    Close_Level("</Foundation.Core.Feature.owner>");
// begin parameters
    Remark("<!-- \"" + curCon.qualifiedName() + progressive + "\" parameters begin -->");
    Open_Level("<Foundation.Core.BehavioralFeature.parameter>");

// parameters loop
    parameters = curCon.parameters();
    for (int k = 0 ; k < parameters.length ; k++)
    {
      Write_Parameter(curClass, curCon, progressive, parameters[k]);
    }

// end of parameters
    Close_Level("</Foundation.Core.BehavioralFeature.parameter>");
    Remark("<!-- \"" + curCon.qualifiedName() + progressive + "\" parameters end -->");
// close
    Close_Level("</Foundation.Core.Operation>");
    Remark("<!-- Constructor \"" + curCon.qualifiedName() + progressive + "\" end -->");
    Writeln("");
}

/*
   Usage: Write_ReturnParameter(ClassDoc, MethodDoc, String)
   return: nothing
   modify: usedType
   Description: print to stdout all information about the return parameter
*/
/**
<br>
Write_ReturnParamter()<br>
{<br>
apre, descrive e chiude il parametro di ritorno<br>
} <br><br>
*/

  static void Write_ReturnParameter(ClassDoc curClass, MethodDoc curMet,
         String progressive)
  {
    Type paramType = curMet.returnType();
    returnCheckType rCheckType = checkType(paramType);
    String ReturnName = "Return";

// open
    Remark("<!-- Parameter \"" +
           ReturnName +
           "\" begin -->");
    Open_Level("<Foundation.Core.Parameter xmi.id=\"" +
            getParameterId(curClass, curMet, progressive, ReturnName) +
            "\">");
// name
    Writeln("<Foundation.Core.ModelElement.name>ReturnName</Foundation.Core.ModelElement.name>");
// visibility
    Writeln("<Foundation.Core.ModelElement.visibility xmi.value=\"" +
            "public" +
            "\"/>");
// defaultValue: empty (meaningless)
    Open_Level("<Foundation.Core.Attribute.defaultValue>");
    Open_Level("<Foundation.Data_Types.Expression>");
    Writeln("<Foundation.Data_Types.Expression.language>Java</Foundation.Data_Types.Expression.language>");
    Writeln("<Foundation.Data_Types.Expression.body></Foundation.Data_Types.Expression.body>");
    Close_Level("</Foundation.Data_Types.Expression>");
    Close_Level("</Foundation.Core.Attribute.defaultValue>");
// parameter kind (in | out | inout | return)
    Writeln("<Foundation.Core.Parameter.kind xmi.value=\"return\"/>");
// parameter type
    Open_Level("<Foundation.Core.Parameter.type>");
    Writeln("<Foundation.Core.DataType xmi.idref=\"" +
            getDatatypeId(rCheckType) +
            "\"/>");
    Close_Level("</Foundation.Core.Parameter.type>");
// close
    Close_Level("</Foundation.Core.Parameter>");
    Remark("<!-- Parameter \"" +
    ReturnName +
    "\" end -->");
  }

/*
   Usage: Write_Parameter(ClassDoc, ContructorDoc, String, Parameter)
   return: nothing
   modify: usedType
   Description: print to stdout all information about this parameter
*/
/**
<br>
Write_Parameter()<br>
{<br>
apre, descrive e chiude un parametro<br>
}<br><br>
*/

  static void Write_Parameter(ClassDoc curClass, ConstructorDoc curCon,
         String progressive, Parameter curParam)
  {
    Type paramType = curParam.type();
    returnCheckType rCheckType = checkType(paramType);

// open
    Remark("<!-- Parameter \"" +
           curParam.name() +
           "\" begin -->");
    Open_Level("<Foundation.Core.Parameter xmi.id=\"" +
            getParameterId(curClass, curCon, progressive, curParam.name()) +
            "\">");
// name
    Writeln("<Foundation.Core.ModelElement.name>" +
            curParam.name() +
            "</Foundation.Core.ModelElement.name>");
// !? visibility: private (for a method is meaningless)
    Writeln("<Foundation.Core.ModelElement.visibility xmi.value=\"private\"/>");
// defaultValue: empty (don't exists in Java)
    Open_Level("<Foundation.Core.Parameter.defaultValue>");
    Open_Level("<Foundation.Data_Types.Expression>");
    Writeln("<Foundation.Data_Types.Expression.language>Java</Foundation.Data_Types.Expression.language>");
    Writeln("<Foundation.Data_Types.Expression.body></Foundation.Data_Types.Expression.body>");
    Close_Level("</Foundation.Data_Types.Expression>");
    Close_Level("</Foundation.Core.Parameter.defaultValue>");
// parameter kind (in | out | inout | return)
    Writeln("<Foundation.Core.Parameter.kind xmi.value=\"in\"/>");
// parameter type
    Open_Level("<Foundation.Core.Parameter.type>");
    Writeln("<Foundation.Core.DataType xmi.idref=\"" +
            getDatatypeId(rCheckType) +
            "\"/>");
    Close_Level("</Foundation.Core.Parameter.type>");
// close
    Close_Level("</Foundation.Core.Parameter>");
    Remark("<!-- Parameter \"" + curParam.name() + "\" end -->");
  }

/*
   Usage: Write_Parameter(ClassDoc, MethodDoc, String, Parameter)
   return: nothing
   modify: usedType
   Description: print to stdout all information about this parameter
*/
  static void Write_Parameter(ClassDoc curClass, MethodDoc curMet,
         String progressive, Parameter curParam)
  {
    Type paramType = curParam.type();
    returnCheckType rCheckType = checkType(paramType);

// open
    Remark("<!-- Parameter \"" +
           curParam.name() +
           "\" begin -->");
    Open_Level("<Foundation.Core.Parameter xmi.id=\"" +
            getParameterId(curClass, curMet, progressive, curParam.name()) +
            "\">");
// name
    Writeln("<Foundation.Core.ModelElement.name>" +
            curParam.name() +
            "</Foundation.Core.ModelElement.name>");
// !? visibility: private (for a method is meaningless)
    Writeln("<Foundation.Core.ModelElement.visibility xmi.value=\"private\"/>");
// defaultValue: empty (don't exists in Java)
    Open_Level("<Foundation.Core.Parameter.defaultValue>");
    Open_Level("<Foundation.Data_Types.Expression>");
    Writeln("<Foundation.Data_Types.Expression.language>Java</Foundation.Data_Types.Expression.language>");
    Writeln("<Foundation.Data_Types.Expression.body></Foundation.Data_Types.Expression.body>");
    Close_Level("</Foundation.Data_Types.Expression>");
    Close_Level("</Foundation.Core.Parameter.defaultValue>");
// parameter kind (in | out | inout | return)
    Writeln("<Foundation.Core.Parameter.kind xmi.value=\"in\"/>");
// parameter type
    Open_Level("<Foundation.Core.Parameter.type>");
    Writeln("<Foundation.Core.DataType xmi.idref=\"" +
            getDatatypeId(rCheckType) +
            "\"/>");
    Close_Level("</Foundation.Core.Parameter.type>");
// close
    Close_Level("</Foundation.Core.Parameter>");
    Remark("<!-- Parameter \"" + curParam.name() + "\" end -->");
  }

// ------------------
// LOW LEVEL ROUTINES
// ------------------

/*
   Usage: getDatatypeId(returnCheckType dataType)
*/

  static String getDatatypeId(returnCheckType dataType)
  {
    if (dataType.isPrimitive)
      return "id" + dataType.returnType;
    else return getClassId(dataType.returnClass);
  }

/*
   Usage: getClassId(ClassDoc);
     ClassDoc: class to find the id out
   Return: the id String of the specified class.
*/
  static String getClassId(ClassDoc curClass)
  {
    return "id" + curClass.qualifiedTypeName(); // .typeName() ??
  }

/*
   Usage: getFieldId(ClassDoc, FieldDoc);
     ClassDoc: class of the field
     FieldDoc: field to find the id out
   Return: the id String of the specified field.
*/
  static String getFieldId(ClassDoc curClass, FieldDoc curField)
  {
    return getClassId(curClass) + "Attr" + curField.name();
  }

/*
   Usage: getOperationId(ClassDoc, MethodDoc, String);
     ClassDoc : class of the method
     MethodDoc: method to find the id out
     String   : method's progressive
   Return: the id String of the specified operation.
*/
  static String getOperationId(ClassDoc curClass, MethodDoc curMet, String progressive)
  {
    return getClassId(curClass) + "Op" + curMet.name() + progressive;
  }

/*
   Usage: getConstructorId(ClassDoc, ConstructorDoc, String);
     ClassDoc : class of the constructor
     ConstructorDoc: constructor to find the id out
     String   : constructor's progressive
   Return: the id String of the specified constructor.
*/
  static String getConstructorId(ClassDoc curClass, ConstructorDoc curCon, String progressive)
  {
    return getClassId(curClass) + "Constructor" + progressive;
  }

/*
   Usage: getParameterId(ClassDoc, MethodDoc, String, String);
     ClassDoc  : method's class
     MethodDoc : parameter's method
     String    : method's progressive
     String : parameter to find the id out
   Return: the id String of the specified field.
*/
  static String getParameterId(ClassDoc curClass, MethodDoc curMet, String progressive, String curParamName)
  {
    return getOperationId(curClass, curMet, progressive) + "Param" + curParamName;
  }

/*
   Usage: getParameterId(ClassDoc, ConstructorDoc, String, String);
   Return: the id String of the specified field.
*/
  static String getParameterId(ClassDoc curClass, ConstructorDoc curCon, String progressive, String curParamName)
  {
    return getConstructorId(curClass, curCon, progressive) + "Param" + curParamName;
  }

/*
   Usage: getGeneralizationId(ClassDoc);
     ClassDoc : child class
   Return: the id String of the specified generalization.
*/
  static String getGeneralizationId(ClassDoc curClass)
  {
    return ("idGener" + curClass.typeName() + curClass.superclass().typeName());
  }

/*
   Usage: getGeneralizeInterfaceId(ClassDoc curClass, ClassDoc curInterf);
     ClassDoc curClass: child class
     ClassDoc curInterf: specified interface
   Return: the id String of the specified generalization.
*/
  static String getGeneralizeInterfaceId(ClassDoc curClass, ClassDoc curInterf)
  {
    return ("idGener" + curClass.typeName() + curInterf.typeName());
  }

  /*
     Usage: getAssociationId(ClassDoc curClass, ClassDoc assocClass)
     Return: the id String of the specified explicit association.
  */
  static String getAssociationId(ClassDoc curClass, ClassDoc assocClass)
  {
    return ("idAssoc" + curClass.typeName() + assocClass.typeName());
  }

  /*
     Usage: getAssociationStartId(ClassDoc curClass, ClassDoc assocClass)
     Return: the id String of the specified explicit association start.
  */
  static String getAssociationStartId(ClassDoc curClass, ClassDoc assocClass)
  {
    return getAssociationId(curClass,assocClass) + "AssocEndOwner";
  }

  /*
     Usage: getAssociationEndId(ClassDoc curClass, ClassDoc assocClass)
     Return: the id String of the specified explicit association end.
  */
/**
<br>
Tutte i metodi del tipo get_elemento_Id ritornano l'identificatore unico nel<br>
documento Xmi del particolare elemento. <br><br>
*/

  static String getAssociationEndId(ClassDoc curClass, ClassDoc assocClass)
  {
    return getAssociationId(curClass,assocClass) + "AssocEndFeature";
  }

/*
   Usage: umlMult(String dimension)
     dimension: dimension string
   Description: it returns the dimension of an attribute, given
                a dimension string (scalar = 1)
   Examples:
   ""     --> "1"
   "[]"   --> "*"
   "[][]" --> "*,*"
*/
/**
<br>
Ritorna la dimensione di un attributo, data la dimensione in formato
stringa.<br>
Esempio:<br>
""     --> "1"<br>
"[]"   --> "*"<br>
"[][]" --> "*,*"<br><br>
*/
static String umlMult(String dimension)
{
  String returnMult;

  if (dimension.equals(""))
  {
    return "1";
  } else
  {
    int l = (dimension.length() / 2);
    returnMult = "*";
    for (int i = 0 ; i < l - 1 ; i++)
    {
      returnMult = returnMult.concat(",*");
    }
  }
  return returnMult;
}

/*
   Usage: isInternal(ClassDoc);
     ClassDoc: class to be searched in "classes" array
                 (with or without including package prefix)
   Return: TRUE if the class is in "classes" array wich contain all classes
                processed by Javadoc;
           FALSE otherwise;
*/
/**
<br>
Ritorna TRUE se la classe e' tra quelle passate a javadoc per essere
esaminata, FALSE altrimenti.
<br><br>
*/
  static boolean isInternal(ClassDoc testClass) {
    for (int i = 0 ; i < classes.length ; ++i)
    {
      if ((classes[i].qualifiedTypeName()).equals(testClass.qualifiedTypeName())) return true;
    }
    return false;
  }

/*
   Usage: checkType(Type)
   Type:  an instance of class Type
   Return: nothing
   Modify: if Type is primitive or is a class not passed to javadoc, add the
           Type name to usedType Vector (if not yet present)
*/
/**
<br>
Ritorna un'istanza della classe returnCheckType che descrive il Type
thisType. Se il tipo e' primitivo o la classe e' esterna, aggiunge l'istanza
returnCheckType relativa a Type al vettore usedType (se non ancora presente)
<br><br>
*/
static returnCheckType checkType(Type thisType)
{
  ClassDoc classType = thisType.asClassDoc();
  returnCheckType r;
  if (classType == null)
//primitive type
  {
    r = new returnCheckType(null, thisType.typeName(), thisType.dimension(), true);
  } else
  {
    r = new returnCheckType(classType, classType.qualifiedTypeName(), thisType.dimension(), false);
  }

// it's already in usedtype?
  boolean found = false;
  for (int i = 0 ; i < usedType.size() ; i++)
  {
    returnCheckType rc = (returnCheckType) usedType.elementAt(i);
    if (rc.returnType.equals(r.returnType))
    {
       found = true;
       break;
    }
  }

// if not already in usedtype, if it's a primitive datatype or an external class, insert in usedType
  if ((!(found)) && (r.isPrimitive || !(isInternal(r.returnClass)))) usedType.addElement(r);
  return r;
} //end of checkType method

/*
   Usage: allPosition (MethodDoc)
   return: array of int indicating the number of methods (in the first cell) and
           the positions, inside methods array, of methods with the same name as
           MethodDoc
   modify: nothing
*/
/**
<br>
Ritorna un array di interi che indica il numero di metodi (nella prima
cella dell'array) e la posizione, all'interno dell'array dei metodi, dei
metodi con lo stesso nome del metodo passato come parametro
<br><br>
*/
static int[] allPosition(MethodDoc method)
{
  int[] position = new int[methods.length + 1];
  int curPos = 0;
  for (int c = 0 ; c < methods.length ; c++)
  {
    if ((methods[c] != null) && (method.name().equals(methods[c].name()) ))
//correct, because && evaluete only left side if it is false
    {
      curPos += 1;
      position[curPos] = c;
    }
  }
  position[0] = curPos;
  return position;
}
/**
<br>
Riempie il vettore nonLeafClass con le classi non foglia.<br><br>
*/
static void fillLeafClass()
{
  for (int i = 0 ; i < classes.length ; i++)
  {
    ClassDoc superClass = classes[i].superclass();
    if ((superClass != null) && (isInternal(superClass))) nonLeafClass.addElement(superClass.qualifiedTypeName() );
  }
}
/**
<br>
Ritorna TRUE se la classe theClass non e' presente nell'array
nonLeafClass,FALSE altrimenti.<br><br>
*/
static boolean isLeaf(ClassDoc theClass)
{
  return (nonLeafClass.indexOf(theClass.qualifiedTypeName() ) == -1) ? true : false;
}

/*
   Usage: Open_Level(row)
   return,modify: nothing
   Description: print out a row and increment indentation
*/
/**
<br>
scrive un tag di apertura e aumenta il livello di indentazione.<br>
<br>
*/

static void Open_Level(String row)
{
  for (int i=0; i<indentlevel; i++) System.out.print("\t");
  System.out.println(row);
  indentlevel++;
}

/*
   Usage: Wtiteln(row)
   return,modify: nothing
   Description: print out a row with the correct indentation
*/
/**
<br>
Scrive una riga<br>
<br>
*/

static void Writeln(String row)
{
  for (int i=0; i<indentlevel; i++) System.out.print("\t");
  System.out.println(row);
}

/*
   Usage: Remark(row)
   return,modify: nothing
   Description: print out a comment
*/
/**
<br>
scrive una riga di commento<br>
Es.Remark("&lt;!-- The UML Model begins --&gt;");<br>
produce<br>
&lt;!-- The UML Model begins --&gt; <br><br>
*/

static void Remark(String row)
{
  for (int i=0; i<indentlevel; i++) System.out.print("\t");
  System.out.println(row);
}

/*
   Usage: Close_Level(row)
   return,modify: nothing
   Description: print out a row and decrement indentation
*/
/**
<br>
abbassa il livello di indentazione e scrive un tag di chiusura<br>
<br>
*/

static void Close_Level(String row)
{
  indentlevel--;
  for (int i=0; i<indentlevel; i++) System.out.print("\t");
  System.out.println(row);
}

} //end of class JavaToXmiuml

//in constructor str1 must eventually be theClass.qualifiedTypeName()
/**
<br>
Classe ausiliaria che viene utilizzata in pratica come struttura dati. Memorizza le<br>
informazioni correlate a un tipo (primitivo o meno).<br>
<br>
*/  
class returnCheckType {
  ClassDoc returnClass;
  String returnType;
  String returnTypeDimension;
  boolean isPrimitive;
  public returnCheckType(ClassDoc theClass, String str1, String str2, boolean b)
  {
    returnClass = theClass;
    returnType = str1;
    returnTypeDimension = str2;
    isPrimitive = b;
  }
}