/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package ajcon.helpers;

import ajcon.custom.util.elements.CBlock;
import ajcon.custom.util.elements.CClass;
import ajcon.custom.util.elements.CField;
import ajcon.custom.util.elements.CLabel;
import ajcon.custom.util.elements.CMethod;
import ajcon.custom.util.groups.CStmt;
import ajcon.enumerations.CModifierType;
import ajcon.enumerations.CNMToken;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;


public class Traverser {
    private ArrayList<Object> element;
    private CMethod initMethod = null;
    public ElementIDContainer elementIDContainer;
    private Map<String, Object> createdObjects;
    private Map<String, Object> createdVars;
    private Map<String, String> variables;
    private Object topObject;
    private DocWriter documentWriter;
    private String output;

    private String ourProjectPath;
    private String filePath;
    private BeanGenerator beanGenerator;

    public String logs = "";


    public Traverser(String filePath, ElementIDContainer elidc, CMethod o, Object oo, String output, String ourProjectPath) {
        topObject = oo;
        this.initMethod = o;
        this.element = new ArrayList<Object>();
        this.elementIDContainer = elidc;
        this.output = output;
        this.filePath = filePath;
        createdObjects = new HashMap<String, Object>();
        createdVars = new HashMap<String, Object>();
        variables = new HashMap<String, String>();
        documentWriter = new DocWriter(createdObjects,output, ourProjectPath);

        this.ourProjectPath = ourProjectPath;
    }

    public ArrayList<Object> getElement() {
        return element;
    }

    public void setElement(ArrayList<Object> element) {
        this.element = element;
    }

    public CMethod getInitMethod() {
        return initMethod;
    }

    public void setInitMethod(CMethod initMethod) {
        this.initMethod = initMethod;
    }

    public boolean traverse() throws IllegalAccessException, IOException{
        if(initMethod == null || elementIDContainer == null)
            return false;

        CBlock cb = initMethod.getCBlock();
        List<CLabel> clabels = cb.getCLabel();
        List<CStmt> cstmt = cb.getCStmt();

        if(!clabels.isEmpty()){
            // TODO: nothing, gelirse dolas
        }

        if(!cstmt.isEmpty()){
            for(CStmt st : cstmt){
                lookInside(st);
            }
        }

        getFields();

        logs += "UI file (.xhtml) was created. ";
        Set fieldValuesSet = createdVars.entrySet();
        if(!fieldValuesSet.isEmpty()){
            Iterator iter = fieldValuesSet.iterator();

            logs += "Converted components over "+ variables.size() +" declared fields:\n";
            while(iter.hasNext()){
                Entry entry= (Entry) iter.next();
                String varName = (String) entry.getKey();
                varName = varName.substring(varName.lastIndexOf(";")+1, varName.length());
                logs +="\t\t" + entry.getValue() + ": " + varName +"\n";
            }

        }

        beanGenerator = new BeanGenerator(filePath, output,topObject, variables);
        beanGenerator.generate();

        logs += "\tBean was created. \n";
        logs += beanGenerator.logs;

        
        documentWriter.setFileName(((CClass) topObject).getName());
        documentWriter.write();

        return true;
    }

    private void getFields(){
        List<CField> fields = ((CClass)topObject).getCField();

        for(int i=0; i<fields.size() ;i++){
            CField f = fields.get(i);
            String varName = f.getName();
            String typeName = f.getCType().getName();

            variables.put(varName, typeName);
        }
    }

    private void lookInside(Object st) throws IllegalAccessException {
        Field[] fs = st.getClass().getDeclaredFields();
        if(fs == null)  return;

        for(Field f : fs){
            
            Object fieldValue = null;
            String fieldName = f.getName();
            Class type = f.getType();


            fieldName = fieldName.substring(0,1).toUpperCase(Locale.ENGLISH) + fieldName.substring(1, fieldName.length());
            Method[] declaredMethods =st.getClass().getDeclaredMethods();
            Method getNameMethod = null;

            for(Method stdm : declaredMethods){
                if(stdm.getName().equals("get" + fieldName)){
                    getNameMethod = stdm;
                }
            }

            try {
               fieldValue  = getNameMethod.invoke(st);
                //System.out.println("FN: "+fieldName + "FV: "+fieldValue.getClass().toString());
            } catch (Exception e){
                System.out.print("ExceptionBizim: ");
                e.printStackTrace();
            }


            if (fieldValue !=null){
                if(type.equals(java.util.List.class)){
                    for(Object o : (ArrayList) fieldValue){
                        if(!o.getClass().equals(CNMToken.class) && !o.getClass().equals(CModifierType.class))
                            lookInside(o);
                    }
                }
                else if(type.equals(java.lang.String.class)){
                    if(fieldName.compareTo("Idref")==0 || fieldName.compareTo("Id")==0){
                        Object o = elementIDContainer.getReferenceTable().get(fieldValue.toString());
                        if(o instanceof CField){
                            if(!createdObjects.containsKey(fieldValue.toString())){
                                String cname = ((CClass) topObject).getName();
                                cname = cname.substring(0,1).toLowerCase() + cname.substring(1, cname.length());
                                String s = "";
                                CField cf = (CField) o;
                                
                                String typeName = cf.getCType().getName();

                                if(typeName.compareTo("JButton") == 0){
                                    s = "<h:commandButton  value=\"#{"+cname+"."+cf.getName()+".text}\" actionListener=\"#{"+cname+".actionPerformed2"+"}\" id=\""+cf.getName()+"\" />";
                                }
                                else if(typeName.compareTo("JTextField") == 0){
                                    s = "<h:inputText  value=\"#{"+cname+"."+cf.getName()+".text}\" id=\""+cf.getName()+"\" />";
                                }
                                else if(typeName.compareTo("JTextArea") == 0){
                                    s = "<h:inputTextarea  value=\"#{"+cname+"."+cf.getName()+".text}\" id=\""+cf.getName()+"\"></h:inputTextarea>";
                                }
                                else if(typeName.compareTo("JCheckBox") == 0){
                                    s = "<h:selectBooleanCheckbox value=\"#{"+ cname +"."+cf.getName()+".selected}\"  id=\""+cf.getName()+"\" />";
                                }
                                else if(typeName.compareTo("JLabel") == 0){
                                    s = "<h:outputText value=\"#{"+ cname +"."+cf.getName()+".text}\"  id=\""+cf.getName()+"\" />";
                                }

                                createdObjects.put(fieldValue.toString(), s);
                                createdVars.put(fieldValue.toString(), typeName);
                            }
                        }
                    }
                }
                else{
                    if(!fieldValue.getClass().equals(CNMToken.class) && !fieldValue.getClass().equals(CModifierType.class))
                        lookInside(fieldValue);
                }
            }

        }
    }


}
