package ajcon.helpers;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class BeanGenerator {
    
    private Map<String, String> variables;
    public String logs="";
    private Object topObject;
    private String filePath;
    private String outputPath;
    private String fileName;

    public BeanGenerator(String filePath, String outputPath, Object topObject, Map<String, String> variables) throws IOException {
        this.filePath = filePath;
        this.topObject = topObject;
        this.outputPath = outputPath;
        this.variables = variables;

        fileName = filePath.substring(filePath.lastIndexOf("\\"), filePath.length());
    }

    
    public void generate() throws IOException{
        CharBuffer cb = readFileIntoBuffer(filePath);
        /* add import and @ManagedBean */
        Pattern pattern = Pattern.compile("((import).+(;)(\\s)+)", Pattern.CASE_INSENSITIVE);
	Matcher matcher =  pattern.matcher(cb);
	boolean result = matcher.find();

        int start,end = 0;
        while(result){
            end = matcher.end();
            result = matcher.find();
        }

        String a = "import javax.faces.bean.ManagedBean;\n@ManagedBean\n";
        File w = new File(outputPath + fileName);
        BufferedWriter bw = new BufferedWriter(new FileWriter(w));
        bw.write(cb.toString().substring(0,end));
        bw.write(a);

        logs += "\tImports and @ManagedBean annotation was added.\n";

        /* replace init with constructor */
        pattern = Pattern.compile("(void(\\s)+init)", Pattern.CASE_INSENSITIVE);
        matcher = pattern.matcher(cb);
        result = matcher.find();

        start = matcher.start();

    
        bw.write(cb.toString().substring(end, start));
        bw.write(fileName.substring(1,fileName.indexOf(".")));

        logs += "\tinit() function was replaced by bean constructor. \n";

        /*****************************************************/

        end = matcher.end();

        /* generate getter and setters */
        int lastCurlyIndex = 0;
        pattern = Pattern.compile("(\\})", Pattern.CASE_INSENSITIVE);
        matcher = pattern.matcher(cb);
        result = matcher.find();
        while(result){
            lastCurlyIndex = matcher.start();
            result = matcher.find(); 
        }

        bw.write(cb.toString().substring(end,lastCurlyIndex));

        StringBuffer getSetString=new StringBuffer();
        Set maps = variables.keySet();
        Iterator iter = maps.iterator();

        while(iter.hasNext()){
            String varName =(String) iter.next();
            String typeName = variables.get(varName);

            pattern = Pattern.compile("(public\\s+"+typeName +"\\s+get"+ varName +"\\s*\\(\\s*\\))", Pattern.CASE_INSENSITIVE);
            matcher = pattern.matcher(cb);
            result = matcher.find();

            if(!result){
                getSetString.append("\tpublic " + typeName + " get"+ varName + "(){\n\t\treturn this."+ varName + ";\n\t}\n");
                logs += "\tGetter was created for "+ typeName + ": "+ varName +"\n";
            }

            pattern = Pattern.compile("(public\\s+void\\s+set"+ varName +"\\s*\\("+ typeName +"\\s+\\w+\\s*\\))", Pattern.CASE_INSENSITIVE);
            matcher = pattern.matcher(cb);
            result = matcher.find();

            if(!result){
                getSetString.append("\tpublic void set"+ varName + "(" + typeName + " a){\n\t\tthis."+ varName + " = a;\n\t}\n");
                logs += "\tSetter was created for "+ typeName + ": "+ varName +"\n";
            }

        }

         bw.write(getSetString.toString() + "\n");
         /***********************************************************/

         /* actionPerformed */
         pattern = Pattern.compile("public\\s+void\\s+actionPerformed\\s*\\(\\s*ActionEvent\\s+((\\w+))\\s*\\)\\s*\\{", Pattern.CASE_INSENSITIVE);
         matcher = pattern.matcher(cb);
         result = matcher.find();

         if(result){ // actionPerformed basi
             end = matcher.end();
             String eventName = matcher.group(1);
             
             int funcEnd = 1;

             pattern = Pattern.compile("(\\{|\\})", Pattern.CASE_INSENSITIVE);
             matcher = pattern.matcher(cb);
             result = matcher.find(end);
             while(result){
                if(cb.charAt(matcher.start())=='{')
                    funcEnd++;
                else if (cb.charAt(matcher.start())=='}')
                    funcEnd--;

                if (funcEnd==0)
                    break;
                result = matcher.find();
             }

             /* replace block with jsf action event functions */
             String actionPerfBlock = cb.toString().substring(end, matcher.start());
             pattern = Pattern.compile( eventName + "\\.getSource\\(\\)\\s*==\\s*((\\w+))", Pattern.CASE_INSENSITIVE);
             matcher = pattern.matcher(cb);
             result = matcher.find(end);

             while(result){
                 String objectName = matcher.group(1);
                 actionPerfBlock = actionPerfBlock.replaceAll(eventName + "\\.getSource\\(\\)\\s*==\\s*("+ objectName +")", eventName + ".getComponent().getId().equals(\"" + objectName + "\")");
                 result = matcher.find();
             }


             bw.write("\tpublic void actionPerformed2 (javax.faces.event.ActionEvent "+ eventName +") {" + actionPerfBlock + "}\n");

             logs += "\tactionPerformed() function was rewritten in actionPerformed2().\n";
             logs +="\t\tjava.awt.event.ActionEvent was replaced by javax.faces.event.\n";
             logs +="\t\tIf getSource() function was used in ActionEvent, code was modified for javax.faces.event.ActionEvent.\n";
        }

         bw.write("}");
         bw.close();

    }


    private CharBuffer readFileIntoBuffer(String filename) throws IOException {
            File f ;
            FileInputStream fis;
            FileChannel fc;
            CharBuffer cb = null ;

            f = new File(filename);
            fis = new FileInputStream(f);
            fc = fis.getChannel();

            // Get a CharBuffer from the source file
            ByteBuffer bb = fc.map(FileChannel.MapMode.READ_ONLY, 0, (int)fc.size());
            Charset cs = Charset.forName("8859_9");
            CharsetDecoder cd = cs.newDecoder();
            cb = cd.decode(bb);
            fis.close();
            fc.close();


            return cb;
    }


}
