/*
 * Liberu.java
 *
 * Created on 30 of August 2005, 2:05
 */
/**
 * web site: www.vitaliberu.pt
 * email: sysliberal@gmail.com; paulo@vitaliberu.pt
 * @author Paulo Roque Silva
 */
import java.awt.*;
import java.awt.event.*;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.util.Enumeration;

import javax.swing.*;

import gnu.io.CommPortIdentifier;
import gnu.io.SerialPort;
import gnu.io.SerialPortEvent;
import gnu.io.SerialPortEventListener;
//import icommand.nxt.Motor;

public class Liberu extends JFrame /*implements SerialPortEventListener*/ {
    
    public static final long    serialVersionUID = 2016L; // SimLiberu Version
    Font			font;
    static boolean  Already, // ready to show
    				Sono; // true if at sleep
    static Liberu	liberu;
    static Interface InterFace; // Human control interface
    Mind            mind; // execute the simulation of the robot (body+brain) and the world
    boolean			executed, // true if under execution
             		stopped, // true if stopped, so I can save and load
             		newUniverse, // true if aWorld initialized
    				terminate, // true if good for new or open
    				saved; // true if data saved
	SerialPort        serialPort;
        /** The port we're normally going to use. */
	private static final String PORT_NAMES[] = { 
//			"/dev/cu.usbmodem1421", // Mac OS X
//                        "/dev/ttyACM0", // Raspberry Pi
//			"/dev/ttyUSB0", // Linux
			"COM6" // Windows
	};
    // Comunications
	public static BufferedReader input;
	/** The output stream to the port */
	public static String inputLine;
	public static OutputStream output;
	/** Milliseconds to block while waiting for port open */
	private static final int TIME_OUT = 2000;
	/** Default bits per second for COM port. */
	private static final int DATA_RATE = 9600;
    
    /** Creates new form SimLiberu */
    public Liberu() {
        int screenWidth;
        int screenHeight;
        
        // Get Screen dimensions
        Toolkit kit = Toolkit.getDefaultToolkit();
        Dimension screenSize = kit.getScreenSize();
        screenWidth = screenSize.width;
        screenHeight = screenSize.height;
        // Center frame in Screen
        setLocation( screenWidth / 8, screenHeight / 8 );
        // Set frame icon
        Image img = kit.getImage("Brain.gif");
        setIconImage(img);
        
        font = new Font("sansSerif", Font.PLAIN, 28);
        Already     = false;
        Sono        = false;
        executed    = false;
 		stopped     = true;
 		newUniverse = true;
 		terminate   = true;
        InterFace   = new Interface();
        mind  		= new Mind(false);
	    mind.display(false);
        initComponents();
        if (screenWidth > 2000)
            setSize( 2*768, 2*600);
        else
            setSize( 768, 600);
        saved       = true;
    }
    
	protected void processWindowEvent(WindowEvent e) {

		if (e.getID() == WindowEvent.WINDOW_CLOSING) {
	        if (!saved) {
	            if (JOptionPane.showConfirmDialog(null,
	            "The Robot's Cortex not saved! Do you want to exit?", "Alert",
	            JOptionPane.OK_CANCEL_OPTION) == JOptionPane.OK_OPTION)
	            	exitLiberu();
	        }
	        else
	        	exitLiberu();
		}
	}
	
	public static String inputLine() {
		
		return inputLine;
	}

	/**
	 * This should be called when you stop using the port.
	 * This will prevent port locking on platforms like Linux.
	 */
    public synchronized void close() {
		
        if (serialPort != null) {
//            serialPort.removeEventListener();
            serialPort.close();
    	}
    }

	/**
	 * Handle an event on the serial port. Read the data and print it.
	 */
    public synchronized void serialEvent(SerialPortEvent oEvent) {
		
        if (oEvent.getEventType() == SerialPortEvent.DATA_AVAILABLE) {
            try {
                String inputLine=input.readLine();
                //  ###############################
                System.out.println(inputLine);
            } catch (Exception e) {
                System.err.println(e.toString());
            }
        }
		// Ignore all the other eventTypes, but you should consider the other ones.
    }

    private void initComm() {
    	
    	// TODO code application logic here
        System.setProperty("gnu.io.rxtx.SerialPorts", "COM6");

        CommPortIdentifier portId = null;
        Enumeration portEnum = CommPortIdentifier.getPortIdentifiers();

        //First, Find an instance of serial port as set in PORT_NAMES.
        while (portEnum.hasMoreElements()) {
            CommPortIdentifier currPortId = (CommPortIdentifier) portEnum.nextElement();
            for (String portName : PORT_NAMES) {
                if (currPortId.getName().equals(portName)) {
                    portId = currPortId;
                    break;
                }
            }
        }
        if (portId == null) {
                System.out.println("Could not find COM port.");
                return;
        }

        try {
        	// open serial port, and use class name for the appName.
                serialPort = (SerialPort) portId.open(this.getClass().getName(), TIME_OUT);

        	// set port parameters
                serialPort.setSerialPortParams(DATA_RATE, SerialPort.DATABITS_8,
        				SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);

        	// open the streams
                input = new BufferedReader(new InputStreamReader(serialPort.getInputStream()));
                output = serialPort.getOutputStream();

        	// add event listeners
//                serialPort.addEventListener(this);
//                serialPort.notifyOnDataAvailable(true);
        } catch (Exception e) {
                System.err.println(e.toString());
        }
    	System.out.println("Started");
    }
	
    private void initComponents() {
        // jPopupMenu1 = new javax.swing.JPopupMenu();
        jPanel1     = new JPanel();
        jPanel1.setFont(font);
        JPanel        panel; // Learning Window
//        jButton1test= new JButton();
        jButton1    = new JButton();
        jButton1.setFont(font);
        jButton2    = new JButton();
        jButton2.setFont(font);
        jButton3    = new JButton();
        jButton3.setFont(font);
        jButton4    = new JButton();
        jButton4.setFont(font);
        jButton5    = new JButton();
        jButton5.setFont(font);
        jButton6    = new JButton();
        jButton6.setFont(font);
        jMenuBar1   = new JMenuBar();
        jMenuBar1.setFont(font);
        jMenu1      = new JMenu();
        jMenu1.setFont(font);
        jMenu3      = new JMenu();
        jMenu3.setFont(font);
        jMenuItem1  = new JMenuItem();
        jMenuItem1.setFont(font);
        jMenuItem2  = new JMenuItem();
        jMenuItem2.setFont(font);
        jMenuItem3  = new JMenuItem();
        jMenuItem3.setFont(font);
        jMenuItem31 = new JMenuItem();
        jMenuItem31.setFont(font);
        jSeparator1 = new JSeparator();
        jMenuItem4  = new JMenuItem();
        jMenuItem4.setFont(font);
        jButton1Act = new JButton();
        jButton1Act.setFont(font);
        jButton2Act = new JButton();
        jButton2Act.setFont(font);
        jButton3Act = new JButton();
        jButton3Act.setFont(font);
        jButton4Act = new JButton();
        jButton4Act.setFont(font);
        jButtonDAct = new JButton();
        jButtonDAct.setFont(font);
        jButtonHAct = new JButton();
        jButtonHAct.setFont(font);
        jButtonSAct = new JButton();
        jButtonSAct.setFont(font);
        jLabel1 = new JLabel("Liberu:");
        jLabel1.setFont(font);
        jLabel2 = new JLabel("Sr. Mouse:");
        jLabel2.setFont(font);
        jLabel3 = new JLabel("Thumb:");
        jLabel3.setFont(font);

        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        setTitle("Liberu 2016 - Formica");
        jPanel1.add(jLabel1);
        jButton1.setText("Play");
        jButton1.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                playAction(evt);
            }
        });
        jPanel1.add(jButton1);

        jButton2.setText("Warn");
        jButton2.setBackground(Color.GREEN);
        jButton2.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                warnAction(evt);
            }
        });
        jPanel1.add(jButton2);

        jButton3.setText("Pause");
        jButton3.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                pauseAction(evt);
            }
        });
        jPanel1.add(jButton3);

        jButton4.setText("Continue");
        jButton4.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                continueAction(evt);
            }
        });
        jPanel1.add(jButton4);

        jButton5.setText("Stop");
        jButton5.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                stopAction(evt);
            }
        });
        jPanel1.add(jButton5);

        jPanel1.add(jLabel3);

        jButton6.setText("Right Up");
        jButton6.setBackground(Color.GREEN);
        jButton6.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                thumbAction(evt);
            }
        });
        jPanel1.add(jButton6);

        getContentPane().add(jPanel1, BorderLayout.NORTH);

        jMenu1.setText("Cortex");
        jMenuItem1.setText("New Cortex");
        jMenuItem1.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                newAction(evt);
            }
        });
        jMenu1.add(jMenuItem1);

        jMenuItem2.setText("Open Cortex...");
        jMenuItem2.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                openAction(evt);
            }
        });
        jMenu1.add(jMenuItem2);

        jMenuItem3.setText("Save Cortex...");
        jMenuItem3.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                saveAction(evt);
            }
        });
        jMenu1.add(jMenuItem3);

        jMenu1.add(jSeparator1);

        jMenuItem4.setText("Exit Liberu");
        jMenuItem4.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                exitAction(evt);
            }
        });
        jMenu1.add(jMenuItem4);
        jMenuBar1.add(jMenu1);

        jMenu3.setText("Help"); 
        jMenuItem31.setText("Version..."); 
        jMenuItem31.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                versionAction(evt);
            }
        });
        jMenu3.add(jMenuItem31);
        jMenuBar1.add(jMenu3);

        setJMenuBar(jMenuBar1);

        getContentPane().add(Liberu.InterFace, BorderLayout.CENTER);
	    panel        = new JPanel(new GridLayout(16, 1));

	    
	    getContentPane().add(panel, BorderLayout.EAST);

        panel.add(jLabel2);

        jButton2Act.setText("Walk");
        jButton2Act.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                walkAction(evt);
            }
        });
        panel.add(jButton2Act);

        jButton1Act.setText("Back");
        jButton1Act.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                backAction(evt);
            }
        });
        panel.add(jButton1Act);

        jButton3Act.setText("Left");
        jButton3Act.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                leftAction(evt);
            }
        });
        panel.add(jButton3Act);

        jButton4Act.setText("Right");
        jButton4Act.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                rightAction(evt);
            }
        });
        panel.add(jButton4Act);

        jButtonDAct.setText("Energy");
        jButtonDAct.setBackground(Color.CYAN);
        jButtonDAct.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                energyAction(evt);
            }
        });
        panel.add(jButtonDAct);

        jButtonHAct.setText("Home");
        jButtonHAct.setBackground(Color.ORANGE);
        jButtonHAct.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                homeAction(evt);
            }
        });
        panel.add(jButtonHAct);

        jButtonSAct.setText("Sleep");
        jButtonSAct.setBackground(Color.GREEN);
        jButtonSAct.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                sonoAction(evt);
            }
        });
        panel.add(jButtonSAct);

        pack();
    }

    private void newAction(ActionEvent evt) {
    	int i;
    	
    	if (stopped && terminate) {
    		mind = new Mind(false);
    		mind.display(false);
            newUniverse = true;
            for (i=0; i<Interface.Taste.length; i++)
            	Interface.Taste[i] = 0;
            for (i=0; i<Interface.Vision.length; i++)
            	Interface.Vision[i] = 0;
            for (i=0; i<Interface.Sound.length; i++)
            	Interface.Sound[i] = 0;
            for (i=0; i<Interface.Smell.length; i++)
            	Interface.Smell[i] = 0;
            Interface.Lovely = 0;
            Interface.QF = 0;
            JOptionPane.showMessageDialog(null, "New Liberu!", "Information",
                JOptionPane.INFORMATION_MESSAGE);
        }
    }

    private void warnAction(ActionEvent evt) {
    	int i; // index
    	
        if (executed)
        	Cortex.Warn = !Cortex.Warn;
    	if (Cortex.Warn) {
            jButton2.setBackground(Color.RED);
    	}
    	else {
            jButton2.setBackground(Color.GREEN);
			Emotions.WARNING = false;
			Interface.Warned = false;
	        for (i=0; i < Brain.SENSES; i++)
	        	Interface.WarnSense[i] = false;
    	}
    }

    private void thumbAction(ActionEvent evt) {

        if (executed)
        	Act.Thumb = !Act.Thumb;
    	if (Act.Thumb) {
            jButton6.setBackground(Color.RED);
            jButton6.setText("Left  Up");
    	}
    	else {
            jButton6.setBackground(Color.GREEN);
            jButton6.setText("Right Up");
    	}
    }

    private void pauseAction(ActionEvent evt) {

    	// CAN'T run without <Play> pressed first
        if (executed) {
        	mind.pause();
            stopped = true;
    		try {
                output.write((byte)113);
                output.write('\n');
    		}
        	catch (Exception e) {
                System.err.println(e.toString());
        	}
//    		Motor.A.stop();
//    		Motor.B.stop();
        }
    }

    private void continueAction(ActionEvent evt) {

    	if (executed) {
            stopped = false;
            mind.continueRun();
        }
    }

    private void exitLiberu() {
    	
    	if (executed) {
    		try {
                output.write((byte)113);
                output.write('\n');
    		}
        	catch (Exception e) {
                System.err.println(e.toString());
        	}
//			Motor.A.stop();
//			Motor.B.stop();
	        Neuron.end = true;
	        mind.setToEnd(); // Set free the nodes to finishing
	        mind.interrupt();
        }
        System.out.println("END Liberu...bye bye");
        System.exit(0);
    }
    
    private void exitAction(ActionEvent evt) {

        if (!saved) {
            if (JOptionPane.showConfirmDialog(null,
            "The Robot's Cortex not, yet, saved! Do you want to exit?", "Alert",
            JOptionPane.OK_CANCEL_OPTION) == JOptionPane.OK_OPTION)
            	exitLiberu();
        }
        else
        	exitLiberu();
    }

    private void saveAction(ActionEvent evt) {
    	String		directory = ".\\", // directory by default
    				file = "Liberu.mind"; // file by default
		File		fout;
		FileDialog 	fd;
        
    	if (stopped) {
    		fd = new FileDialog(this, "File to Save?", FileDialog.SAVE);
    		fd.setVisible(true);
    		if (fd.getDirectory() != null && fd.getFile() != null) {
    			directory = fd.getDirectory();
    			file = fd.getFile();
    		}
    		fout = new File(directory + file);
	        try {
	            // Save the nodes to Disk file <Liberu.dat>
	            ObjectOutputStream out = new ObjectOutputStream(new
	                    FileOutputStream(fout));
	            out.writeObject(mind.brain.past);
	            out.close();
	            saved = true;
	        }
	        catch (Exception e) {
	            e.printStackTrace();
	        }
        }
    }

    private void openAction(ActionEvent evt) {
    	String		directory = ".\\", // directory by default
    				file = "Liberu.dat"; // file by default
		File		fin;
		FileDialog 	fd;
        
    	if (stopped && terminate) {
    		mind = new Mind(true);
    		fd = new FileDialog(this, "File to Load?", FileDialog.LOAD);
    		fd.setVisible(true);
    		if (fd.getDirectory() != null && fd.getFile() != null) {
    			directory = fd.getDirectory();
    			file = fd.getFile();
    		}
    		fin = new File(directory + file);
    		if (fin.exists()) {
    	        try {
    	            // Load the nodes from the Disk file <Liberu.dat>
    	            ObjectInputStream in = new ObjectInputStream(new
    	                    FileInputStream(fin));
    	            mind.brain.past = (Cortex)in.readObject();
    	            in.close();
    	        }
                catch (Exception e) {
                    e.printStackTrace();
                }
    	        Neuron.end = false;
                newUniverse = true;
                mind.display(true);
    		}
        }
    }

    private void playAction(ActionEvent evt) {

    	if (!executed && newUniverse) {
            executed = true;
            terminate = false;
            stopped = false;
        	liberu.initComm();  // formica
            mind.step(false);
            mind.setDaemon(true);
            mind.start();
            mind.display(true);
            newUniverse = false;
            saved = false;
        }
    }
    
    private void stopAction(ActionEvent evt) {

    	if (executed) {
            if (JOptionPane.showConfirmDialog(null,
                    "The Robot is going to Stop...", "Alert",
                    JOptionPane.OK_CANCEL_OPTION) == JOptionPane.OK_OPTION) {
            	mind.setToEnd();                  // Free nodes to be finishing
            	mind.brain.endLiberu(true);
            	mind.interrupt();
                executed = false;
                stopped = true;
                terminate = true;
                serialPort.close();
            }
        }
    }

    private void versionAction(ActionEvent evt) {

        JOptionPane.showMessageDialog(null, "Liberu, by Paulo Roque Silva... 2004/2016", "Information\n"
        		+ " - Formica C - 10.000 neurons",
                JOptionPane.INFORMATION_MESSAGE);
    }

    private void backAction(ActionEvent evt) {

    	if (executed) {
    		mind.brain.idAct1(Brain.ABACK);
    		mind.brain.idAct2(Brain.BBACK);
    	}
    }

    private void walkAction(ActionEvent evt) {

    	if (executed) {
    		mind.brain.idAct1(Brain.AWALK);
    		mind.brain.idAct2(Brain.BWALK);
    	}
    }

    private void leftAction(ActionEvent evt) {

    	if (executed) {
    		mind.brain.idAct1(Brain.ABACK);
    		mind.brain.idAct2(Brain.BWALK);
    	}
    }

    private void rightAction(ActionEvent evt) {

    	if (executed) {
    		mind.brain.idAct1(Brain.AWALK);
    		mind.brain.idAct2(Brain.BBACK);
    	}
    }

    private void energyAction(ActionEvent evt) { // REVIUE
    	
    	if (executed)
        	Brain.Energy = !Brain.Energy;
    	if (executed && Brain.Energy) {
            jButtonDAct.setBackground(Color.RED);
    	}
    	if (executed && !Brain.Energy) {
            jButtonDAct.setBackground(Color.CYAN);
    	}
    }

    private void homeAction(ActionEvent evt) { // REVIUE
    	
    	if (executed)
        	Brain.BackHome = !Brain.BackHome;
    	if (executed && Brain.BackHome) {
            jButtonHAct.setBackground(Color.RED);
    	}
    	if (executed && !Brain.BackHome) {
            jButtonHAct.setBackground(Color.ORANGE);
    	}
    }

    private void sonoAction(ActionEvent evt) {

    	if (executed)
        	Sono = !Sono;
    	if (executed && Sono) {
        	mind.pause();
            stopped = true;
        		try {
                    output.write((byte)113);
                    output.write('\n');
        		}
            	catch (Exception e) {
                    System.err.println(e.toString());
            	}
//        	Motor.A.stop();
//        	Motor.B.stop();
            jButtonSAct.setBackground(Color.PINK);
            mind.brain.sono();
    	}
    	if (executed && !Sono) {
            stopped = false;
            mind.continueRun();
            jButtonSAct.setBackground(Color.GREEN);
    	}
    }
    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) throws Exception {

    	EventQueue.invokeLater(new Runnable() {
    		public void run() {
            	liberu = new Liberu();
            	liberu.setVisible(true);
            }
        });
    }    
//    private JButton    jButton1test;
    private JButton    jButton1;
    private JButton    jButton2;
    private JButton    jButton3;
    private JButton    jButton4;
    private JButton    jButton5;
    private JButton    jButton6;
    private JMenu      jMenu1;
    private JMenu      jMenu3;
    private JMenuBar   jMenuBar1;
    private JMenuItem  jMenuItem1;
    private JMenuItem  jMenuItem2;
    private JMenuItem  jMenuItem3;
    private JMenuItem  jMenuItem4;
    private JMenuItem  jMenuItem31;
    private JPanel     jPanel1;
    private JSeparator jSeparator1;
    private JButton    jButton1Act;
    private JButton    jButton2Act;
    private JButton    jButton3Act;
    private JButton    jButton4Act;
    public static JButton    jButtonDAct;
    public static JButton    jButtonHAct;
    private JButton    jButtonSAct;
    private JLabel	   jLabel1;
    private JLabel	   jLabel2;
    private JLabel	   jLabel3;
}