package main;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;

import javax.imageio.ImageIO;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
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.event.ChangeListener;

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;
import tools.Text;

import main.ChronoPanel;

public class ChronoWindow extends JFrame implements KeyListener,ChangeListener{

	private static final long serialVersionUID = 1L;
	public static int WIDTH=800;
	public static int HEIGHT=500;
	
	public static ArrayList<ChronoPanel> chrono = new ArrayList<ChronoPanel>();
	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 JMenuItem add_text = new JMenuItem("Text");
	private JMenuItem settings_text = new JMenuItem("Stettings text");
	
	
	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");
	
	
	private JMenu info = new JMenu("Info");
	private JMenuItem info_appli = new JMenuItem("About...");
	
	public ChronoWindow(){
		this.setTitle("Chronogram Editor - Patoche 2019 : v"+Main.version);
        this.setSize(WIDTH, HEIGHT);
        this.setLocationRelativeTo(null);
        addKeyListener(this);
        
        // Tabs Customization
        //UIManager.put("TabbedPane.background", Color.WHITE);
        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);
        
        docChooser.addChoosableFileFilter(new Filter(".chr", "Chronogram File"));
        imgChooser.addChoosableFileFilter(new Filter(".jpg, .png, .gif", ""));
        
        this.addComponentListener(new java.awt.event.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 += sizeA.charAt(i);
			    }
				WIDTH=Integer.parseInt(size.split("x")[0]);
				HEIGHT=Integer.parseInt(size.split("x")[1]);
				repaint();
			}
		});
        this.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
        this.addWindowListener(new WindowAdapter(){
	        public void windowClosing(WindowEvent e){
		        quit();
	        }
        });
        
        file_new.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N,KeyEvent.CTRL_MASK));
        this.file.add(file_new);
        file_open.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O,KeyEvent.CTRL_MASK));
        this.file.add(file_open);
        file_save.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S,KeyEvent.CTRL_MASK));
        this.file.add(file_save);
        this.file.add(file_save_as);
        this.file.addSeparator();
        file_export.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_E,KeyEvent.CTRL_MASK));
        this.file.add(file_export);
        this.file.addSeparator();
		this.file.add(file_quit);
		
		this.add.add(add_clock);
		this.add.addSeparator();
		this.add.add(add_sync_signal);
		this.add.add(add_sync_bus);
		this.add.addSeparator();
		this.add.add(add_async_signal);
		this.add.add(add_async_bus);
		this.add.addSeparator();
		this.add.add(add_text);
		this.add.add(settings_text);
		
		
		this.tools_timeLapse.add(tools_timeLapse_add);
		this.tools_timeLapse.add(tools_timeLapse_removeAll);
		this.tools.add(tools_timeLapse);
		this.tools_back_lines.add(tools_back_lines_show);
		this.tools.add(tools_back_lines);
		this.tools_antialiasing.add(tools_antialiasing_on);
		this.tools.add(tools_antialiasing);
		this.tools_assertion.add(tools_assertion_add);
		this.tools_assertion.add(tools_assertion_delete_all);
		this.tools.add(tools_assertion);
		
		this.info.add(info_appli);
		
		initButtons();
		
		this.menuBar.add(file);
		this.menuBar.add(add);
		this.menuBar.add(tools);
		this.menuBar.add(info);
		
		// Add All to Frame
		this.setJMenuBar(menuBar);
		this.getContentPane().add(tabs);
		
        this.setVisible(true);
	}
	
	public void initButtons(){
		file_new.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent arg0) {
				newChrono();
				repaint();
			}
		});
		
		file_open.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent arg0) {
				docChooser.setCurrentDirectory(new File("."));

				if(docChooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION){
					File choosenFile = docChooser.getSelectedFile();
					if(docChooser.getFileFilter().accept(choosenFile)){
						newChrono();
						Slot.load(choosenFile);
						int maxId=0;
						for(int i=0; i<chrono.get(active).signals.size(); i++){
							maxId=Math.max(maxId, chrono.get(active).signals.get(i).id);
						}
						Signals.setIdBank(maxId+1);
						chrono.get(active).openedFile=choosenFile;
						chrono.get(active).saveFileOk=true;
						changeActiveTabTitle(choosenFile.getName());
					}
					else{
						JOptionPane.showMessageDialog(null, "File extension did not match \nExptected .chr", "Error", JOptionPane.ERROR_MESSAGE);
					}
				}
				repaint();
			}
		});
		
		file_save.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent arg0) {
				save(false,active);
			}
		});
		
		file_save_as.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent arg0) {
				save(true,active);
			}
		});

		file_export.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent arg0) {
				export();
			}
		});

		file_quit.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent arg0) {
				quit();
			}
		});
		
		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){
						chrono.get(active).add(new Clock(db.name,db.freq,db.clockDomain,db.ratio));
					}
					else{
						chrono.get(active).add(new Clock(db.name,db.freq));
					}
				}
			}
		});
		
		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) chrono.get(active).add(new SyncSignal(db.name, db.clockDomain));
			}
		});
		
		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) chrono.get(active).add(new SyncBus(db.name, db.clockDomain));
			}
		});
		
		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) chrono.get(active).add(new AsyncSignal(db.name,db.freq));
			}
		});
		
		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) chrono.get(active).add(new AsyncBus(db.name,db.freq));
			}
		});
		
		
		add_text.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent arg0) 
			{
				DialogBox db = new DialogBox(null, "Add text", "text" );
				db.showDialog();
				if (db.name!=null) 
				{	
					System.out.println(db.name);
					String val = db.name;
					chrono.get(active).Text(val);
					
					//chrono.get(active).coco(true);
					
				}	
			}
		});
		
		settings_text.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent arg0) 
			{
				 //new FontChooser().show();
				 //new FontChooser02().show(new JFrame());
				 
				// http://www.java2s.com/Code/Java/Tiny-Application/AdvancedFontChooser.htm
				
				FontChooser03 dlg = new FontChooser03(new JFrame());
				dlg.show();
				Object [] retour = dlg.getDonnees();
	         	
				Font newFont = (Font)retour[0];
				Color newColor = (Color)retour[1];
				 
			}
		});
		
		
		tools_timeLapse_add.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent arg0) {
				if (chrono.get(active).nbrTimeLapse<5){
					chrono.get(active).addTimeLapse();
					repaint();
				}
				else{
					JOptionPane.showMessageDialog(null, "Can not set more than 5 timelapses", "Error", JOptionPane.ERROR_MESSAGE);
				}
				
			}
		});
		
		tools_timeLapse_removeAll.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent arg0) {
				chrono.get(active).removeTimeLapse();
				tools_timeLapse_add.setEnabled(true);
				repaint();
			}
		});
		
		tools_back_lines_show.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent arg0) {
				chrono.get(active).displayBackLines=!chrono.get(active).displayBackLines;
				chrono.get(active).modifToSave=true;
				repaint();
			}
		});
		
		tools_antialiasing_on.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent arg0) {
				chrono.get(active).antialiasing=!chrono.get(active).antialiasing;
				chrono.get(active).modifToSave=true;
				repaint();
			}
		});
		
		tools_assertion_add.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent arg0) {
				chrono.get(active).newAssertion();
				chrono.get(active).modifToSave=true;
				repaint();
			}
		});
		
		tools_assertion_delete_all.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent arg0) {
				chrono.get(active).removeAssertions();
				chrono.get(active).modifToSave=true;
				repaint();
			}
		});
	}
	
	public void quit(){
		boolean okToQuit=true;
		
		for (int i=0; i<chrono.size(); i++){
			if (chrono.get(i).modifToSave) okToQuit=false;
		}
		
		if (!okToQuit){
    		int option = JOptionPane.showConfirmDialog(null, "Some chronograms are not saved.\nExit Chronogram Editor ?", "Confirm exit", JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE);
    		if(option != JOptionPane.CANCEL_OPTION && option != JOptionPane.CLOSED_OPTION){
    			if (option == JOptionPane.OK_OPTION){
    				System.exit(0);
    			}
    		}
    	}
    	else{
    		System.exit(0);
    	}
	}
	
	public void export(){
		if (chrono.get(active).openedFile!=null){
			imgChooser.setCurrentDirectory(chrono.get(active).openedFile.getParentFile());
			imgChooser.setSelectedFile(new File(chrono.get(active).openedFile.getName().replace("chr","png")));
		}
		else imgChooser.setCurrentDirectory(new File("."));
		
		if(imgChooser.showSaveDialog(null) == JFileChooser.APPROVE_OPTION){
			File choosenFile = imgChooser.getSelectedFile();
			if(imgChooser.getFileFilter().accept(choosenFile)){
				// Release selected areas
				chrono.get(active).releaseSelection();
				// Save Image
				BufferedImage bufImg = new BufferedImage((int) chrono.get(active).getSize().getWidth(),(int) chrono.get(active).getSize().getHeight(), BufferedImage.TYPE_3BYTE_BGR); 
				Graphics g = bufImg.getGraphics();
				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")) ImageIO.write(bufImg, "GIF", choosenFile);
				} catch (FileNotFoundException e) {
					JOptionPane.showMessageDialog(null, "File directory error", "Error", JOptionPane.ERROR_MESSAGE);
				} catch (IOException e) {
					JOptionPane.showMessageDialog(null, "Error during exportation", "Error", JOptionPane.ERROR_MESSAGE);
				}
			}
			else{
				JOptionPane.showMessageDialog(null, "File extension error", "Error", JOptionPane.ERROR_MESSAGE);
			}
		}
	}
	
	public void save(boolean saveAs, int chronoIndex){
		if (chrono.get(chronoIndex).saveFileOk && !saveAs){
			Slot.save(chrono.get(chronoIndex).openedFile);
			chrono.get(chronoIndex).modifToSave=false;
		}
		else{
			if (chrono.get(chronoIndex).openedFile!=null){
				docChooser.setCurrentDirectory(chrono.get(chronoIndex).openedFile.getParentFile());
				docChooser.setSelectedFile(new File(chrono.get(active).openedFile.getName()));
			}
			else docChooser.setCurrentDirectory(new File("."));
			
			if(docChooser.showSaveDialog(null) == JFileChooser.APPROVE_OPTION){
				File choosenFile = docChooser.getSelectedFile();

				String[] tmp = choosenFile.getName().split("[.]");
				String ext = "";
				if (tmp.length==2) ext = tmp[1];
				
				// If no extension, add it
				if (ext==""){
					choosenFile = new File(choosenFile.getPath()+".chr");
					System.out.println(choosenFile.getPath());
				}
				
				if(docChooser.getFileFilter().accept(choosenFile)){
					Slot.save(choosenFile);
					chrono.get(chronoIndex).modifToSave=false;
					chrono.get(chronoIndex).saveFileOk=true;
					chrono.get(chronoIndex).openedFile=choosenFile;
					changeActiveTabTitle(choosenFile.getName());
				}
				else{
					JOptionPane.showMessageDialog(null, "File extension error", "Error", JOptionPane.ERROR_MESSAGE);
				}
			}
		}
		checkModifToSave();
	}
	
	public void newChrono(){
		chrono.add(new ChronoPanel());
		active = chrono.size()-1;
		tabs.addTab("New", chrono.get(active));
		tabs.setTabComponentAt(active, new ButtonTabComponent("New",active));
		tabs.setSelectedIndex(active);
		chrono.get(active).saveFileOk=false;
	}
	
	public void changeActiveTabTitle(String title){
		tabs.setTabComponentAt(active, new ButtonTabComponent(title,active));
		chrono.get(active).fileName=title;
	}
	
	public void checkModifToSave(){
		if (chrono.get(active).modifToSave){
			if (!chrono.get(active).fileName.endsWith("*")){
				tabs.setTabComponentAt(active, new ButtonTabComponent(chrono.get(active).fileName+"*",active));
				chrono.get(active).fileName+="*";
			}
		}
		else{
			if (chrono.get(active).fileName.endsWith("*")){
				chrono.get(active).fileName= chrono.get(active).fileName.substring(0, chrono.get(active).fileName.length()-1);
				tabs.setTabComponentAt(active, new ButtonTabComponent(chrono.get(active).fileName,active));
			}
		}
	}

	@Override
	public void keyPressed(KeyEvent e) {
		// Delete
		if (e.getKeyCode()==127){
			chrono.get(active).removeSelected();
			repaint();
		}
		
	}

	@Override
	public void keyReleased(KeyEvent e) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void keyTyped(KeyEvent e) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void stateChanged(ChangeEvent e) {
		JTabbedPane pane = (JTabbedPane) e.getSource();
		active = pane.getSelectedIndex();
	}
}
