 package main;
 
 import java.awt.Color;
 import java.awt.Container;
 import java.awt.Dimension;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.awt.event.ComponentAdapter;
 import java.awt.event.ComponentEvent;
 import java.awt.event.KeyEvent;
 import java.awt.event.KeyListener;
 import java.awt.event.WindowEvent;
 import java.awt.image.BufferedImage;
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.PrintStream;
 import java.util.ArrayList;
 import javax.imageio.ImageIO;
 import javax.swing.JFileChooser;
 import javax.swing.JMenu;
 import javax.swing.JMenuBar;
 import javax.swing.JMenuItem;
 import javax.swing.JOptionPane;
 import javax.swing.JTabbedPane;
 import javax.swing.KeyStroke;
 import javax.swing.UIManager;
 import javax.swing.event.ChangeEvent;
 import javax.swing.filechooser.FileFilter;
 import save.Filter;
 import save.Slot;
 import signals.AsyncBus;
 import signals.AsyncSignal;
 import signals.Clock;
 import signals.Signals;
 import signals.SyncBus;
 import signals.SyncSignal;
 import useful.ButtonTabComponent;
 
 public class ChronoWindow extends javax.swing.JFrame implements KeyListener, javax.swing.event.ChangeListener
 {
   private static final long serialVersionUID = 1L;
   public static int WIDTH = 800;
   public static int HEIGHT = 500;
   
   public static ArrayList<ChronoPanel> chrono = new ArrayList();
   public static int active = 0;
   
   public static JTabbedPane tabs;
   private JMenuBar menuBar = new JMenuBar();
   JFileChooser docChooser = new JFileChooser();
   JFileChooser imgChooser = new JFileChooser();
   
   private JMenu file = new JMenu("File");
   private JMenuItem file_new = new JMenuItem("New");
   private JMenuItem file_open = new JMenuItem("Open");
   private JMenuItem file_save = new JMenuItem("Save");
   private JMenuItem file_save_as = new JMenuItem("Save As..");
   private JMenuItem file_export = new JMenuItem("Export to..");
   private JMenuItem file_quit = new JMenuItem("Quit");
   
   private JMenu add = new JMenu("Add");
   private JMenuItem add_clock = new JMenuItem("Clock");
   private JMenuItem add_sync_signal = new JMenuItem("Synchronous Signal");
   private JMenuItem add_sync_bus = new JMenuItem("Synchronous Bus");
   private JMenuItem add_async_signal = new JMenuItem("Asynchronous Signal");
   private JMenuItem add_async_bus = new JMenuItem("Asynchronous Bus");
   
   private JMenu tools = new JMenu("Tools");
   private JMenu tools_timeLapse = new JMenu("Time Lapse");
   private JMenuItem tools_timeLapse_add = new JMenuItem("Add");
   private JMenuItem tools_timeLapse_removeAll = new JMenuItem("Remove all");
   private JMenu tools_back_lines = new JMenu("Background Lines");
   private JMenuItem tools_back_lines_show = new JMenuItem("Show/Hide");
   private JMenu tools_antialiasing = new JMenu("Antialiasing");
   private JMenuItem tools_antialiasing_on = new JMenuItem("On/Off");
   private JMenu tools_assertion = new JMenu("Assertion");
   private JMenuItem tools_assertion_add = new JMenuItem("Add");
   private JMenuItem tools_assertion_delete_all = new JMenuItem("Delete All");
   
   public ChronoWindow() {
     setTitle("Chronogram Editor v" + Main.version);
     setSize(WIDTH, HEIGHT);
     setLocationRelativeTo(null);
     addKeyListener(this);
     
 
 
     UIManager.put("TabbedPane.borderHightlightColor", Color.BLACK);
     UIManager.put("TabbedPane.contentAreaColor", Color.WHITE);
     UIManager.put("TabbedPane.selected", Color.WHITE);
     
     tabs = new JTabbedPane();
     tabs.addChangeListener(this);
     tabs.setFocusable(false);
     
     this.docChooser.addChoosableFileFilter(new Filter(".chr", "Chronogram File"));
     this.imgChooser.addChoosableFileFilter(new Filter(".jpg, .png, .gif", ""));
     
     addComponentListener(new ComponentAdapter() {
       public void componentResized(ComponentEvent e) {
         String sizeA = e.paramString().split(" ")[2];
         String size = "";
         for (int i = 0; i < sizeA.length(); i++) {
           if (sizeA.charAt(i) != ')') size = size + sizeA.charAt(i);
         }
         ChronoWindow.WIDTH = Integer.parseInt(size.split("x")[0]);
         ChronoWindow.HEIGHT = Integer.parseInt(size.split("x")[1]);
         ChronoWindow.this.repaint();
       }
     });
     setDefaultCloseOperation(0);
     addWindowListener(new java.awt.event.WindowAdapter() {
       public void windowClosing(WindowEvent e) {
         ChronoWindow.this.quit();
       }
       
     });
     this.file_new.setAccelerator(KeyStroke.getKeyStroke(78, 2));
     this.file.add(this.file_new);
     this.file_open.setAccelerator(KeyStroke.getKeyStroke(79, 2));
     this.file.add(this.file_open);
     this.file_save.setAccelerator(KeyStroke.getKeyStroke(83, 2));
     this.file.add(this.file_save);
     this.file.add(this.file_save_as);
     this.file.addSeparator();
     this.file_export.setAccelerator(KeyStroke.getKeyStroke(69, 2));
     this.file.add(this.file_export);
     this.file.addSeparator();
     this.file.add(this.file_quit);
     
     this.add.add(this.add_clock);
     this.add.addSeparator();
     this.add.add(this.add_sync_signal);
     this.add.add(this.add_sync_bus);
     this.add.addSeparator();
     this.add.add(this.add_async_signal);
     this.add.add(this.add_async_bus);
     
 
     this.tools_timeLapse.add(this.tools_timeLapse_add);
     this.tools_timeLapse.add(this.tools_timeLapse_removeAll);
     this.tools.add(this.tools_timeLapse);
     this.tools_back_lines.add(this.tools_back_lines_show);
     this.tools.add(this.tools_back_lines);
     this.tools_antialiasing.add(this.tools_antialiasing_on);
     this.tools.add(this.tools_antialiasing);
     this.tools_assertion.add(this.tools_assertion_add);
     this.tools_assertion.add(this.tools_assertion_delete_all);
     this.tools.add(this.tools_assertion);
     
     initButtons();
     
     this.menuBar.add(this.file);
     this.menuBar.add(this.add);
     this.menuBar.add(this.tools);
     
 
 
     setJMenuBar(this.menuBar);
     getContentPane().add(tabs);
     
     setVisible(true);
   }
   
   public void initButtons() {
     this.file_new.addActionListener(new ActionListener() {
       public void actionPerformed(ActionEvent arg0) {
         ChronoWindow.this.newChrono();
         ChronoWindow.this.repaint();
       }
       
     });
     this.file_open.addActionListener(new ActionListener() {
       public void actionPerformed(ActionEvent arg0) {
         ChronoWindow.this.docChooser.setCurrentDirectory(new File("."));
         
         if (ChronoWindow.this.docChooser.showOpenDialog(null) == 0) {
           File choosenFile = ChronoWindow.this.docChooser.getSelectedFile();
           if (ChronoWindow.this.docChooser.getFileFilter().accept(choosenFile)) {
             ChronoWindow.this.newChrono();
             Slot.load(choosenFile);
             int maxId = 0;
             for (int i = 0; i < ((ChronoPanel)ChronoWindow.chrono.get(ChronoWindow.active)).signals.size(); i++) {
               maxId = Math.max(maxId, ((Signals)((ChronoPanel)ChronoWindow.chrono.get(ChronoWindow.active)).signals.get(i)).id);
             }
             Signals.setIdBank(maxId + 1);
             ((ChronoPanel)ChronoWindow.chrono.get(ChronoWindow.active)).openedFile = choosenFile;
             ((ChronoPanel)ChronoWindow.chrono.get(ChronoWindow.active)).saveFileOk = true;
             ChronoWindow.this.changeActiveTabTitle(choosenFile.getName());
           }
           else {
             JOptionPane.showMessageDialog(null, "File extension did not match \nExptected .chr", "Error", 0);
           }
         }
         ChronoWindow.this.repaint();
       }
       
     });
     this.file_save.addActionListener(new ActionListener() {
       public void actionPerformed(ActionEvent arg0) {
         ChronoWindow.this.save(false, ChronoWindow.active);
       }
       
     });
     this.file_save_as.addActionListener(new ActionListener() {
       public void actionPerformed(ActionEvent arg0) {
         ChronoWindow.this.save(true, ChronoWindow.active);
       }
       
     });
     this.file_export.addActionListener(new ActionListener() {
       public void actionPerformed(ActionEvent arg0) {
         ChronoWindow.this.export();
       }
       
     });
     this.file_quit.addActionListener(new ActionListener() {
       public void actionPerformed(ActionEvent arg0) {
         ChronoWindow.this.quit();
       }
       
     });
     this.add_clock.addActionListener(new ActionListener() {
       public void actionPerformed(ActionEvent arg0) {
         DialogBox db = new DialogBox(null, "Add clock", new Clock(""));
         db.showDialog();
         if (db.name != null) {
           if ((db.clockDomain != -1) && (db.ratio > 0.0F)) {
             ((ChronoPanel)ChronoWindow.chrono.get(ChronoWindow.active)).add(new Clock(db.name, db.freq, db.clockDomain, db.ratio));
           }
           else {
             ((ChronoPanel)ChronoWindow.chrono.get(ChronoWindow.active)).add(new Clock(db.name, db.freq));
           }
           
         }
       }
     });
     this.add_sync_signal.addActionListener(new ActionListener() {
       public void actionPerformed(ActionEvent arg0) {
         DialogBox db = new DialogBox(null, "Add synchronous signal", new SyncSignal(""));
         db.showDialog();
         if (db.name != null) { ((ChronoPanel)ChronoWindow.chrono.get(ChronoWindow.active)).add(new SyncSignal(db.name, db.clockDomain));
         }
       }
     });
     this.add_sync_bus.addActionListener(new ActionListener() {
       public void actionPerformed(ActionEvent arg0) {
         DialogBox db = new DialogBox(null, "Add synchronous bus", new SyncBus(""));
         db.showDialog();
         if (db.name != null) { ((ChronoPanel)ChronoWindow.chrono.get(ChronoWindow.active)).add(new SyncBus(db.name, db.clockDomain));
         }
       }
     });
     this.add_async_signal.addActionListener(new ActionListener() {
       public void actionPerformed(ActionEvent arg0) {
         DialogBox db = new DialogBox(null, "Add asynchronous signal", new AsyncSignal(""));
         db.showDialog();
         if (db.name != null) { ((ChronoPanel)ChronoWindow.chrono.get(ChronoWindow.active)).add(new AsyncSignal(db.name, db.freq));
         }
       }
     });
     this.add_async_bus.addActionListener(new ActionListener() {
       public void actionPerformed(ActionEvent arg0) {
         DialogBox db = new DialogBox(null, "Add asynchronous bus", new AsyncBus(""));
         db.showDialog();
         if (db.name != null) { ((ChronoPanel)ChronoWindow.chrono.get(ChronoWindow.active)).add(new AsyncBus(db.name, db.freq));
         }
       }
     });
     this.tools_timeLapse_add.addActionListener(new ActionListener() {
       public void actionPerformed(ActionEvent arg0) {
         if (((ChronoPanel)ChronoWindow.chrono.get(ChronoWindow.active)).nbrTimeLapse < 5) {
           ((ChronoPanel)ChronoWindow.chrono.get(ChronoWindow.active)).addTimeLapse();
           ChronoWindow.this.repaint();
         }
         else {
           JOptionPane.showMessageDialog(null, "Can not set more than 5 timelapses", "Error", 0);
         }
         
       }
       
     });
     this.tools_timeLapse_removeAll.addActionListener(new ActionListener() {
       public void actionPerformed(ActionEvent arg0) {
         ((ChronoPanel)ChronoWindow.chrono.get(ChronoWindow.active)).removeTimeLapse();
         ChronoWindow.this.tools_timeLapse_add.setEnabled(true);
         ChronoWindow.this.repaint();
       }
       
     });
     this.tools_back_lines_show.addActionListener(new ActionListener() {
       public void actionPerformed(ActionEvent arg0) {
         ((ChronoPanel)ChronoWindow.chrono.get(ChronoWindow.active)).displayBackLines = (!((ChronoPanel)ChronoWindow.chrono.get(ChronoWindow.active)).displayBackLines);
         ((ChronoPanel)ChronoWindow.chrono.get(ChronoWindow.active)).modifToSave = true;
         ChronoWindow.this.repaint();
       }
       
     });
     this.tools_antialiasing_on.addActionListener(new ActionListener() {
       public void actionPerformed(ActionEvent arg0) {
         ((ChronoPanel)ChronoWindow.chrono.get(ChronoWindow.active)).antialiasing = (!((ChronoPanel)ChronoWindow.chrono.get(ChronoWindow.active)).antialiasing);
         ((ChronoPanel)ChronoWindow.chrono.get(ChronoWindow.active)).modifToSave = true;
         ChronoWindow.this.repaint();
       }
       
     });
     this.tools_assertion_add.addActionListener(new ActionListener() {
       public void actionPerformed(ActionEvent arg0) {
         ((ChronoPanel)ChronoWindow.chrono.get(ChronoWindow.active)).newAssertion();
         ((ChronoPanel)ChronoWindow.chrono.get(ChronoWindow.active)).modifToSave = true;
         ChronoWindow.this.repaint();
       }
       
     });
     this.tools_assertion_delete_all.addActionListener(new ActionListener() {
       public void actionPerformed(ActionEvent arg0) {
         ((ChronoPanel)ChronoWindow.chrono.get(ChronoWindow.active)).removeAssertions();
         ((ChronoPanel)ChronoWindow.chrono.get(ChronoWindow.active)).modifToSave = true;
         ChronoWindow.this.repaint();
       }
     });
   }
   
   public void quit() {
     boolean okToQuit = true;
     
     for (int i = 0; i < chrono.size(); i++) {
       if (((ChronoPanel)chrono.get(i)).modifToSave) { okToQuit = false;
       }
     }
     if (!okToQuit) {
       int option = JOptionPane.showConfirmDialog(null, "Some chronograms are not saved.\nExit Chronogram Editor ?", "Confirm exit", 1, 3);
       if ((option != 2) && (option != -1) && 
         (option == 0)) {
         System.exit(0);
       }
     }
     else
     {
       System.exit(0);
     }
   }
   
   public void export() {
     if (((ChronoPanel)chrono.get(active)).openedFile != null) {
       this.imgChooser.setCurrentDirectory(((ChronoPanel)chrono.get(active)).openedFile.getParentFile());
       this.imgChooser.setSelectedFile(new File(((ChronoPanel)chrono.get(active)).openedFile.getName().replace("chr", "png")));
     } else {
       this.imgChooser.setCurrentDirectory(new File("."));
     }
     if (this.imgChooser.showSaveDialog(null) == 0) {
       File choosenFile = this.imgChooser.getSelectedFile();
       if (this.imgChooser.getFileFilter().accept(choosenFile))
       {
         ((ChronoPanel)chrono.get(active)).releaseSelection();
         
         BufferedImage bufImg = new BufferedImage((int)((ChronoPanel)chrono.get(active)).getSize().getWidth(), (int)((ChronoPanel)chrono.get(active)).getSize().getHeight(), 5);
         java.awt.Graphics g = bufImg.getGraphics();
         ((ChronoPanel)chrono.get(active)).paint(g);
         try {
           if (choosenFile.getName().endsWith("jpg")) ImageIO.write(bufImg, "JPG", choosenFile);
           if (choosenFile.getName().endsWith("png")) ImageIO.write(bufImg, "PNG", choosenFile);
           if (!choosenFile.getName().endsWith("gif")) return; ImageIO.write(bufImg, "GIF", choosenFile);
         } catch (FileNotFoundException e) {
           JOptionPane.showMessageDialog(null, "File directory error", "Error", 0);
         } catch (IOException e) {
           JOptionPane.showMessageDialog(null, "Error during exportation", "Error", 0);
         }
       }
       else {
         JOptionPane.showMessageDialog(null, "File extension error", "Error", 0);
       }
     }
   }
   
   public void save(boolean saveAs, int chronoIndex) {
     if ((((ChronoPanel)chrono.get(chronoIndex)).saveFileOk) && (!saveAs)) {
       Slot.save(((ChronoPanel)chrono.get(chronoIndex)).openedFile);
       ((ChronoPanel)chrono.get(chronoIndex)).modifToSave = false;
     }
     else {
       if (((ChronoPanel)chrono.get(chronoIndex)).openedFile != null) {
         this.docChooser.setCurrentDirectory(((ChronoPanel)chrono.get(chronoIndex)).openedFile.getParentFile());
         this.docChooser.setSelectedFile(new File(((ChronoPanel)chrono.get(active)).openedFile.getName()));
       } else {
         this.docChooser.setCurrentDirectory(new File("."));
       }
       if (this.docChooser.showSaveDialog(null) == 0) {
         File choosenFile = this.docChooser.getSelectedFile();
         
         String[] tmp = choosenFile.getName().split("[.]");
         String ext = "";
         if (tmp.length == 2) { ext = tmp[1];
         }
         
         if (ext == "") {
           choosenFile = new File(choosenFile.getPath() + ".chr");
           System.out.println(choosenFile.getPath());
         }
         
         if (this.docChooser.getFileFilter().accept(choosenFile)) {
           Slot.save(choosenFile);
           ((ChronoPanel)chrono.get(chronoIndex)).modifToSave = false;
           ((ChronoPanel)chrono.get(chronoIndex)).saveFileOk = true;
           ((ChronoPanel)chrono.get(chronoIndex)).openedFile = choosenFile;
           changeActiveTabTitle(choosenFile.getName());
         }
         else {
           JOptionPane.showMessageDialog(null, "File extension error", "Error", 0);
         }
       }
     }
     checkModifToSave();
   }
   
   public void newChrono() {
     chrono.add(new ChronoPanel());
     active = chrono.size() - 1;
     tabs.addTab("New", (java.awt.Component)chrono.get(active));
     tabs.setTabComponentAt(active, new ButtonTabComponent("New", active));
     tabs.setSelectedIndex(active);
     ((ChronoPanel)chrono.get(active)).saveFileOk = false;
   }
   
   public void changeActiveTabTitle(String title) {
     tabs.setTabComponentAt(active, new ButtonTabComponent(title, active));
     ((ChronoPanel)chrono.get(active)).fileName = title;
   }
   
   public void checkModifToSave() {
     if (((ChronoPanel)chrono.get(active)).modifToSave) {
       if (!((ChronoPanel)chrono.get(active)).fileName.endsWith("*")) {
         tabs.setTabComponentAt(active, new ButtonTabComponent(((ChronoPanel)chrono.get(active)).fileName + "*", active));
         ((ChronoPanel)chrono.get(active)).fileName += "*";
       }
       
     }
     else if (((ChronoPanel)chrono.get(active)).fileName.endsWith("*")) {
       ((ChronoPanel)chrono.get(active)).fileName = ((ChronoPanel)chrono.get(active)).fileName.substring(0, ((ChronoPanel)chrono.get(active)).fileName.length() - 1);
       tabs.setTabComponentAt(active, new ButtonTabComponent(((ChronoPanel)chrono.get(active)).fileName, active));
     }
   }
   
 
 
   public void keyPressed(KeyEvent e)
   {
     if (e.getKeyCode() == 127) {
       ((ChronoPanel)chrono.get(active)).removeSelected();
       repaint();
     }
   }
   
 
 
 
   public void keyReleased(KeyEvent e) {}
   
 
 
 
   public void keyTyped(KeyEvent e) {}
   
 
 
 
   public void stateChanged(ChangeEvent e)
   {
     JTabbedPane pane = (JTabbedPane)e.getSource();
     active = pane.getSelectedIndex();
   }
 }





