/**
 *This class is used to generate a XML schema for a moby objet; To builder a XML schema element, call the method of
 *buildSchem of the class; when a name of object is given, we find a MElement for this name; By analysis of the has Vector
 *and hasa Vector of the MElement, we get the XML Schema for the object which has the inputed name.
 *@author Lixin
 *@author Eddie
 *@version 1.0
 */
package org.biomoby.shared.schema;

import java.util.Date;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;

import org.jdom.Attribute;
import org.jdom.Comment;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.Namespace;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;



public class Builder {

	private int typeCount=0;  //Everytime we create a type (complexType or simpleType), the variable will increase one.
	
	private  Element root;  //The root element of the XML Schema

	private Element firstComplexType;
	
	public static   Namespace namespace; //This namespace is "http://www.3w.org/2001/XMLSchem".
	
	/**
	 *Given a string, we will give a element represnting an xml schema which describe the object of the name. 
	 *@param name the name of object
	 *@return XML Element which represents an XML Schema
	*/
	public Element buildSchema(String name) 
	{
		MElement mElement=new MElement();
		try{
			mElement=RdfParser.buildMElement(name);  //find the MElement object representing the moby object
			// object doesnt exist so return null
			if (mElement == null)
			    return null;
       		}
		catch(Exception e)
		{
			e.printStackTrace();
			return null;
		}
		


		String nameOf=mElement.getName();
		root=getRoot(nameOf);   //create a root element for the XML Schema of the moby object

		getElement(mElement);  //add the rest part of XML schema to the root element

		return root;
	
	}

	/**
	 * 
	 * @param name the name of the Moby data type that a complete moby message schema document will be created for
	 * @return a jDom element object that contains the schema for the moby data type 'name' or null if no valid data type exists 
	 */
	public Element buildMobyEncapsulatedSchema(String name) {
	    Element moby = buildSchema(name);
	    if (moby == null)
	        return null;
	    // create the MOBY element
	    Element MOBYelement = new Element("element", namespace);
	    MOBYelement.setAttribute("name", "MOBY");
	    Element complex = new Element("complexType", namespace);
	    Element sequence = new Element("sequence", namespace);
	    Element innerElement = new Element("element", namespace);
	    innerElement.setAttribute("name", "mobyContent");
	    innerElement.setAttribute("type", "moby:mobyContentType");
	    sequence.addContent(innerElement);
	    complex.addContent(sequence);
	    MOBYelement.addContent(complex);
	    moby.addContent(MOBYelement);
	    // mobyContent element
	    complex = new Element("complexType", namespace);
	    complex.setAttribute("name", "mobyContentType");
	    sequence = new Element("sequence", namespace);
	    innerElement = new Element("element", namespace);
	    innerElement.setAttribute("name", "mobyData");
	    innerElement.setAttribute("type", "moby:mobyDataType");
	    sequence.addContent(innerElement);
	    complex.addContent(sequence);
	    moby.addContent(complex);
	    // mobyDataType complex type
	    complex = new Element("complexType", namespace);
	    Element attributeElement = new Element("attribute", namespace);
	    attributeElement.setAttribute("name","queryID");
	    attributeElement.setAttribute("use","required");
	    attributeElement.setAttribute("form","qualified");
	    complex.setAttribute("name", "mobyDataType");
	    sequence = new Element("sequence", namespace);
	    innerElement = new Element("element", namespace);
	    innerElement.setAttribute("name", "Simple");
	    innerElement.setAttribute("type", "moby:SimpleType");
	    sequence.addContent(innerElement);
	    complex.addContent(sequence);
	    complex.addContent(attributeElement);
	    moby.addContent(complex);
	    // add the datatype name to the simple complex type
	    complex = new Element("complexType", namespace);
	    attributeElement = new Element("attribute", namespace);
	    attributeElement.setAttribute("name","articleName");
	    attributeElement.setAttribute("use","required");
	    attributeElement.setAttribute("form","qualified");
	    complex.setAttribute("name", "SimpleType");
	    sequence = new Element("sequence", namespace);
	    innerElement = new Element("element", namespace);
	    innerElement.setAttribute("name", name);
	    innerElement.setAttribute("type", "moby:"+name+"Type");
	    sequence.addContent(innerElement);
	    complex.addContent(sequence);
	    complex.addContent(attributeElement);
	    moby.addContent(complex);
	    /*
	<xs:complexType name="SimpleType">
		<xs:sequence>
			<xs:element name="mobyDataType" type="moby:mobyDataTypeType"/> // this is the line that is modified when handing out the full scale moby schema
		</xs:sequence>
		<xs:attribute name="articleName" use="required" form="qualified"/>
	</xs:complexType>
	     */
	    

	    return moby;
	}
	
	/**
	 *the input is a MElement object; we will find all its hasa and has relations with other object; then modify the root
         * element of the output xml file;  the root element is the root element of a xml schema xml file.
         *@param m a MElement
         */
	public void getElement(MElement m)
	{
		Vector hasa=m.getHasaMElements();
		
		Vector has=m.getHasMElements();

		//if this MElement does not have hasa or has relation with other object, only need to return 
		//the first level. 
		if((hasa.size()==0)&&(has.size()==0))
		{
			getFirstLevel(m, root);
			Vector vcc=new Vector();	//create an empty vector as a parameter of function set3Attributes		
			set3Attributes(m, firstComplexType,vcc);
			
			
			return;
		}
		else //this MElement have has and/or hasa relation with ohter MElment
		{
			
		
			getFirstLevel(m,root);
			Element sequence=new Element("sequence",namespace); //need a sequence element in XML schema for has
									   //and hasa object
			firstComplexType.addContent(sequence);
			
			
			
			//find the primitive element and add them to schema
			Vector tempt1;
			Vector tempt2;
			tempt1=(Vector)has.clone();//do not change tempt1 and tempt2, so clone two vector for them.
			tempt2=(Vector)hasa.clone();
			
			PrimitiveVector pri=new PrimitiveVector(tempt1, tempt2); 
			
			
			
			addPrimitiveElement(pri, sequence);//add these primitive elements to the squences
			
			/*for object other than primitive type*/
			if(has.size()>0)
			{
	
				
				for (int i=0; i<has.size(); i++)
				{
					MElement temM=(MElement)has.get(i);
					String namem=temM.getName();


					
					//if the element is not primitive, create a new XML Schema element for every MElement
					if(!(MElement.isPrimitive(namem)))
					{
							
						Element a=new Element("element",namespace);
						Attribute at=new Attribute("name",namem);

						String typeNamem=namem+"Type"+typeCount;
						typeCount++;
						Attribute at2=new Attribute("type","moby:"+ typeNamem);

						Vector hasaNamesV=getHasaNameVector(temM);
						addUniqueElement(a,"unique_1",hasaNamesV);
						
						//add notation of description
						String st=temM.getDescription();
						addDescriptNote(st,sequence);
					
						sequence.addContent(a);
						a.setAttribute(at);
						a.setAttribute(at2);

						//add occurs attribute; has relation has the following occurs attributes
						Attribute o1=new Attribute("minOccurs","1");
						Attribute o2=new Attribute("maxOccurs","unbounded");
				
				
						a.setAttribute(o1);
						a.setAttribute(o2);

						Vector empty=new Vector();//only create a empty vector as a parameter
						Element myCom=getComplexTypeRec(temM, typeNamem,empty);
						root.addContent(myCom);
						
					}
				}
			}
			if(hasa.size()>0)//the following dealing with the object in the hasa vector
			{
				/*create a MElementHastable for the hasa Vector. The key of the hashtabel is MElement, 
				and the value of hashtable of a vector containing article names*/
				MElementHashtable hss=new MElementHashtable(hasa);

				Hashtable hs=hss.getHashtable();//get a hashtable 
				
				Enumeration e=hs.keys();//get all keys of the hashtable
				
				while(e.hasMoreElements())//go through the Enumeration
				{
					MElement ml=(MElement)e.nextElement();
					
					Vector vc=(Vector)hs.get(ml);//get value, a vector of article names, of the hashtable
					String namem=ml.getName();

					
					if(!(MElement.isPrimitive(namem)))
					{
						Element a=new Element("element", namespace);//add the element to the sequence
						Attribute at=new Attribute("name",namem);
					
						String typeNamem=namem+"Typep"+typeCount;
						typeCount++;
						Attribute at2=new Attribute("type","moby:"+ typeNamem);
						
						Vector hasaNamesV=getHasaNameVector(ml);
						addUniqueElement(a,"unique_1",hasaNamesV);//add an unique element
				
												
						String st=ml.getDescription();
						addDescriptNote(st,sequence);
						sequence.addContent(a);
						a.setAttribute(at);
						a.setAttribute(at2);
						
						String size=""+vc.size();
						
						Attribute o1=new Attribute("minOccurs",size);//add occurence of element
						Attribute o2=new Attribute("maxOccurs",size);
						a.setAttribute(o1);
						a.setAttribute(o2);
						
						//recursively to find the complex type
						Element myCom=getComplexTypeRec(ml,typeNamem,vc);
						root.addContent(myCom);
					}
				}
				
				
			}
			Vector vcc2=new Vector();//the empty vector is only used to as a parameter of set3Attributes()
			set3Attributes( m,firstComplexType,vcc2);

			
		}
		
	}

	/**
	 *Given a vector containing possible article names and type name, add an XML Schema element to describe 
	 *the restriction.
	 *@param roots the root element of the XML Schema
	 *@param types the name of XML Schema simpleType
         *@param articles a vector containing different article names
	*/
	public void addArticleNameType(Element roots, String types, Vector articles)
	{    
                //create a simpleType XML Schema element
		Element simpleType=new Element("simpleType", namespace);
		Attribute at=new Attribute("name",types);
		simpleType.setAttribute(at);

                //create a XML schema restriction element
		Element restriction=new Element("restriction", namespace);
		Attribute base=new Attribute("base","xs:string");
		restriction.setAttribute(base);

		simpleType.addContent(restriction);

		//put all article names into the enumeration of the restriction element
		for(int i=0;i<articles.size();i++)
		{
			String arName=(String)articles.elementAt(i);
			Element en=new Element("enumeration", namespace);
			Attribute att=new Attribute("value",arName);
			en.setAttribute(att);

			restriction.addContent(en);
		}
	
		roots.addContent(simpleType);//add this simpleType element into the root element
	}

		
	
	/**
	*Add ID, namespace and article attributes elements into Element types; every moby object has these three attributes.
	*@param m a MElement
	*@param types the type of MElement; there is a field in MElement
	*@param ar a vector containing all possible article names for this MElement
	*/
	public void set3Attributes(MElement m, Element types, Vector ar)
	{

			//indicate wether we need use simpleContent element or not
			int flag=1;

			Vector hasa=m.getHasaMElements();  //get hasa vector containing objects with hasa relationship
			Vector has=m.getHasMElements();  //get has vector containing objects with has relationship
			if((hasa.size()>0) ||(has.size()>0))//if true, we can not use simpleContent XML Schema element
			{
				flag=0;
			}
			String articleName=m.getArticleName();

			Element e1=getNamespaceAttribute();
			Element e2=getIDAttribute();
			Element e3;

			if(ar.size()==0)
			{
				 e3=getArticleName(articleName);
			}
			else
			{
				/*if this object can has many article names, we put restriction on the article names*/
				e3=getRestrictionArticleName(ar);
			}

			//check whether the type of this element is null or not
			String typeName=m.getType();
		
			/*check if the name of the element is primitive*/
			String priName=m.getName();
			if(MElement.isPrimitive(priName))
			{
				typeName=priName;
			} 
			
			if(typeName==null||typeName.length()==0||flag==0)
			{
				
				types.addContent(e1);
				types.addContent(e2);
				types.addContent(e3);
			}
			
			/*if the type is not empty, and use extensionin schema to describe this relation*/
			else
			{
				typeName=typeName.toLowerCase();
			
				/*create a simpleContent XML Schema element*/
				Element simpleContent=new Element("simpleContent",namespace);

				Element extension=new Element("extension", namespace);

				Attribute base=new Attribute("base","xs:"+typeName);
				extension.setAttribute(base);

				extension.addContent(e1);
				extension.addContent(e2);
				extension.addContent(e3);

				simpleContent.addContent(extension);

				types.addContent(simpleContent);
		}
	
	}
		
	/**
	 *create the top level of xml schema element for a moby object.
	 *@param m a MElement
	 *@param rt a xML Schema root element
	 */
	public  void getFirstLevel(MElement m, Element rt)
	{
		String name=m.getName();
		String type=name+"Type";

		Element tem1=new Element("element",namespace);
		Attribute attr1=new Attribute("name",name);
		Attribute attr2=new Attribute("type", "moby:"+type);
		tem1.setAttribute(attr1);
		tem1.setAttribute(attr2);
		
		/*add unique element for moby objects in the hasa relationship*/
		Vector hasaNames=getHasaNameVector(m);
		//add an unique element to the first level
		addUniqueElement(tem1,"first", hasaNames);
		rt.addContent(tem1);

		String str=m.getDescription();
		addDescriptNote(str,rt);

                /*add the complexType element of XML Schema to the root element*/
		firstComplexType=getComplexType(m, type);
		

		rt.addContent(firstComplexType);
	}

	/**
	*recursively get a complexType XML Shema element for MElement; when this MElement does
	*not have has and hasa relation, we use another method called getComplexType; 
	*@param m a MElement object
	*@param typeName the name of complexType
	*@param vc1 a vector containing all possible article names for the MElement
	*@return the complexType element for this MElement object
	*/
	public Element getComplexTypeRec(MElement m, String typeName, Vector vc1)
	{

		root.addContent(new Comment("This is definition of complexType "+typeName));
		
		/*get has and hasa vector for this MElement object*/
		Vector hasa1=m.getHasaMElements();
		
		Vector has1=m.getHasMElements();
		
		/*create a complexType element*/
		Element complexType=new Element("complexType",namespace);
		Attribute at1=new Attribute("name",typeName);
		complexType.setAttribute(at1);
		
		/*if this MElement does not have has or hasa relationship with other object, we have done*/
		if((hasa1.size()==0)&&(has1.size()==0))
		{

			set3Attributes(m,complexType,vc1);
			
			return complexType;
		}
		/*if this MElement has has or hasa relationshipe with other object, need puts all object into sequence XML
		 schema element*/
		else
		{
			Element sequence1=new Element("sequence",namespace);
			complexType.addContent(sequence1);

			//find the primitive elements and add these to schema
			PrimitiveVector pri=new PrimitiveVector(hasa1,has1);
			addPrimitiveElement(pri, sequence1);
			
			/*deal with objects in the hasa vector*/
			if(hasa1.size()>0)
			{

				MElementHashtable hss=new MElementHashtable(hasa1);
				Hashtable hs=hss.getHashtable();
				
				Enumeration e=hs.keys();
				
				while(e.hasMoreElements())
				{
					MElement ml=(MElement)e.nextElement();
					Vector vc=(Vector)hs.get(ml);
					String namem=ml.getName();
					
					/*we has handled the primitive element before*/
					if(!(MElement.isPrimitive(namem)))
					{
						Element a=new Element("element",namespace);
						Attribute at=new Attribute("name",namem);

						String typeNamem=namem+"Typehasa"+typeCount;
						typeCount++;
						Attribute at2=new Attribute("type","moby:"+typeNamem);
					
						Vector hasaNameV=getHasaNameVector(ml);	
						addUniqueElement(a,"unique_1", hasaNameV);

						a.setAttribute(at);
						a.setAttribute(at2);
						
						String size=""+vc.size();
						Attribute o1=new Attribute("minOccurs",size);
						Attribute o2=new Attribute("maxOccurs",size);
						a.setAttribute(o1);
						a.setAttribute(o2);
						sequence1.addContent(a);

						Element myCom=getComplexTypeRec(ml,typeNamem,vc);
						root.addContent(myCom);
					}
				}
						
		
			}
			if(has1.size()>0)
			{
				
				
				for(int i=0;i<has1.size();i++)
				{
					MElement mm=(MElement)has1.get(i);
					String namem=mm.getName();

					//if the element is not primitive
					if(!(MElement.isPrimitive(namem)))
					{
						Element a=new Element("element",namespace);
						Attribute at=new Attribute("name",namem);
					
						String typeNamem=namem+"Typehas"+typeCount;
						typeCount++;
					
						Attribute at2=new Attribute("type",typeNamem);
						
						Vector hasaNamesV=getHasaNameVector(mm);
						addUniqueElement(a,"unique_1",hasaNamesV);

						a.setAttribute(at);
						a.setAttribute(at2);

						Attribute o1=new Attribute("minOccurs","1");
						Attribute o2=new Attribute("maxOccurs","unbounded");
						a.setAttribute(o1);
						a.setAttribute(o2);
						sequence1.addContent(a);

						Vector empty=new Vector();
						/*use getComplexTypeRec recursively*/
						Element myCom=getComplexTypeRec(mm,typeNamem, empty);
						root.addContent(myCom);
					}
				}
			}
			
			set3Attributes(m,complexType,vc1);
			

			return complexType;
		}
		
	}
	
	/**
	 *create a complexType XML schema element for MElement which does not have has or hasa relation with other MElement
	 *@param m a MElement
	 *@param typeName the name of the complexType
	 *@return a complexType XML schema element
	 */
	public Element getComplexType(MElement m, String typeName)
	{
		
		Element complexType=new Element("complexType",namespace);
		Attribute at1=new Attribute("name",typeName);
		complexType.setAttribute(at1);
	
		return complexType;
		
	}
	
	/**
	 *create an xml schema element for namescape attribute of the moby element.
	 *@return an xml schema element for namespace attribute
	 */
	public Element getNamespaceAttribute()
	{
		Element e=new Element("attribute",namespace);
		Attribute ea=new Attribute("name","namespace");
		e.setAttribute(ea);

		Attribute e2=new Attribute("use","required");
		e.setAttribute(e2);

		Attribute e3=new Attribute("form","qualified");
		e.setAttribute(e3);

		Attribute e4=new Attribute("type","xs:string");
		e.setAttribute(e4);
		return e;
	}
	
	/**
	 *create an xml schema element for ID attribute 0f a moby object.
	 *@return an xml schema element for ID attribute
	 */
	public Element getIDAttribute()
	{
		Element e=new Element("attribute",namespace);
		Attribute ea=new Attribute("name","id");

		Attribute ea2=new Attribute("use","required");
		Attribute ea3=new Attribute("form","qualified");
		e.setAttribute(ea);
		e.setAttribute(ea2);
	
		e.setAttribute(ea3);

		Attribute e4=new Attribute("type","xs:string");
		e.setAttribute(e4);
		return e;
	}

	/**
	 *create an xml schema element for article name attribute of a moby object
	 *@param article value of the article attribute
	 *@return an xml schema element for articleName attribute
	 */
	public Element getArticleName(String article )
	{
		Element e=new Element("attribute",namespace);
		Attribute ea=new Attribute("name","articleName");
		e.setAttribute(ea);

		if(article.equals(""))
		{
			Attribute r0=new Attribute("use", "required");
			Attribute r1=new Attribute("form","qualified");
			e.setAttribute(r0);
			e.setAttribute(r1);
			
			return e;
		}
		/*if the value of article name is not empty, we need set the article name value*/
		else
		{
			Attribute w1=new Attribute("use","required");
			e.setAttribute(w1);

			Attribute w2=new Attribute("form","qualified");
			e.setAttribute(w2);
			Attribute at3=new Attribute("fixed",article);
			e.setAttribute(at3);
			
			Attribute ty1=new Attribute("type","xs:string");
			e.setAttribute(ty1);
		}
		return e;
	
	}
	/**
	 *create an xml schema element for articleName attribute if the values of the articleName can have multiple choices.
	 *@param vc a vector containing possible values of articleName attribute
	 *@return an xml schema elment for articleName attribute
	 */
	public Element getRestrictionArticleName(Vector vc)
	{
		Element e=new Element("attribute",namespace);
		Attribute ea=new Attribute("name","articleName");
		e.setAttribute(ea);

		Attribute w1=new Attribute("use","required");
		e.setAttribute(w1);

		String typeName="articleType"+typeCount;
		typeCount++;
		Attribute ty=new Attribute("type","moby:"+ typeName);
		e.setAttribute(ty);

		//need to add this type in the root
		addArticleNameType(root,typeName,vc);
		return e;
	}
	/**
	 *create a root element for the schema to begin.
	 *@param str 
	 *@return an root element of XML schema
	 */
	public static Element getRoot(String str)
	{
		 namespace=Namespace.getNamespace("xs","http://www.w3.org/2001/XMLSchema");
		 Namespace namespace2=Namespace.getNamespace("moby","http://www.biomoby.org/moby");
		Element root=new Element("schema",namespace);
		
		Attribute elementFormDefault=new Attribute("elementFormDefault","qualified");
		root.setAttribute(elementFormDefault);

		Attribute attributeFormDefault=new Attribute("attributeFormDefault","qualified");
		root.setAttribute(attributeFormDefault);
		
		Attribute target=new Attribute("targetNamespace","http://www.biomoby.org/moby");
		root.setAttribute(target);
		
		root.addNamespaceDeclaration(namespace2);

		Element annota=new Element("annotation",namespace);

		Element appinfo=new Element("appinfo",namespace);
		Attribute lang=new Attribute("lang","en",Namespace.XML_NAMESPACE);
	
		appinfo.setText("Generating a XML Schema for the Moby object "+str+". "+getDate());
		appinfo.setAttribute(lang);
		
		annota.addContent(appinfo);

		root.addContent(annota);
		
		
		return root;
	}

	/**
	 *add description or comment element to the element parent.
	 *@param str the description of an element
	 *@param parent the element which we wnat to give a description
	 */
	public  void addDescriptNote(String str, Element parent)
	{
		if(str.length()<1)
		{
			return;
		}
		else
		{
			parent.addContent(new Comment(str));
			
		}
	}

	/**
	 *get the date of current time
	 *@return a string representing current time
	*/
	public static  String getDate()
	{
		Date d=new Date();
		String str=d.toString()+"."+" Eddie and Lixin";
		return str;
	}
	
	/**add all primitive element to the sequnece element.
	*@param pri a PrimitiveVector object
        *@param element a XML Schema element
	*/
	public void addPrimitiveElement(PrimitiveVector pri, Element element)
	{
		/*get all vectors which store these primitive element*/
		Vector strVector=pri.getStringVector();
		Vector intVector=pri.getIntegerVector();
		Vector flaVector=pri.getFloatVector();
		Vector datVector=pri.getDateTimeVector();

		/*handle primitive element String*/
		if(strVector.size()!=0)
		{
			int size=strVector.size();
			String sizeStr=""+size;
			Element str=new Element("element",namespace);
			Attribute a1=new Attribute("name","String");
			Attribute a2=new Attribute("minOccurs",sizeStr); //create occurence attribute
			Attribute a3=new Attribute("maxOccurs",sizeStr);

			

			String type="stringType"+typeCount;
			typeCount++;
			Attribute a4=new Attribute("type","moby:"+type);
			str.setAttribute(a1);
			str.setAttribute(a4);
			str.setAttribute(a2);
			str.setAttribute(a3);
			element.addContent(str);

			//add the complexType for string
			addPrimitiveComplexType(root,type,"xs:string"); 

			//add the simpleType for string
			addPrimitiveSimpleType(root, strVector,"Article"+type);
		}
		
		/*handle primitive element Integer*/
		if(intVector.size()!=0)
		{
			int size=intVector.size();
			String sizeStr=""+size;
			Element str=new Element("element",namespace);
			Attribute a1=new Attribute("name","Integer");
			Attribute a2=new Attribute("minOccurs",sizeStr);
			Attribute a3=new Attribute("maxOccurs",sizeStr);

			String type="integerType"+typeCount;
			typeCount++;

			Attribute a4=new Attribute("type","moby:"+type);
			str.setAttribute(a1);
			str.setAttribute(a4);
			str.setAttribute(a2);
			str.setAttribute(a3);
			element.addContent(str);

			//add the complexType for integer
			addPrimitiveComplexType(root, type,"xs:integer");

			//add the simpleType for integer
			addPrimitiveSimpleType(root, intVector,"Article"+type);
		}

		/*handle primitive element Float*/
		if(flaVector.size()!=0)
		{
			int size=flaVector.size();
			String sizeStr=""+size;
			Element str=new Element("element",namespace);
			Attribute a1=new Attribute("name","Float");
			Attribute a2=new Attribute("minOccurs",sizeStr);
			Attribute a3=new Attribute("maxOccurs",sizeStr);

			String type="floatType"+typeCount;
			typeCount++;
			Attribute a4=new Attribute("type","moby:"+type);
			str.setAttribute(a1);
			str.setAttribute(a4);
			str.setAttribute(a2);
			str.setAttribute(a3);
			element.addContent(str);

			//add the complexType for float
			addPrimitiveComplexType(root,type,"xs:float");
			
			//add the simpleType for float
			addPrimitiveSimpleType(root, flaVector,"Article"+type);
		}

		/*handle primitive object DateTime*/
		if(datVector.size()!=0)
		{
			int size=datVector.size();
			String sizeStr=""+size;
			Element str=new Element("element",namespace);
			Attribute a1=new Attribute("name","DateTime");
			Attribute a2=new Attribute("minOccurs",sizeStr);
			Attribute a3=new Attribute("maxOccurs",sizeStr);

			String type="DateTimeType"+typeCount;
			typeCount++;

			Attribute a4=new Attribute("type","moby:"+type);
			str.setAttribute(a1);
			str.setAttribute(a4);
			str.setAttribute(a2);
			str.setAttribute(a3);
			element.addContent(str);

			//add the complexType for DateTime
			addPrimitiveComplexType(root, type,"xs:DateTime");
			
			//add the simpleType for DateTime
			addPrimitiveSimpleType(root, datVector,"Article"+type);
		}
	}

	
	/**add an unique element as a child of an element parent.
	*@param parent the parent element of unique element
	*@param name the name of the unique element
	*@param strV a Vector containing the name of MElement in a hasa Vector
	*/

	public void addUniqueElement(Element parent, String name, Vector strV)
	{
		Element unique=new Element("unique", namespace);//create unique element
		Attribute u1=new Attribute("name",name);
		unique.setAttribute(u1);

		Element selector=new Element("selector",namespace);//create the selector element
		
		String xpathStr="moby:String|moby:Float|moby:Integer|moby:DateTime";
		for(int i=0; i <strV.size(); i++)
		{
			String str=(String)strV.elementAt(i);
			if(!(MElement.isPrimitive(str)))
			{
				xpathStr+="|moby:"+str;//add all name in the Vector strV into XPath
			}
			
		}
		
		Attribute s1=new Attribute("xpath", xpathStr); //create a XPath
		selector.setAttribute(s1);

		unique.addContent(selector);

		Element field=new Element("field", namespace);//create a field element
		Attribute f1=new Attribute("xpath","@moby:articleName");
		field.setAttribute(f1);

		unique.addContent(field); //add the field element to the unique element

		parent.addContent(unique);
	
	}
	
	/**
	*get a vector which contains all names of MElements in the hasa relationship of a MElement
	*@param mElement a MElement object
	*@return a vector which contains all names of MElements in the hasa vector of mElement
	*/
	private Vector getHasaNameVector(MElement mElement)
	{
		Vector hasa=mElement.getHasaMElements();
		Vector result=new Vector();
		for(int i=0; i<hasa.size(); i++)
		{
		
			MElement oElement=(MElement)hasa.elementAt(i);
			
			String name=oElement.getName();
		
			/*if the result vector is empty, we add the first name into the vector*/
			if(result.size()==0)
			{
				result.add(name);
			}
			/*if the result vector is not empty, we check whether the name already exist in the result vector*/
			else
			{
				int flag=1;
				for(int j=0; j<result.size();j++)
				{
					if(name.equalsIgnoreCase((String)result.elementAt(j)))
					{
						flag=0;//if already exists, set flag to 0
					}
				}
				
				if(flag==1)
				{
					result.add(name);
				}
			}
		}
		return result;
	}

	/**
	 *add a complexType for string to the root element; Element parent is the root Element.
	 *@param parent the parent element of this complexTpe element which is a root element here
	 *@param name the complexType name
	 *@param base the base we will extend
	 */
	public void addPrimitiveComplexType(Element parent, String name, String base)
	{
		//create the complexType element
		Element complexW=new Element("complexType",namespace);
		Attribute c1=new Attribute("name",name);
		complexW.setAttribute(c1);

		//normally primitive element is not empty
		Element simpleContent=new Element("simpleContent", namespace);
		complexW.addContent(simpleContent);

		Element extension=new Element("extension",namespace);
		Attribute extensionA1=new Attribute("base",base);
		extension.setAttribute(extensionA1);

		simpleContent.addContent(extension);
		
		//create an atribute element for articleName
		Element att1=new Element("attribute", namespace);
		Attribute att1_1=new Attribute("name", "articleName");
		Attribute att1_2=new Attribute("use","required");
		Attribute att1_3=new Attribute("form","qualified");
		Attribute att1_4=new Attribute("type","moby:Article"+name);
		att1.setAttribute(att1_1);
		att1.setAttribute(att1_2);
		att1.setAttribute(att1_3);
		att1.setAttribute(att1_4);

		extension.addContent(att1);
	
		//create an attribute element for id
		Element att2=new Element("attribute",namespace);
		Attribute att2_1=new Attribute("name","id");
		Attribute att2_2=new Attribute("use","required");
		Attribute att2_3=new Attribute("form","qualified");
		att2.setAttribute(att2_1);
		att2.setAttribute(att2_2);
		att2.setAttribute(att2_3);

		extension.addContent(att2);
	
		//create an attribute element for namespace
		Element att3=new Element("attribute",namespace);
		Attribute att3_1=new Attribute("name","namespace");
		Attribute att3_2=new Attribute("use","required");
		Attribute att3_3=new Attribute("form","qualified");
		att3.setAttribute(att3_1);
		att3.setAttribute(att3_2);
		att3.setAttribute(att3_3);

		extension.addContent(att3);

		parent.addContent(complexW);

	}
	
	
	

	/**
	 *add simpleType for the primitive element; create a enumeration XML schema element for article names.
	 *@param parent the root element
	 *@param vc a vector containing article names
	 *@param name the name of this simpleType
	 */
	public void addPrimitiveSimpleType(Element parent, Vector vc, String name)
	{
		//create the simpleType element
		Element simpleType=new Element("simpleType", namespace);
		parent.addContent(simpleType);

		Attribute simpleTypeA1=new Attribute("name",name);
		simpleType.setAttribute(simpleTypeA1);

		Element restriction=new Element("restriction", namespace);
		simpleType.addContent(restriction);

		//create a enumeration XML schema element for article names
		Attribute restrictionA1=new Attribute("base","xs:string");
		restriction.setAttribute(restrictionA1);

		for(int i=0;i<vc.size();i++)
		{
			String oneValue=(String)vc.get(i);

			Element enu=new Element("enumeration", namespace);
			Attribute enuA1=new Attribute("value",oneValue);
			enu.setAttribute(enuA1);

			restriction.addContent(enu);
		}
	}
	
	
	/**
	 * 
	 * @param args the string array containing the arguments for this main method
	 */
	public static void main(String[] args ) 
	{
		if(args.length<1)
		{
		    printUsage();
		}
		try
		{
			Builder b=new Builder();
			//input the name of moby object
			Element root = null;
			if (args.length == 1)
			    root = b.buildSchema(args[0]);
			else {
			    if (args.length == 2) {
			        // -m generates a full moby message schema
			        if (args[0].equals("-m")) {
			            root = b.buildMobyEncapsulatedSchema(args[1]);
			        } else {
			            printUsage();
			        }
			    }
			}
			Document doc=new Document(root);

			XMLOutputter fmt=new XMLOutputter();
		
			Format format=Format.getPrettyFormat();
			fmt.setFormat(format);
	
			if (root != null)
			    System.out.println(fmt.outputString(doc));
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
	}

    /*
     * used to display the usage of the Main method 
     */
    private static void printUsage() {
		System.out.println("Usage: java Builder <options> moby_data_type");
		System.out.println("where possible options include:");
		System.out.println("    -m       generate a schema that describes the complete moby message");
		System.out.println();
		System.exit(1);
    }
}		
	



