package tsp;

import java.applet.Applet;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.FlowLayout;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.border.TitledBorder;


public class TSPApplet extends Applet
{
	private static final long serialVersionUID = 1L;
	public static final int MAX_POINTS = 2048;
    TSPMap map = null;
    int pointsCount = 100;
    int iterationCount = 100;
    int popCount = 50;
    int crossFactor = 40;
    int muteFactor = 20;
    TourDispComponent tourComp;
    JLabel lenLabel;
    JTextField inputPoints;
    JTextField inputIterations;
    JTextField outputDistance;
    JTextField outputTime;
    JTextField inputPop;
    JTextField inputCross;
    JTextField inputMute;
    Thread worker;
    boolean threadWorking = false;
    
    public TSPApplet()
    {
        map = null;
        threadWorking = false;
    }

    public void init()
    {
        tourComp = new TourDispComponent(map);
        tourComp.setMinimumSize(new Dimension(400, 400));
        tourComp.setPreferredSize(new Dimension(400, 400));
        lenLabel = new JLabel("Press 'Random' or 'Grid' button to start...");

    }

    public void start()
    {    	
    	this.setLayout(new FlowLayout(1,0,0));
    	JPanel panel = new JPanel();
    	panel.setPreferredSize(new Dimension(420,430)); 
   	panel.add(tourComp);
    	Border border = new TitledBorder("Map");
    	panel.setBorder(border);
        this.add(panel);
        
        JPanel rPanel = new JPanel(new FlowLayout(1,0,0));        
        rPanel.setPreferredSize(new Dimension(170,430)); 
        rPanel.setLocation(0,0);
        System.out.println(rPanel);
        panel = new JPanel();

        panel.setBorder(new TitledBorder("Parameters"));        
        panel.setPreferredSize(new Dimension(170,140));        
  
        panel.add(new JLabel("      # of cities:")); 
        inputPoints = new JTextField();
        inputPoints.setPreferredSize(new Dimension(50,17));
        inputPoints.setText(Integer.toString(pointsCount));
        panel.add(inputPoints);        
        panel.add(new JLabel("# of iterations:"));
        inputIterations = new JTextField();
        inputIterations.setPreferredSize(new Dimension(50,17));
        inputIterations.setText(Integer.toString(iterationCount));
        panel.add(inputIterations);         
        panel.add(new JLabel("Population(GA):"));
        inputPop = new JTextField();
        inputPop.setPreferredSize(new Dimension(30,17));
        inputPop.setText(Integer.toString(popCount));
        panel.add(inputPop);         
        panel.add(new JLabel("Cross Factor(GA):"));
        inputCross = new JTextField();
        inputCross.setPreferredSize(new Dimension(30,17));
        inputCross.setText(Integer.toString(crossFactor));
        panel.add(inputCross);         
        panel.add(new JLabel("Mute Factor(GA):"));
        inputMute = new JTextField();
        inputMute.setPreferredSize(new Dimension(30,17));
        inputMute.setText(Integer.toString(muteFactor));
        panel.add(inputMute);          
        rPanel.add(panel);
        
        panel = new JPanel();
        panel.setBorder(new TitledBorder("Results"));   
        panel.setPreferredSize(new Dimension(170,75));        
        panel.add(new JLabel("Distance:"));
        outputDistance = new JTextField();
        outputDistance.setPreferredSize(new Dimension(90,17));
        outputDistance.setText("0");
        panel.add(outputDistance); 
        panel.add(new JLabel("Time(ms):"));
        outputTime = new JTextField();
        outputTime.setPreferredSize(new Dimension(80,17));
        outputTime.setText("0");
        panel.add(outputTime);         
        rPanel.add(panel);
        
        final JButton gridButton = new JButton("Grid");        
        final JButton nnButton = new JButton("Nearest Neighbor");
        final JButton optButton = new JButton("2-opt");
        final JButton gaButton = new JButton("Genetic");
        final JButton gaModButton = new JButton("Genetic-M");
        final JButton stopButton = new JButton("STOP");
        
        panel = new JPanel();
        panel.setPreferredSize(new Dimension(170,60));        
        panel.setBorder(new TitledBorder("Points"));   
        final JButton newButton = new JButton("Random");        
        panel.add(newButton);
        panel.add(gridButton);
        rPanel.add(panel);
        
        panel = new JPanel();
        panel.setPreferredSize(new Dimension(170,155));
        panel.setBorder(new TitledBorder("Methods"));
        
        int bW = 130;
        int bH = 20;
        
        nnButton.setPreferredSize(new Dimension(bW,bH));
        panel.add(nnButton);
        optButton.setPreferredSize(new Dimension(bW,bH));
        panel.add(optButton);
        gaButton.setPreferredSize(new Dimension(bW,bH));
        panel.add(gaButton);
        gaModButton.setPreferredSize(new Dimension(bW,bH));
        panel.add(gaModButton);  
        stopButton.setPreferredSize(new Dimension(bW,bH));
        panel.add(stopButton);
        rPanel.add(panel);
        
        this.add(rPanel);
        
        this.add(new JLabel("TSP Java Implementation - Ramunas Dronga IT-4/1."));
        this.add(lenLabel); 
        
        newButton.addActionListener(new ActionListener() {

            public void actionPerformed(final ActionEvent e)
            {
                doNew();
            }

        });
        gridButton.addActionListener(new ActionListener() {

            public void actionPerformed(final ActionEvent e)
            {
                doGrid();
            }

        });        
        nnButton.addActionListener(new ActionListener() {

            public void actionPerformed(final ActionEvent e)
            {
                doNn();
            }

        });
        optButton.addActionListener(new ActionListener() {

            public void actionPerformed(final ActionEvent e)
            {
                doOpt();
            }

        });
        gaButton.addActionListener(new ActionListener() {

            public void actionPerformed(final ActionEvent e)
            {
                doGa();
            }

        });
        gaModButton.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e)
            {
                doGaMod();
            }

        });   
        stopButton.addActionListener(new ActionListener(){
        	//@SuppressWarnings("deprecation")
			public void actionPerformed(ActionEvent e){
        		if(threadWorking){
        			worker.stop();
        			threadWorking = false;
        		}
        	}
        });
    }

    public void doNew()
    {
        if(threadWorking)
        {
            return;
        } else
        {
            lenLabel.setText("Choose algorithm to solve map...");
            pointsCount = Integer.parseInt(inputPoints.getText());            
            if(pointsCount > TSPApplet.MAX_POINTS){
            	pointsCount = TSPApplet.MAX_POINTS;
            	inputPoints.setText(Integer.toString(pointsCount));
            	
            }
            map = new TSPMap(pointsCount, 380);
            tourComp.setMap(map);
            return;
        }
    }
    public void doGrid()
    {
        if(threadWorking)
        {
            return;
        } else
        {
            lenLabel.setText("Choose method to solve map...");
            pointsCount = Integer.parseInt(inputPoints.getText());            
            map = new TSPMap();
            map.CreateGridCities(pointsCount, 380);
            
            tourComp.setMap(map);
            return;
        }
    }    

    public void doNn()
    {
        if(threadWorking || map == null)
        {
            return;
        } else
        {
        	worker = new Thread(){
        		public void run(){
        			long time = System.currentTimeMillis();
		            final TSPNnSolver tsp = new TSPNnSolver(map);
		            TSPTour tour = tsp.getSolution();
		            double length = tour.getLength();
		            double l;
		            int cnt = map.getPointCount();
		            for(int i = 0;i < cnt;i++){
		            	tour = tsp.getSolutionFromPoint(i);
		            	l = tour.getLength();
		            	if(l < length){
		            		tourComp.setTour(tour);
		            		length = l;
		            	}
		            	lenLabel.setText("Calculating (" + i + "):" + length);
		            	delay.pause(10);
		            }
		            lenLabel.setText("NN done: " + length);
		            outputTime.setText(Double.toString(System.currentTimeMillis()-time));
		            outputDistance.setText(Double.toString(length));
		            threadWorking = false;
        		}
        	}; 
        	worker.start();
            threadWorking = true;
        }
    }

    public void doOpt()
    {
        if(threadWorking || map == null)
        {
            return;
        } else
        {
        	worker = new Thread(){
        		public void run(){
        			long time = System.currentTimeMillis();
        			iterationCount = Integer.parseInt(inputIterations.getText());
		            TSPTour tour = new TSPTour(map,true);
		            int i;
		            double l,length;
		            length = tour.getLength();		            
		            for(i = 1; i <= iterationCount; i++)
		            {      
		            	tour.randomize();            	
		            	tour.do2Opt();
		            	l = tour.getLength();
		            	if(l <= length){
		            		length = l;
		            		tourComp.setTour(tour);
		            		
		            	}
		            	lenLabel.setText("Calculating (" + i + "):" + length);		            	
		            	delay.pause(10);	            	
		            	
		            }
		            lenLabel.setText("2-opt done: " + length);
		            outputTime.setText(Double.toString(System.currentTimeMillis()-time));
		            outputDistance.setText(Double.toString(length));
		            threadWorking = false;
        		}
        	};
            worker.start();
            threadWorking = true;
        }
    }

    public void doGa()
    {
        if(map == null)
            return;
        if(!threadWorking)
        {
            worker = new Thread() {

                public void run()
                {
                	long time = System.currentTimeMillis();
                	iterationCount = Integer.parseInt(inputIterations.getText());
                	popCount = Integer.parseInt(inputPop.getText());
                	crossFactor = Integer.parseInt(inputCross.getText());
                	muteFactor = Integer.parseInt(inputMute.getText());
                	
                	double l,length;
                    final TSPGeneticSolver tsp = new TSPGeneticSolver(map, popCount, crossFactor, muteFactor);
                    TSPTour tour = tsp.getSolution();                    
                    length = tour.getLength();                    
                    int i;
                    for(i = 1; i < iterationCount; i++)
                    {
                        tsp.doOneGeneration();
                        tour = tsp.getSolution();                        
                        l = tour.getLength();
                        if(l <= length){
                        	length = l;
                        	tourComp.setTour(tour);
                        }
                        lenLabel.setText("Calculating (" + i + "): " + length);
                    }
                   	lenLabel.setText("GA done: " + length);
                   	outputTime.setText(Double.toString(System.currentTimeMillis()-time));
                   	outputDistance.setText(Double.toString(length));
                    threadWorking = false;
                }

            };
            worker.start();
            threadWorking = true;
        }
    }
    public void doGaMod()
    {
        if(map == null)
            return;
        if(!threadWorking)
        {
            worker = new Thread() {

                public void run()
                {
                	long time = System.currentTimeMillis();
                	iterationCount = Integer.parseInt(inputIterations.getText());
                	popCount = Integer.parseInt(inputPop.getText());
                	crossFactor = Integer.parseInt(inputCross.getText());
                	muteFactor = Integer.parseInt(inputMute.getText());
                	double l,length;
                    final TSPGeneticSolver tsp = new TSPGeneticSolver(map, popCount, crossFactor, muteFactor);
                    TSPTour tour = tsp.getSolution();
                    length = tour.getLength();
                    int i;
                    for(i = 1; i < iterationCount; i++)
                    {
                        tsp.doOneGenerationModified();
                        tour = tsp.getSolution();
                        l = tour.getLength();
                        if(l <= length){
                        	length = l;
                        	tourComp.setTour(tour);                        
                        }
                        lenLabel.setText("Calculating (" + i + "): " + length);
                    }                    
                   	lenLabel.setText("GA-M done: " + length);
                   	outputTime.setText(Double.toString(System.currentTimeMillis()-time));
                   	outputDistance.setText(Double.toString(length));
                    threadWorking = false;
                }

            };
            worker.start();
            threadWorking = true;
        }
    }   
}
