/**
 * CobLib.java
 *
 * Created on November 19, 2001, 2:35 PM (CST)
 *
 */

package cse605;

/**
 *
 * @author  adev
 * @version 
 */

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

final class CobLib
{

  /**
   * path of the folder where images for circuitry are stored.
   */
   public static String IMAGE_PATH = "images/";
   
  /**
   * path of the temp direcory where files generated for resolving the circuit 
   * are stored.
   */
   public static String TEMP_DIR_PATH = "";

  /**
   * path of the "rm" binary on the workstation 
   */
   private static String RM = "";

  /**
   * path of the "mkdir" binary on the workstation 
   */
   private static String MDIR = "";

  /**
   * path of the prolog binary on the workstation 
   */
   private static String PROLOG_PATH = "";

  /**
   * path of the clpr binary on the workstation 
   */
   private static String CLPR_PATH = "";

  /**
   * path of the "translator" file for prolog on the workstation 
   */
   private static String TRANSLATOR_PATH = "";

  /**
   * path of the "helper" file for clpr on the workstation 
   */
   private static String HELPER_PATH = "";

  /**
   * name of the temporary COB file in temp directory
   */
   private static String TEMP_COB_FILE = "";

  /**
   * name of the temporary CLPR file in temp directory
   */
   private static String TEMP_CLPR_FILE = "";

  /**
   * name of the temporary file that contains commands to be executed 
   * on prolog
   */
   private static String TEMP_PROLOG_INPUT_FILE = "" ;

  /**
   * name of the temporary file that contains output of the commands
   * executed on prolog
   */
   private static String TEMP_PROLOG_OUTPUT_FILE = "";

  /**
   * name of the temporary file that contains commands to be executed 
   * on clpr
   */
   private static String TEMP_CLPR_INPUT_FILE = "";

  /**
   * name of the temporary file that contains output of the commands
   * executed on clpr
   */
   private static String TEMP_CLPR_OUTPUT_FILE = "";

  /**
   * path of the executable binary that interfaces circuitry with prolog/clpr 
   */
   private static String EXEFILE = "";   


  /**
   * path of the Log file
   */
   public static String COB_LOG = "";

  /**
   * Log file
   */
   private static RandomAccessFile logFile;

  /**
   * Font for all the textual displays
   */
  public static Font font = new Font("currier", Font.PLAIN, 14);


  /**
   * text containing useful output of the CLPR code
   */
  private static String output = "";

  /**
   * Constructor to ensure Uninstantiability of CobLib class.
   */
   private CobLib()
   {
   }
   
  /**
   * The array of string containing the lines of the clpr output.
   */
   private static String rows[] = new String[0] ;
   
   public static boolean runCobCode(String code)
   {
        int count = 0;
	output = "";

   	try{
    	  /* create temp cob file */
	  BufferedWriter bufWrite = new BufferedWriter(
		new OutputStreamWriter( new FileOutputStream(TEMP_COB_FILE)));
	  bufWrite.write(code);
	  bufWrite.close();
	  /* create a temp prolog-input file */
	  bufWrite = new BufferedWriter( new OutputStreamWriter( 
		new FileOutputStream(TEMP_PROLOG_INPUT_FILE)));

	  String prologText = "['"+ TRANSLATOR_PATH+"'].\ncob2clpr('"+TEMP_COB_FILE+"','"+TEMP_CLPR_FILE+"').";
	  bufWrite.write(prologText);
	  bufWrite.close();

	  /* create a temp clpr-input file */
	  bufWrite = new BufferedWriter( new OutputStreamWriter( 
		new FileOutputStream(TEMP_CLPR_INPUT_FILE)));

	  String clprText = "['"+TEMP_CLPR_FILE+"'].\ncircuit(_,_).";
	  bufWrite.write(clprText);
	  bufWrite.close();
	  
	  /* run prolog and clpr code */
	  (Runtime.getRuntime().exec(EXEFILE + " " + PROLOG_PATH +" "+ TEMP_PROLOG_INPUT_FILE +" "+ TEMP_PROLOG_OUTPUT_FILE+ " " + CLPR_PATH + " "+TEMP_CLPR_INPUT_FILE+" "+TEMP_CLPR_OUTPUT_FILE)).waitFor();


	  /* get resulting text */

	  File readFile = new File(TEMP_CLPR_OUTPUT_FILE);
	  BufferedReader bufRead = new BufferedReader( 
			new InputStreamReader (new FileInputStream (readFile)));


	  String text;
	  
	  do{
	     text = bufRead.readLine() ;
	  }
	  while( !text.startsWith("2 ?- "));


	  text = "";
	  do{
	     output += text + "\n";
	     text = bufRead.readLine();
	  }
	  while( !text.startsWith("*"));
	   

	  bufRead.close();
	}
	catch(NullPointerException npe){
           JOptionPane.showMessageDialog( null,"Failure while running Cob code.\n\nOutput cannot be interpreted\n"+npe.toString(),"ERROR", JOptionPane.ERROR_MESSAGE);  


	   output = "";
 	   return false;
	}
	catch(Exception e){
           JOptionPane.showMessageDialog(null,"Can't run the Cob code. Failure inside runCobCode function:\n"+e.toString(),"ERROR", JOptionPane.ERROR_MESSAGE); 
//	   e.printStackTrace();
 	   return false;
	}

	if(output.equals("")) return true;

	/* Parse to get separate lines from output string*/	
	StringTokenizer st = new StringTokenizer(output,"\n");
	rows = new String[st.countTokens()];
	while(st.hasMoreTokens())
	{
	    rows[count++] = st.nextToken();
	}
	
	return true;
   }
   

  /**
   * method to obtain the output of the CobCode
   */
   public static String getOutput()
   {
      /* check for blank value */

      if(output.equals("")) return "Not Available";
      else return output;
   }
   
  /**
   * method to obtain the output of the Cob code on prolog
   */
   public static String getPrologOutput()
   {
      String text = "";
      try{
         BufferedReader bufRead = new BufferedReader( new InputStreamReader (new FileInputStream (TEMP_PROLOG_OUTPUT_FILE)));
	 String tempText = "";
         do{
	   text += tempText+ "\n";
	   tempText = bufRead.readLine();
         }
         while(!tempText.equals("null"));
	 bufRead.close();
      }
      catch(NullPointerException e){ /* end of file reached */
       /* Do nothing */
      }
      catch(Exception e){ /* IO error */
          text = "Prolog output has not been generated";
      }
      
      return text;
   }

  /**
   * method to obtain the output of the CLPR code on clpr
   */
   public static String getClprOutput()
   {
      String text = "";
      try{
         BufferedReader bufRead = new BufferedReader( new InputStreamReader (new FileInputStream (TEMP_CLPR_OUTPUT_FILE)));
	 String tempText = "";
         do{
	   text += tempText+ "\n";
	   tempText = bufRead.readLine();
         }
         while(!tempText.equals("null"));
	 bufRead.close();
      }
      catch(NullPointerException e){ /* end of file reached */
       /* Do nothing */
      }
      catch(Exception e){/* IO error */
          text = "Clpr output has not been generated";     
      }
      return text;
   }

  /**
   * method to obtain the CLPR code
   */
   public static String getClprCode()
   {
      String text = "";
      try{
         BufferedReader bufRead = new BufferedReader( new InputStreamReader (new FileInputStream (TEMP_CLPR_FILE)));
	 String tempText = "";
         do{
	   text += tempText+ "\n";
	   tempText = bufRead.readLine();
         }
         while(!tempText.equals("null"));
	 bufRead.close();
      }
      catch(NullPointerException e){ /* end of file reached */
       /* Do nothing */
      }
      catch(Exception e){/* IO error */
          text = "Clpr output has not been generated";     
      }
      
      return text;
   }

  /**
   * method to obtain the value of an entity like current, resistance, voltage
   * of any electrical component on the circuit.
   */
   public static String getResult(String[] list)
   {
        String ans = "";
	HashSet ht = new HashSet();
        for(int i=0 ; i < list.length; i++)
	{
	     for(int j = 0; j < rows.length; j++)
	     {
	         boolean flag = true;
	         StringTokenizer st = new StringTokenizer(rows[j]);

	         while(st.hasMoreTokens() && flag)
		 {
	            if( (st.nextToken()).equals(list[i]))
		    {
		        ht.add( rows[j]+"\n") ;
			flag = false;
		    }
		 }
	     }
	}
	
	Iterator itr = ht.iterator() ;
	while(itr.hasNext()) ans += (String)itr.next() ;
   	return ans;
   }

  /**
   * Clears up the temporary files from temp directory by executing unix
   * "rm" command.
   */
   public static void clearUp()
   {
      try{
          Runtime.getRuntime().exec(RM + " " + TEMP_PROLOG_INPUT_FILE);
          Runtime.getRuntime().exec(RM + " " + TEMP_PROLOG_OUTPUT_FILE);
          Runtime.getRuntime().exec(RM + " " + TEMP_CLPR_INPUT_FILE);
          Runtime.getRuntime().exec(RM + " " + TEMP_CLPR_OUTPUT_FILE);
          Runtime.getRuntime().exec(RM + " " + TEMP_COB_FILE);
      }
      catch(Exception exp)
      {/* no need to worry abt this */
      }
   }
   
   
  /**
   * Sets the "temp" directory. If the temp directory does not exist, it
   * creates one in the path specified
   */
   public static void setTempDir()
   {
      JFileChooser fileDialog = new JFileChooser(".");
      fileDialog.setFileFilter(new DirectoryFilter());
      int result = fileDialog.showDialog(null, "OK");
      if ( result == JFileChooser.APPROVE_OPTION ) {
	 try {
	    String dirname = fileDialog.getSelectedFile().getName();
	    if ( dirname.equals("temp") ){
		TEMP_DIR_PATH = dirname ;
	    }
	    else /* create temp dir */
	    {
	    	(Runtime.getRuntime().exec(MDIR+" "+dirname+"/temp")).waitFor();
		TEMP_DIR_PATH = dirname +"/temp";
	    }
	    JOptionPane.showMessageDialog(null, "Path Selected : "+TEMP_DIR_PATH,
					  "Make Directory",
					  JOptionPane.INFORMATION_MESSAGE);
	  } 
	  catch (Exception exp) {
	    JOptionPane.showMessageDialog(null, "Write error: " + 
					  exp.getMessage(),
					  "Make Directory Error",
					  JOptionPane.ERROR_MESSAGE);
//	    exp.printStackTrace();
	  }      
      }
   }

   public static void setPaths(JFrame frame, String propfile)
   {
         BufferedReader bufRead;
	 try{
         bufRead = new BufferedReader( new InputStreamReader (new FileInputStream (propfile)));
	 String tempText = "";
	 int count = 0;
         do{
	   tempText = bufRead.readLine();
	   count++;
	   if(tempText!=null && tempText.startsWith("@"))
	   {
	   	StringTokenizer st = new StringTokenizer(tempText,"@= ", false);
		if(st.countTokens()!=2)
		{
		    JOptionPane.showMessageDialog(frame, "Error in Property File at line : "+count+"\nAborting ...",
					  "Properties Read Error",
					  JOptionPane.ERROR_MESSAGE);
		    System.exit(0);
		}
		else
		{
		    if(!assignPath(st.nextToken(), st.nextToken()))
		    {
			    if(JOptionPane.NO_OPTION == JOptionPane.showConfirmDialog(frame, "Unknown Property in cob.prop file at line : "+count+"\nIgnore ?",
					  "Properties Read Error",
					  JOptionPane.YES_NO_OPTION,
					  JOptionPane.ERROR_MESSAGE )
			    ) System.exit(0);
		    }
		}
	   }
         }
         while(!tempText.equals("null"));
         bufRead.close();
	
      }
      catch(NullPointerException e){ /* end of file reached */
       /* Do nothing */
      }

/*      catch (RuntimeException re){

      }
*/      
      catch(Exception e){/* IO error */
         JOptionPane.showMessageDialog(frame, "Cannot read Property file : \"cob.props\"\n"+e.toString()+"\nPath specified : "+propfile+"\n\nAborting ...",
				  "Properties Read Error",
				  JOptionPane.ERROR_MESSAGE);
	 e.printStackTrace();			  
	 System.exit(0);
      	 
      }

	 		 
      // check if the temp-directory exists at the path specified */
	if(!(new File(TEMP_DIR_PATH)).exists())
	 {
	    JOptionPane.showMessageDialog(frame, "Temp directory does not exist at the specified path.\nCreating ...",
					  "Temp Directory",
					  JOptionPane.INFORMATION_MESSAGE);
					  	      
	   try{
	    	(Runtime.getRuntime().exec(MDIR+" "+TEMP_DIR_PATH)).waitFor();
	      }
	   catch (Exception exp) {
	    JOptionPane.showMessageDialog(null, "Write error: " + 
					  exp.getMessage(),
					  "Make Directory Error",
					  JOptionPane.ERROR_MESSAGE);
	   }
	 }

      openLog();
      
      TEMP_COB_FILE = TEMP_DIR_PATH+"circuit.cob";
      TEMP_CLPR_FILE = TEMP_DIR_PATH+"circuit.clpr";
      TEMP_PROLOG_INPUT_FILE = TEMP_DIR_PATH+"prolog.in";
      TEMP_PROLOG_OUTPUT_FILE = TEMP_DIR_PATH+"prolog.out";
      TEMP_CLPR_INPUT_FILE = TEMP_DIR_PATH+"clpr.in";
      TEMP_CLPR_OUTPUT_FILE = TEMP_DIR_PATH+"clpr.out";
   }
   
   private static boolean assignPath(String name, String path)
   {
   	if(name.equals("TEMP_DIR_PATH"))  TEMP_DIR_PATH= path;
   	else if(name.equals("RM")) RM = path;
   	else if(name.equals("MDIR")) MDIR = path;
   	else if(name.equals("PROLOG_PATH")) PROLOG_PATH = path;
   	else if(name.equals("CLPR_PATH")) CLPR_PATH = path;
   	else if(name.equals("TRANSLATOR_PATH")) TRANSLATOR_PATH = path;
   	else if(name.equals("EXEFILE")) EXEFILE = path;
   	else if(name.equals("COB_LOG")) COB_LOG = path;
	else return false;
	
	return true;
   }
   
   public static void writeLog(String text)
   {
	if(logFile!=null)/* write text */
	{
	    try{
	      logFile.writeBytes(text);
	    }
	    catch(Exception e)
	    {
	       /* do nothing */
	       e.printStackTrace();
	    }
	}
   }
   
   private static void openLog()
   {
      if(COB_LOG!= null)
      {
	File file = new File(COB_LOG);
	if( !file.exists() )
	{
	    if(JOptionPane.YES_OPTION == JOptionPane.showConfirmDialog(null, "Log file \""+COB_LOG+"\" does not exist.\nCreate ?",
					  "File Not Found Error",
					  JOptionPane.YES_NO_OPTION,
					  JOptionPane.ERROR_MESSAGE ))
		{
		    try{
  		    	logFile = new RandomAccessFile(COB_LOG, "rw");
		    }
		    
		    catch(Exception exp)
		    {
		        if(JOptionPane.NO_OPTION == JOptionPane.showConfirmDialog(null, "Cannot create log file \""+COB_LOG+"\".\nContinue ?",
					  "File Create Error",
					  JOptionPane.YES_NO_OPTION,
					  JOptionPane.ERROR_MESSAGE ))
					  
					  System.exit(0);
		    }
		}// else do nothing
	
	}
	else /* if file exists */
	{
	   try{
    	    logFile = new RandomAccessFile(COB_LOG, "rw");
            logFile.seek(logFile.length());
	   }
	   catch(Exception exp)
	   {
	   	System.out.println("Can't open log file\ncheck the permissions on it\n");
	   }
        }
     }
   }
} 
