/*******************************************************************************
* Copyright (c)                                                                *
*           2005   Tristan Allwood,                                            *
*           2005   Daniel Burke,                                               *
*           2005   Marc Hull,                                                  *
*           2005   Ekaterina Itskova,                                          *
*           2005   Steve Zymler                                                *
*                                                                              *
* Permission is hereby granted, free of charge, to any person obtaining a      *
* copy of this software and associated documentation files (the                *
* "Software"), to deal in the Software without restriction, including          *
* without limitation the rights to use, copy, modify, merge, publish,          *
* distribute, sublicense, and/or sell copies of the Software, and to           *
* permit persons to whom the Software is furnished to do so, subject to        *
* the following conditions:                                                    *
*                                                                              *
* The above copyright notice and this permission notice shall be included      *
* in all copies or substantial portions of the Software.                       *
*                                                                              *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS      *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF                   *
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.       *
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY         *
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,         *
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE            *
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                       *
*******************************************************************************/
package uk.ac.ic.doc.kevlar.api.programs.arguments.internal.iomapping;

import uk.ac.ic.doc.kevlar.api.programs.IProgramInfoNode;
import uk.ac.ic.doc.kevlar.core.framework.typecheck.BasicTypeClass;
import uk.ac.ic.doc.kevlar.core.framework.typecheck.IBasicTypeClass;
import uk.ac.ic.doc.kevlar.core.framework.typecheck.IInterfaceClass;
import uk.ac.ic.doc.kevlar.core.framework.typecheck.IParameteredTypeClass;
import uk.ac.ic.doc.kevlar.core.framework.typecheck.ITypeClass;
import uk.ac.ic.doc.kevlar.core.framework.typecheck.ParameteredTypeClass;
import uk.ac.ic.doc.kevlar.publicInterfaces.INode;
import uk.ac.ic.doc.kevlar.publicInterfaces.INodeID;
import uk.ac.ic.doc.kevlar.publicUtil.dom.XMLUtil;
import uk.ac.ic.doc.kevlar.publicUtil.strings.StringUtil;

/**
 * @author Daniel Burke
 *
 */
public abstract class AbstractNode implements INode, INodeHelp, Comparable<IProgramInfoNode>	
{
	private ITypeClass type;
	private String overview = "Node help";
	private INodeID id;
	
	public AbstractNode(String name, IInterfaceClass type, String pipeHelp)
	{
		setup(name, pipeHelp);
		this.type = new BasicTypeClass(type);
	}
	
	
	public AbstractNode(String name, IInterfaceClass type, String pipeHelp, String parameterName)
	{
	    setup(name, pipeHelp);
		
		if(parameterName == null || !StringUtil.isSimpleIdentifier(parameterName))
		{
			throw new IllegalArgumentException("parameterName must be" +
					" consisted of one or more alphanumeric chars or - or _");
		}
		
		this.type = new ParameteredTypeClass(parameterName, type);
	}
	
	private void setup(String name, String pipeHelp)
	{
		if(name == null)
		{
			throw new IllegalArgumentException("null param");
		}
		
		if(pipeHelp == null)
		{
			throw new IllegalArgumentException("null param");
		}
		
		if(!StringUtil.isSimpleIdentifier(name))
		{
			throw new IllegalArgumentException("name only have alphanumeric chars, - or _");
		}
		
		this.id = new NodeID(name);
		this.overview = pipeHelp;
		
	}
	
	public boolean equals(INodeID other)
	{
	    if(other == null)
	    {
	        return false;
	    }
	    return this.id.getFriendlyName().equals(other.getFriendlyName());
	}
	
	
	// TODO deb02: Try and think of a way to get this to be safe without breaking everything
	public boolean equals(Object other) {
		if(other == null)
		{
			return false;
		}
		
		/*
		if(other instanceof AbstractNode)
		{
		    return this.getName().equals(((AbstractNode)other).getName());
		}*/
		
		if(other instanceof INode)
		{
		    INode otherNode = (INode)other;
		    

		    ITypeClass otherType = otherNode.getType();
		    

		    if(otherType instanceof IBasicTypeClass
		            && !(type instanceof IBasicTypeClass))
		    {
		        return false;
		    }
		    
		    if(otherType instanceof IBasicTypeClass)
		    {
		        if(!(type instanceof IBasicTypeClass))
		        {
		            return false;
		        }
		    }
		    else
		    {
		        if(!(type instanceof IParameteredTypeClass))
		        {
		            return false;
		        }
		    }
		    
		    return getName().equals(otherNode.getName()) &&
		    	type.getTypeDependancy().equals(otherType.getTypeDependancy());
		}
		else if(other instanceof INodeID)
		{
		    INodeID otherNodeID = (INodeID)other;
		    return this.equals(otherNodeID);
		}
		
		return false;
	}
	
    public int hashCode() {
        return id.hashCode();
    }

	public INodeID getNodeID() {
		return id;
	}

	public ITypeClass getType() {
		return type;
	}
	
    public String getName() 
    {   
        return id.getFriendlyName();
    }
    
    public String toString()
    {
    	return toString(0);
    }
    
    public String toString(int depth)
    {
    	StringBuilder text = new StringBuilder();
    	depth = XMLUtil.putOpenElem(text, "pipe", depth);
    	
    	XMLUtil.putElement(text, "name", id.getFriendlyName(), depth);
    	XMLUtil.putElement(text, "type", type.getTypeDependancy().getTypeClass().getName(), depth);
    	XMLUtil.putElement(text, "pipe-help", overview, depth);
    	
    	if(type instanceof IParameteredTypeClass)
    	{
    		IParameteredTypeClass paramType = (IParameteredTypeClass)type;
    		XMLUtil.putElement(text, "param-name", paramType.getTemplateName(), depth);
    	}
    	
    	depth = XMLUtil.putCloseElem(text, "pipe", depth);
    	return text.toString();
    }
    
    public INodeHelp getNodeHelp()
    {
        return this;
    }
    
    public String getOverview()
    {
        return overview;
    }


    public int compareTo(IProgramInfoNode arg0) {
        return getName().compareTo(arg0.getName());
    }
}
