package graphTool;

import java.util.*;
import java.text.*;
import java.io.*;
import LogParser.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

@SuppressWarnings("serial")
public class GraphToolFrame extends JFrame
{
   JTextField tf_dateFrom;
   JTextField tf_dateTo;
   FileDisplayTableModel fileTable;
   FileDisplayTableModel exerciseTable;
   FileDisplayTableModel methodTable;
   JTable t_exercise;
   JTable t_method;
   JRadioButton agg;
   JRadioButton indiv;
   JRadioButton agg_agg;
   JRadioButton allPlots;
   JRadioButton oncampus;
   JRadioButton offcampus;
   Vector<XMLLog> logs;
   
   public GraphToolFrame()
   {
      super("TCRA Graph Generator");
      this.setIconImage(new ImageIcon("graphIcon.gif").getImage());
      this.getContentPane().setLayout(new GridLayout(5,1));
      this.setSize(640,480);
      this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      
      makeMenuBar();
      addComponents();      
      
      this.setVisible(true);
   } // end ctor
   
   private void loadFileTable(String[] names)
   {
      String fileheaders[] = {"Loaded Files"};
      String data[][] = new String[names.length][1];

      for(int i = 0; i < names.length; ++i)
         data[i][0] = names[i];
      fileTable.setDataVector(data, fileheaders);
      
      String exercise_header[] = {"Availables Exercises"};
      exerciseTable.setDataVector(new String[1][1], exercise_header);
      
      String method_header[]  = {"Exercise","Available Methods"};
      methodTable.setDataVector(new String[1][2], method_header);
   } // end loadFileTable(String[])
   
   private void loadExerciseTable()
   {
      String header[] = {"Availables Exercises"};
      Vector<String> dataVector = logs.elementAt(0).getUniqueFilenames();
      for(int i = 1; i < logs.size(); ++i)
      {
         Vector<String> temp = logs.elementAt(i).getUniqueFilenames();
         for(int j = 0; j < temp.size(); ++j)
         {
            if(!dataVector.contains(temp.elementAt(j)))
            {
               dataVector.add(temp.elementAt(j));
            } // end if
         } // end for
      } // end for
      
      String data[][] = new String[dataVector.size()][1];
      for(int i = 0; i < dataVector.size(); ++i)
         data[i][0] = dataVector.elementAt(i);
      
      exerciseTable.setDataVector(data, header);
   } // end loadExerciseTable()
   
   private void loadMethodTable()
   {
      int count = 0;
      int selected[] = t_exercise.getSelectedRows();
      String exercises[] = new String[selected.length];
      Vector<Vector<String>> methods = new Vector<Vector<String>>(selected.length);
      
      for(int i = 0; i < selected.length; ++i)
      {
         methods.add(new Vector<String>());
         exercises[i] = ((String)exerciseTable.getValueAt(selected[i], 0));
         for(int j = 0; j < logs.size(); ++j)
         {
            Vector<String> temp = logs.elementAt(j).getMethods(exercises[i]);
            for(int k = 0; k < temp.size(); ++k)
            {
               if(!methods.elementAt(i).contains(temp.elementAt(k)))
               {
                  ++count;
                  methods.elementAt(i).add(temp.elementAt(k));
               } // end if
            } // end for
         } // end for
      } // end for
      
      String header[]  = {"Exercise","Available Methods"};
      String table[][] = new String[count][2];
      count = 0;
      for(int i = 0; i < selected.length; ++i)
      {
         if(i > 0)
         {
            count += methods.elementAt(i-1).size();
         } // end if
         for(int j = 0; j < methods.elementAt(i).size(); ++j)
         {
            table[j+count][0] = exercises[i];
            table[j+count][1] = methods.elementAt(i).elementAt(j);
         } // end for
      } // end for
      methodTable.setDataVector(table, header);
   } // end loadMethodTable()
   
   private void makeGraphs()
   {
      Date from = null;
      Date to   = null;
      int choices[] = t_method.getSelectedRows();
      SimpleDateFormat sdf = new SimpleDateFormat();
      sdf.applyPattern("MM/dd/yyyy hh:mm");
      try
      {
         from = sdf.parse(tf_dateFrom.getText());
         to   = sdf.parse(tf_dateTo.getText());
      } // end try
      catch(ParseException pe)
      {
         JOptionPane.showMessageDialog(this, pe.getMessage(),
                                       "Error", JOptionPane.ERROR_MESSAGE);
         return;
      } // end catch(ParseException)
      
      int counts[][][] = new int[logs.size()][choices.length][2];
      for(int i = 0; i < logs.size(); ++i)
      {
         //System.out.println("Results for log "+i);
         for(int j = 0; j < choices.length; ++j)
         {
            String exercise = (String)methodTable.getValueAt(choices[j], 0);
            String method   = (String)methodTable.getValueAt(choices[j], 1);
            counts[i][j][0] = logs.elementAt(i).correctnessQuery(exercise, method,
                                                              true, from, to);
            counts[i][j][1] = logs.elementAt(i).correctnessQuery(exercise, method,
                                                              false, from, to);
            //System.out.println("Method "+j);
            //System.out.println("#true: "+counts[j][0]+" #false: "+counts[j][1]);
         } // end for
      } // end for
      
      if(agg.isSelected())
      {
         // Make aggregate graphs
         outputAggregate(counts);
      } // end if
      else if(indiv.isSelected())
      {
         // Make individual graphs
         outputIndividual(counts);
      } // end else if
      else if(agg_agg.isSelected())
      {
         // Make aggregate graphs of all methods selected
         outputAggregateAll(counts);
      } // end else if
      else if(allPlots.isSelected())
      {
         outputAggregate(counts);
         outputIndividual(counts);
         outputAggregateAll(counts);
      } // end else if
      
      new Thread(new GraphDisplayThread()).start();
   } // end makeGraphs()
   
   private void outputAggregate(int[][][] counts)
   {
      // one file per method - every student in the file
      // X True False
      // <student_uname> [x][y][0] [x][y][1]
      // <student_uname> [x+1][y][0] [x+1][y][1]
      for(int i = 0; i < t_method.getSelectedRows().length; ++i)
      {
         try
         {
            FileWriter fw = new FileWriter("agg_plotOf"+t_method.getValueAt(i, 1));
            fw.write("X True False\n");
         
            for(int j = 0; j < logs.size(); ++j)
            {            
               fw.write(logs.elementAt(j).getID()+" "+counts[j][i][0]+" "+counts[j][i][1]+"\n");
            } // end for (user loop)
      
            fw.flush();
            fw.close();
          } // end try
          catch(IOException ioe)
          {
             System.out.println("Could not write plot file\n"+ioe.getMessage());
          } // end catch(IOException)
          catch(Exception e)
          {
             System.out.println("Could not do something\n"+e.getMessage());
          } // end catch(Exception)
      } // end for (file loop)      
      
      for(int i = 0; i < t_method.getSelectedRows().length; ++i)
      {
         try
         {
            Process proc;
            Runtime rt = Runtime.getRuntime();
            String os = System.getProperty("os.name");
            if(os.contains("Windows"))
               proc = rt.exec("plot.bat agg_plotOf"+t_method.getValueAt(i, 1)+
                     " "+t_method.getValueAt(i, 1));
            else
               proc = rt.exec("./plot agg_plotOf"+t_method.getValueAt(i, 1)+
                                      " "+t_method.getValueAt(i, 1));
            proc.waitFor();      
         } // end try
         catch(Throwable t)
         {
         } // end catch(Throwable)
      } // end for(runtime loop)
   } // end outputAggregate(int[][][])

   private void outputIndividual(int[][][] counts)
   {
      try
      {
         for(int j = 0; j < logs.size(); ++j)
         {
            FileWriter fw = new FileWriter("ind_plotOf"+logs.elementAt(j).getID());
            fw.write("X True False\n");
      
            for(int i = 0; i < t_method.getSelectedRows().length; ++i)
            {
               String temp = (String)methodTable.getValueAt(i, 1);
               fw.write(temp);
               fw.write(" "+counts[j][i][0]+" "+counts[j][i][1]+"\n");
            } // end for (user loop)
      
            fw.flush();
            fw.close();
         
         } // end for (file loop)
      } // end try
      catch(IOException ioe)
      {
         System.out.println("Could not write plot file\n"+ioe.getMessage());
      } // end catch(IOException)
      catch(Exception e)
      {
         System.out.println("Could not do something\n"+e.getMessage());
      } // end catch(Exception)

   
      for(int i = 0; i < logs.size(); ++i)
      {
         try
         {
            Process proc;
            Runtime rt = Runtime.getRuntime();
            String os = System.getProperty("os.name");
            if(os.contains("Windows"))
               proc = rt.exec("plot.bat ind_plotOf"+ logs.elementAt(i).getID()+
                     " "+logs.elementAt(i).getID());
            else
               proc = rt.exec("./plot ind_plotOf"+ logs.elementAt(i).getID()+
                     " "+logs.elementAt(i).getID());
            proc.waitFor();      
         } // end try
         catch(Throwable t)
         {
      
         } // end catch(Throwable)
      } // end for (runtime loop)
   } // end outputIndividual(int[][][])
   
   private void outputAggregateAll(int[][][] counts)
   {
      try
      {
         FileWriter fw = new FileWriter("agg_plotOfAll");
         fw.write("X True False\n");
      
         for(int i = 0; i < t_method.getSelectedRows().length; ++i)
         {
            String temp = (String)methodTable.getValueAt(i, 1);
            
            for(int j = 0; j < logs.size(); ++j)
            {
               if(j > 0) temp = "~";
               
               fw.write(temp+" "+counts[j][i][0]+" "+counts[j][i][1]+"\n");
            } // end for (user loop)
         } // end for (file loop)      

         fw.flush();
         fw.close();
   
         Process proc;
         Runtime rt = Runtime.getRuntime();
         String os = System.getProperty("os.name");
         if(os.contains("Windows"))
            proc = rt.exec("plot.bat agg_plotOfAll AllMethods");
         else
            proc = rt.exec("./plot agg_plotOfAll AllMethods");
         proc.waitFor();
         
         //displayGraphs("agg_plotOfAll");
      } // end try
      catch(IOException ioe)
      {
         System.out.println("Could not write plot file\n"+ioe.getMessage());
      } // end catch(IOException)
      catch(Exception e)
      {
         System.out.println("Could not do something\n"+e.getMessage());
      } // end catch(Exception)
   } // end outputAggregateAll(int[][][])
      
   private void addComponents()
   {
      JButton b_files = new JButton("Choose Files.");
      b_files.addActionListener(new ActionListener()
      {
         public void actionPerformed(ActionEvent ae)
         {
            File files[] = LogUtilities.loadFile();
            if(files == null) return;
            
            String[] names = new String[files.length];
            for(int i = 0; i < names.length; ++i)
               names[i] = files[i].getName();
            
            // Load names into file table
            loadFileTable(names);
            // Create XMLLog objects from filenames
            LogParser lp = new LogParser(null);
            logs = new Vector<XMLLog>(files.length);
            for(int i = 0; i < files.length; ++i)
            {
               logs.add(lp.getLog(files[i].getPath()));
            } // end for
            // Load unique method names into exercise table
            loadExerciseTable();
         } // end actionPerformed(ActionEvent)
      });
      b_files.setPreferredSize(new Dimension(150,30));
      
      JButton b_exercises = new JButton("Choose Exercises.");
      b_exercises.addActionListener(new ActionListener()
      {
         public void actionPerformed(ActionEvent ae)
         {
            loadMethodTable();
         }
      });
      b_exercises.setPreferredSize(new Dimension(150,30));
      
      JLabel lb_date = new JLabel("Enter Date Range (MM/DD/YYYY HH:MM)");
      lb_date.setPreferredSize(new Dimension(500,30));
      lb_date.setHorizontalAlignment(SwingConstants.CENTER);
      
      tf_dateFrom = new JTextField("Beginning Date");
      tf_dateFrom.setPreferredSize(new Dimension(300,30));
      
      tf_dateTo = new JTextField("Ending Date");
      tf_dateTo.setPreferredSize(new Dimension(300,30));
      
      String fileheaders[] = {"Loaded Files"};
      fileTable = new FileDisplayTableModel(new String[1][1], fileheaders);
      JTable t_file = new JTable(fileTable);
      t_file.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
      t_file.setRowSelectionAllowed(false);
      t_file.setColumnSelectionAllowed(false);
      t_file.setPreferredScrollableViewportSize(new Dimension(100,80));
      JScrollPane sp_file = new JScrollPane(t_file);
      sp_file.setPreferredSize(new Dimension(150,80));
      
      String exerciseheaders[] = {"Available Exercises"};      
      exerciseTable = new FileDisplayTableModel(new String[1][1], exerciseheaders);
      t_exercise = new JTable(exerciseTable);
      t_exercise.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
      t_exercise.setRowSelectionAllowed(true);
      t_exercise.setColumnSelectionAllowed(false);
      t_exercise.setPreferredScrollableViewportSize(new Dimension(250,80));
      JScrollPane sp_exercise = new JScrollPane(t_exercise);
      sp_exercise.setPreferredSize(new Dimension(250,80));
      
      String methodheaders[] = {"Exercise","Available Methods"};
      methodTable = new FileDisplayTableModel(new String[1][2], methodheaders);
      t_method = new JTable(methodTable);
      t_method.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
      t_method.setRowSelectionAllowed(true);
      t_method.setColumnSelectionAllowed(false);
      t_method.setPreferredScrollableViewportSize(new Dimension(400,80));
      JScrollPane sp_method = new JScrollPane(t_method);
      sp_method.setPreferredSize(new Dimension(400,80));
      
      JPanel p1 = new JPanel();
      p1.setLayout(new GridLayout(1,2));
      JPanel p1_1 = new JPanel();
      p1_1.add(b_files);
      p1.add(p1_1);
      p1.add(sp_file);
      
      JPanel p2 = new JPanel();
      p2.setLayout(new GridLayout(1,2));
      JPanel p2_1 = new JPanel();
      p2_1.add(b_exercises);
      p2.add(p2_1);
      p2.add(sp_exercise);
      
      JPanel p2_5 = new JPanel();
      p2_5.add(sp_method);
      
      JPanel p3 = new JPanel();
      p3.add(lb_date);
      p3.add(tf_dateFrom);
      p3.add(tf_dateTo);
      
      JPanel p4 = new JPanel();
      JButton b_generate = new JButton("Generate graph(s).");
      b_generate.addActionListener(new ActionListener()
      {
         public void actionPerformed(ActionEvent ae)
         {
            makeGraphs();
         } // end actionPerformed(ActionEvent)
      });
      p4.add(b_generate);
      
      this.getContentPane().add(p1);
      this.getContentPane().add(p2);
      this.getContentPane().add(p2_5);
      this.getContentPane().add(p3);
      this.getContentPane().add(p4);
   }
   
   private void makeMenuBar()
   {
      JMenuBar mb_main = new JMenuBar();

      JMenu m_file = new JMenu("File");
      m_file.setMnemonic(KeyEvent.VK_F);
      JMenuItem mi_exit = new JMenuItem("Exit");
      mi_exit.setMnemonic(KeyEvent.VK_X);
      mi_exit.addActionListener(new ActionListener()
      {
         public void actionPerformed(ActionEvent ae)
         {
            System.exit(0);
         } // end actionPerformed(ActionEvent)
      });
      m_file.add(mi_exit);
      JMenu m_graph = new JMenu("Graph Options");
      m_graph.setMnemonic(KeyEvent.VK_G);
      
      agg   = new JRadioButton("Aggregate Results per Method", true);
      indiv = new JRadioButton("Individual Results per Student");
      agg_agg = new JRadioButton("Aggregate Results for all Methods");
      allPlots = new JRadioButton("All Available Graphs");
      ButtonGroup plots = new ButtonGroup();
      plots.add(agg);
      plots.add(indiv);
      plots.add(agg_agg);
      plots.add(allPlots);
      
      m_graph.add(agg);
      m_graph.add(indiv);
      m_graph.add(agg_agg);
      m_graph.add(allPlots);
      
      JMenu m_tools = new JMenu("Tools");
      m_tools.setMnemonic(KeyEvent.VK_T);
      JMenuItem mi_logs = new JMenuItem("Download Logs");
      mi_logs.setMnemonic(KeyEvent.VK_D);
      
      // Stupid anonymous classes and final variables
      final JFrame parent = this;
      mi_logs.addActionListener(new ActionListener()
      {
         public void actionPerformed(ActionEvent ae)
         {
            if(oncampus.isSelected())
               LogDownloader.getInstance().downloadLogs(parent, LogDownloader.ONCAMPUS);
            else if(offcampus.isSelected())
               LogDownloader.getInstance().downloadLogs(parent, LogDownloader.OFFCAMPUS);
         } // end actionPerformed(ActionEvent)
      });
      
      // Change server address based on which is selected
      oncampus = new JRadioButton("On Campus Access", true);
      offcampus = new JRadioButton("Off Campus Access");
      ButtonGroup network = new ButtonGroup();
      network.add(oncampus);
      network.add(offcampus);
      
      m_tools.add(oncampus);
      m_tools.add(offcampus);
      m_tools.add(mi_logs);      

      mb_main.add(m_file);
      mb_main.add(m_graph);
      mb_main.add(m_tools);

      this.setJMenuBar(mb_main);
   } // end makeMenuBar()
} // end class
