/*
 * (c) Copyright IBM Corp 2001, 2005 
 */

package edu.uga.cs.lsdis.meteors.wadls;

import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Vector;

import javax.wadls.Application;
import javax.wadls.ModelReference;
import javax.wadls.Grammars;
import javax.wadls.WADLSException;
import javax.wadls.extensions.schema.Schema;
import javax.wadls.extensions.ExtensibilityElement;
import javax.xml.namespace.QName;

import org.w3c.dom.Attr;
import org.w3c.dom.Element;

import edu.uga.cs.lsdis.meteors.wadls.util.SchemaUtils;

/**
 * This class represents the &lt;types&gt; section of a WSDL document.
 *
 * @author Zixin Wu (wuzixin@uga.edu)
 * @author Matthew J. Duftler (duftler@us.ibm.com)
 */
public class GrammarsImpl implements Grammars
{
	protected Application app = null;		//WADLS Definition
	protected List<ModelReference> modelReferences = null;
	protected Element docEl = null;
	protected List extElements = new Vector();
	protected Map allSchemas = null;
	
	
	public static final long serialVersionUID = 1;
	
	public GrammarsImpl(Application app){
		this.app = app;
	}
	
	public List getTopLevelSchemas(){
		return SchemaUtils.getSchemas(this.extElements);		
	}
	
	/**
	 * Get the DOM elements of all the schemas in this Types.
	 * @return A list of DOM elements of all the schemas in this Types.
	 */
	public Map getSchemas(){
		return this.allSchemas;
	}
	
	public void setSchemas(Map allSchemas){
		this.allSchemas = allSchemas;
	}
	
	
	/**
	 * Get the DOM element of the first schema in this Types.
	 * @return The DOM element of the first schema in this Types.
	 */
	public Schema getFirstSchema(){
		return SchemaUtils.getFirstSchema(this.extElements);
	}
	public ModelReference getModelReference(){
		if(modelReferences == null)
			return null;
		return modelReferences.get(0);
	}
	
	public List<ModelReference> getModelReferences(Element startElement, String path, Application app) throws WADLSException, URISyntaxException {
		Element el = getXSDEle(startElement, path);
		if (el == null)
			return null;
		String attrModelReference = el.getAttributeNS(Constants.NS_URI_WADLS, Constants.ATTR_MODELREF);
		if (attrModelReference.equals(""))
			return null;
		List<ModelReference> mrefs = ModelReferenceImpl.getModelReferences(attrModelReference, app);
		if(mrefs.size() == 0)
			return null;
		return mrefs;
	}
	public ModelReference getModelReference(Element startElement, String path, Application app) throws WADLSException, URISyntaxException{
		List<ModelReference> mrefs = getModelReferences(startElement, path, app);
		return mrefs.get(0);
	}
	
	
	private Element getXSDEle(Element startElement, String path) throws WADLSException{
		if (path == null || path == "")
			return startElement;
		String eleName = startElement.getLocalName();
		if (eleName.equals("element")){					//search the target from <element ...
			return SchemaUtils.findXSDEleOnEle(startElement, path, this);
		}
		else if (eleName.equals("complexType")){			//search the target from <complexType ...
			return SchemaUtils.findXSDEleOnComplexType(startElement, path, this);
		}
		else{												//error
			WADLSException wsdlsExc = new WADLSException(WADLSException.PATH_ERROR, 
			"simpleType cannot has path");
			throw wsdlsExc;
		}
	}
	

	
	/**
	 * Get all the extensibility elements defined here.
	 */

	/**
	 * Set the modelReference.
	 *
	 * @param modelReference The desired modelReference.
	 */
	public void addModelReference(ModelReference modelReference){
		if(modelReferences == null)
			modelReferences = new ArrayList<ModelReference>();
		modelReferences.add(0, modelReference);
	}
	
	public List<ModelReference> getModelReferences() {
		return modelReferences;
	}
	
	public void setModelReferences(List<ModelReference> refs) {
		modelReferences = refs;		
	}
	
	/**
	 * Set the documentation element for this document. This dependency
	 * on org.w3c.dom.Element should eventually be removed when a more
	 * appropriate way of representing this information is employed.
	 *
	 * @param docEl the documentation element
	 */
	public void setDocumentationElement(Element docEl)
	{
		this.docEl = docEl;
	}
	
	public void setModelReferences(Element startElement, String path, List<ModelReference> refs) throws WADLSException {
		for(ModelReference ref : refs) {
			addModelReference(startElement, path, ref);
		}
	}
	
	public void addModelReference(Element startElement, String path, ModelReference modelReference) throws WADLSException{
		Element el = getXSDEle(startElement, path);
		
		if (modelReference != null){
			String strModelReference = modelReference.value();
			Attr attr = el.getAttributeNodeNS(
					Constants.NS_URI_WADLS, Constants.ATTR_MODELREF);
			if(attr == null) {
				attr = el.getOwnerDocument().createAttributeNS(Constants.NS_URI_WADLS, Constants.ATTR_MODELREF);
				attr.setPrefix(Constants.PREFIX_WSDLS);
				el.setAttributeNodeNS(attr);
			}
			String value = attr.getValue();
			if(value != null) {
				value += " " + strModelReference;
			} else {
				value = strModelReference;
			}
			attr.setValue(value);
			modelReference.setParent(el);
		}
		else
			el.removeAttributeNS(Constants.NS_URI_WADLS, Constants.ATTR_MODELREF);
	}
	
	
	/**
	 * Get the documentation element. This dependency on org.w3c.dom.Element
	 * should eventually be removed when a more appropriate way of
	 * representing this information is employed.
	 *
	 * @return the documentation element
	 */
	public Element getDocumentationElement()
	{
		return docEl;
	}
	
	public void setLoweringSchemaMapping(Element startElement, String path, String schemaMapping) throws WADLSException{
		Element el = getXSDEle(startElement, path);
		if (schemaMapping != null){
			Attr attr = el.getOwnerDocument().createAttributeNS(Constants.NS_URI_WADLS, Constants.ATTR_LOWERINGSCHEMAMAPPING);
			attr.setPrefix(Constants.PREFIX_WSDLS);
			attr.setValue(schemaMapping);
			el.setAttributeNodeNS(attr);
		}
		else
			el.removeAttributeNS(Constants.NS_URI_WADLS, Constants.ATTR_LOWERINGSCHEMAMAPPING);
	}
	
	public void setLiftingSchemaMapping(Element startElement, String path, String schemaMapping) throws WADLSException{
		Element el = getXSDEle(startElement, path);
		if (schemaMapping != null){
			Attr attr = el.getOwnerDocument().createAttributeNS(Constants.NS_URI_WADLS, Constants.ATTR_LIFTINGSCHEMAMAPPING);
			attr.setPrefix(Constants.PREFIX_WSDLS);
			attr.setValue(schemaMapping);
			el.setAttributeNodeNS(attr);
		}
		else
			el.removeAttributeNS(Constants.NS_URI_WADLS, Constants.ATTR_LIFTINGSCHEMAMAPPING);
	}
	public String getLoweringSchemaMapping(Element startElement, String path) throws WADLSException{
		Element el = getXSDEle(startElement, path);
		if (el == null)
			return null;
		String attrSchemaMapping = el.getAttributeNS(Constants.NS_URI_WADLS, Constants.ATTR_LOWERINGSCHEMAMAPPING);
		if (attrSchemaMapping == "")
			return null;
		return attrSchemaMapping;
		
	}
	
	public String getLiftingSchemaMapping(Element startElement, String path) throws WADLSException{
		Element el = getXSDEle(startElement, path);
		if (el == null)
			return null;
		String attrSchemaMapping = el.getAttributeNS(Constants.NS_URI_WADLS, Constants.ATTR_LIFTINGSCHEMAMAPPING);
		if (attrSchemaMapping == "")
			return null;
		return attrSchemaMapping;
		
	}
	

	/**
	 * Add an extensibility element.
	 *
	 * @param extElement the extensibility element to be added
	 */
	
	
	/**
	 * Get all the extensibility elements defined here.
	 */

	
	public String toString()
	{
		StringBuffer strBuf = new StringBuffer();
		
		strBuf.append("Types:");
		
		if (extElements != null)
		{
			Iterator extIterator = extElements.iterator();
			
			while (extIterator.hasNext())
			{
				strBuf.append("\n" + extIterator.next());
			}
		}
		
		return strBuf.toString();
	}
	
	
}
