package ajcon.UI;

import ajcon.helpers.ElementIDContainer;
import ajcon.helpers.ElementMappingBuilder;
import ajcon.helpers.EnumMappingBuilder;
import java.lang.reflect.*;
import java.util.Stack;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public class GeneralManager extends DefaultHandler{

    private ElementMappingBuilder emb;
    private EnumMappingBuilder enumMappingBuilder;
    public ElementIDContainer container;
    private Stack<Object> allElements;
    public Object topObject;

    public String classId;
    public String outputPath;

    
    public GeneralManager(String output)
    {
        container = new ElementIDContainer();
        allElements = new Stack<Object>();
        emb = new ElementMappingBuilder();
        emb.createElementMappings();
        enumMappingBuilder = new EnumMappingBuilder();
        enumMappingBuilder.createEnumMappings();
        outputPath = output;
    }


    	@Override
	public void startElement (String uri, String name,String qName, Attributes atts) throws SAXException {

            try{

            if(qName.equals("java-source-program") || qName.equals("type-dependences") ||
               qName.equals("java-class-file") || qName.equals("type-dependence") ||
               qName.equals("type-ref"))
                return;

            //Start Element okudunum, elementin adini aldim, classin bir instanceini yarattim.
            //Bu elementi stacek pushladim.

            Object stackTopObject;
            Class stackTopClass;

            String realClassName = emb.getElementHashes().get(qName);

            Class currentClass = Class.forName(realClassName);

            Object retCurrentClass = currentClass.newInstance();

            if(qName.equals("this")){  // set one top-level object's id, not push into stack
                stackTopObject = allElements.lastElement();
                stackTopClass = stackTopObject.getClass();

                int lastIndex = stackTopObject.getClass().getName().lastIndexOf('.');
                String className = stackTopObject.getClass().getName().substring(lastIndex+1);

                if(className.equals("CFieldSet")){

                    Method[] stackTopDeclaredMethods =stackTopClass.getDeclaredMethods();
                    Method setMethod = null;
                    Method getNameMethod = null;
                    for(Method stdm : stackTopDeclaredMethods)
                    {
                        if(stdm.getName().equals("setIdref"))
                        {
                            setMethod = stdm;
                        }

                         if(stdm.getName().equals("getName"))
                        {
                            getNameMethod = stdm;
                        }
                    }

                    Object fieldName = getNameMethod.invoke(stackTopObject);
                    Object setMethodArgList[] = new Object[1];
                    setMethodArgList[0] = classId + fieldName;

                    setMethod.invoke(stackTopObject, setMethodArgList);

                    return;
                }
            }

            if(!allElements.isEmpty())
            {
                stackTopObject = allElements.lastElement();
                stackTopClass = stackTopObject.getClass();

                Method[] stackTopDeclaredMethods =stackTopClass.getDeclaredMethods();
                Method stackTopGetMethod = null;
                Method stackTopSetMethod = null;


                    int lastIndex = realClassName.lastIndexOf('.');
                    String shortClassName = "";
                    String shortClassParentName = "";

                    if(lastIndex == -1)
                    {

                    }
                    else
                    {
                        shortClassName = realClassName.substring(lastIndex+1);

                        if(currentClass.getSuperclass().equals(ajcon.custom.util.groups.CStmt.class))
                        {
                            int lastParentIndex = realClassName.lastIndexOf('.');
                            shortClassParentName = "CStmt";
                        }

                        String getMethodName = "get" + shortClassName;
                        String setMethodName = "set" + shortClassName;
                        String addMethodName = "add" + shortClassName;


                        String getParentMethodName = "get" + shortClassParentName;
                        String setParentMethodName = "set" + shortClassParentName;
                        String addParentMethodName = "add" + shortClassParentName;


                        Method getMethod = null;
                        Method setMethod = null;
                        Method addMethod = null;


                        for(Method stdm : stackTopDeclaredMethods)
                        {
                            if(stdm.getName().equals(getMethodName))
                            {
                                getMethod = stdm;
                            }
                            else if(stdm.getName().equals(setMethodName))
                            {
                                setMethod = stdm;
                            }
                            else if(stdm.getName().equals(addMethodName))
                            {
                                addMethod = stdm;
                            }
                            else if(stdm.getName().equals(getParentMethodName))
                            {
                                getMethod = stdm;
                            }
                            else if(stdm.getName().equals(setParentMethodName))
                            {
                                setMethod = stdm;
                            }
                            else if(stdm.getName().equals(addParentMethodName))
                            {
                                addMethod = stdm;
                            }
                        }
                        //System.out.println(qName + " " + getMethodName + " " + shortClassParentName);
                        Class getMethodReturnType = getMethod.getReturnType();


                        if(getMethodReturnType.equals(java.util.List.class))
                        {
                              Object addMethodArgList[] = new Object[1];
                              addMethodArgList[0] = retCurrentClass;
                              addMethod.invoke(stackTopObject, addMethodArgList);
                        }
                        else
                        {
                              Object setMethodArgList[] = new Object[1];
                              setMethodArgList[0] = retCurrentClass;
                              setMethod.invoke(stackTopObject, setMethodArgList);
                        }

                        allElements.push(retCurrentClass);
                    }

            }
            else
            {
                allElements.push(retCurrentClass);
            }

            Method[] declaredMethods = currentClass.getDeclaredMethods();
            int attsLength = atts.getLength();

            for(int i = 0 ; i < attsLength; i++)
            {

                String attributeName = atts.getQName(i);
                String attributeValue = atts.getValue(i);

                if(qName.equals("class") && attributeName.equals("id")){
                    classId = attributeValue;
                }

                if(attributeName.equals("id")){
                    container.addObject(attributeValue,retCurrentClass);
                }
                
                int indexOfTire = attributeName.indexOf("-");
                if(indexOfTire!=-1){  // contains -
                    attributeName = attributeName.substring(0, indexOfTire) + attributeName.substring(indexOfTire+1, attributeName.length());
                }
                
                attributeName = (char)(attributeName.charAt(0) - 32) +
                                attributeName.substring(1,attributeName.length());


                String getMethodName = "get" + attributeName;
                String setMethodName = "set" + attributeName;
                Method getMethod = null;
                Method setMethod = null;

                for(Method dm : declaredMethods)
                {
                    if(dm.getName().equals(getMethodName))
                    {
                        getMethod = dm;
                    }
                    else if(dm.getName().equals(setMethodName))
                    {
                        setMethod = dm;
                    }
                }

                Class getMethodReturnType = getMethod.getReturnType();
                if(getMethodReturnType.equals(String.class))
                {
                      Object setMethodArgList[] = new Object[1];
                      setMethodArgList[0] = attributeValue;
                      setMethod.invoke(retCurrentClass, setMethodArgList);
                }
                else if(getMethodReturnType.equals(ajcon.enumerations.CModifierType.class))
                {
                      Object setMethodArgList[] = new Object[1];                   
                      setMethodArgList[0] = enumMappingBuilder.getModifierHashes().get(attributeValue);
                      setMethod.invoke(retCurrentClass, setMethodArgList);
                }
                else if(getMethodReturnType.equals(ajcon.enumerations.CNMToken.class))
                {
                      Object setMethodArgList[] = new Object[1];
                      setMethodArgList[0] = enumMappingBuilder.getTokenHashes().get(attributeValue);
                      setMethod.invoke(retCurrentClass, setMethodArgList);

                }
              }
          }

            catch(Exception ex)
            {
                ex.printStackTrace();
            }

            //Class instancei yaratma bitti. Simdi attributelari setleyecegim.
        }

	@Override
	public void endElement (String uri,String localName,String qName) throws SAXException{


            if(qName.equals("java-source-program") || qName.equals("type-dependences") ||
               qName.equals("java-class-file") || qName.equals("type-dependence") ||
               qName.equals("type-ref"))
                return;

            if(qName.equals("this")){
                Object stackTopObject = allElements.lastElement();

                int lastIndex = stackTopObject.getClass().getName().lastIndexOf('.');
                String className = stackTopObject.getClass().getName().substring(lastIndex+1);

                if(className.equals("CFieldSet"))
                    return;
            }

            Object poppedObject = allElements.pop();

            if(allElements.isEmpty())
                topObject = poppedObject;

     
        }

	@Override
	public void characters (char ch[], int start, int length) throws SAXException{

	}
}