/*  CompilerOutput.java
 *
 *  Here the code within the EditPanel is compiled
 *  using the runtime environment and also run using 
 *  the same environment if compilation is successful.
 *
 *  Created on July 1, 2005, 1:54 PM
 *
 *  Author: Michael A. Piskuric (2537405) Summer 2005
 */

import Robot.*;
import java.awt.*;
import javax.swing.*;
import java.util.*;
import java.io.*;

public class Compiler extends JPanel {
   
    private TeachVAL    parent;             // parent class 
    private JTextArea   textArea;           // used for output
    private String      className = null;   // the name of the class being compiled and run
    private int         numPoints = 0;    // number of points that are automatically added
    
    // create a new compiler class and add it to the main window
    public Compiler(TeachVAL p) {
        parent = p;
        int width = parent.getWidth()-20;
        int height = (int)((parent.getHeight()-80)*.2); 			
        setPreferredSize(new Dimension(width,height));
        setBorder(BorderFactory.createTitledBorder("Output"));    
        textArea = new JTextArea((int)(height/20),(int)(width/11.25));
        textArea.setEditable(false);
        textArea.setBackground(Color.WHITE);
        JScrollPane scrollPane = new JScrollPane(textArea,JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
        add(scrollPane); 
        clear();
        parent.add(this);
    }   // end constructor
    
    // write text to the screen
    public void write(String text) {
        textArea.append(text + "\n");
    }
    
    // write an integer to the screen
    public void write(Integer i) {
        write(Integer.toString(i));
    }
    
    // clear the window
    public void clear() {
        textArea.setText("");
    }
    
    // use the java runtime environment to compile 
    // the code in the edit window
    public void compile() {
        boolean successful = false;
        clear();
        className = getClassName(); // parse out the class name
        String line;
        
        if(className != null) {
            try { 
                FileWriter out = new FileWriter(className+".java");
                out.write(insertPoints(parent.getEditPanel().getText()));
                out.close();    // write the existing text to a file
                
                // use the runtime to compile
                Process proc = Runtime.getRuntime().exec("javac -classpath Robot.jar "+className+".java",null,parent.getCWD());
                
                // get the error stream form the compilation and write it 
                // to the window if errors exist
                DataInputStream input = new DataInputStream(proc.getErrorStream());
                try {while((line = input.readLine())!= null) writeErrorLine(line);}                
                catch (IOException e) {new TVException("Error in stream");}
                
                proc.waitFor(); // wait for process to finish.
                if(proc.exitValue() == 0) successful = true;
            }catch (Exception e) {new TVException("Some sort of error in compiling.");};
        }
            
        parent.getMenu().setRun(successful);
        if(successful) {
            write("Compilation complete without any errors!");
            parent.getStatusBar().setText("Compilation Complete!");
        }
        else {
            write("Error in compilation.");
            parent.getStatusBar().setText("Error in Compilation.");
        }
        
    }   // end compile
    
    private void writeErrorLine(String line){
        int firstColon = line.indexOf(".java:");
        int secondColon = line.indexOf(":", firstColon+6);
                
        if(firstColon>0 && numPoints>0){
            int number = Integer.parseInt(line.substring(firstColon+6, secondColon));
            String text = line.substring(0, firstColon+6);
            text += number-(numPoints+2);
            text += line.substring(secondColon, line.length());            
            write(text);
        }
        else write(line);
    }
    
    // this uses the runtime environment again to execute the
    // compiled class.
    public void execute(){
        String line;
        clear();
        write("Executing...");
        parent.getStatusBar().setText("Executing...");
        
        try{
            parent.tempClosePort();     // temporarily close the port
            
            // use the runtime to run the code
            Process proc = Runtime.getRuntime().exec("java -classpath Robot.jar;comm.jar;. " + className,null,parent.getCWD());
            
            // capture the output stream and write it to the window
            DataInputStream output = new DataInputStream(proc.getInputStream());
            try {while (((line = output.readLine())!= null)) write(line);} 
            catch (IOException e) {new TVException("Error in error stream");}
            proc.waitFor(); // wait for the process.
            
            parent.reOpenPort();    // reopen the port 
            write("Execution Complete!");
            parent.getStatusBar().setText("Execution Complete!");
            parent.getStatusBar().setText("Execution Complete!");
        }catch (Exception e) {new TVException(e.getMessage());};
    }
    
    // parse out the name of the class from the given text
    private String getClassName() {
        String text = parent.getEditPanel().getText();
        int place = text.indexOf("public class");
        int space1 = text.indexOf(32,place+12);
        int space2 = text.indexOf(32,space1+2);
        int space3 = text.indexOf('{',space1+2);
                
        if(space1 > 12 && space2<space3)return text.substring(space1+1,space2);   
        else if(space1>12 && space2>space3) return text.substring(space1+1,space3);   
        else return null;
    }
    
    // take the points out of the point panel and add them to the 
    // temporary .java file so that they are compiled too
    public String insertPoints(String prog) {
        Iterator it = parent.getPointPanel().getAllPoints().iterator();
        int insertPoint = prog.indexOf("public " + getClassName())-1;       
        String temp = prog.substring(0, insertPoint) + "\t";        
        numPoints = parent.getPointPanel().getAllPoints().size();
        
        if(numPoints>0)temp += "//COMPILER GENERATED CODE; DO NOT MODIFY\n\t";
        
        while(it.hasNext()) {                     
            String text = ((Location)it.next()).toJavaString();
            temp += (text + "\n\t");
        }     
        if(numPoints>0)temp += "//COMPILER GENERATED CODE; DO NOT MODIFY\n";
        temp += "\n\t" + prog.substring(insertPoint+1, prog.length());
        return temp;
    }
}   //end compiler