package Main;

//~--- non-JDK imports --------------------------------------------------------

/**
 * 3      * Curso B?sico de desarrollo de Juegos en Java - Invaders
 * 4
 * 5      * (c) 2004 Planetalia S.L. - Todos los derechos reservados. Prohibida su reproducci?n
 *
 * http://www.planetalia.com
 *
 */
import Wireless.BaseStation;
import Wireless.MobileDevice;

import org.jfree.chart.*;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.*;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.data.*;
import org.jfree.data.xy.XYDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;

//~--- JDK imports ------------------------------------------------------------

import java.awt.Button;
import java.awt.Canvas;
import java.awt.Checkbox;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Rectangle;
import java.awt.TextField;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferStrategy;

import java.util.ArrayList;
import java.util.List;

import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;

public class GUI extends Canvas implements Entorno {

    // Ubicacion del mouse
    int posicionX = 0;
    int posicionY = 0;
    int contadorCambios_ABS = 0;
    int contadorCambios_HYS = 0;
    ArrayList<Ruta> rutas = new ArrayList<Ruta>();

    // Serie de datos para estación Base 1
    XYSeries  series1     = new XYSeries("EB1");
    XYSeries  series2     = new XYSeries("EB2");
    XYSeries  series3     = new XYSeries("EB3");
    XYSeries  series4     = new XYSeries("EB4");
    private boolean iniciar     = false;
    FlowLayout      flowLayout1 = new FlowLayout();

    // Variables del grafico
    final XYDataset                dataset;
    boolean                        configurar  = true;
    Config                         configPanel = new Config();
    ChartPanel                     chartPanel;
    final JFreeChart               chart;
    private ArrayList<BaseStation> BSs;
    MobileDevice                   MD;
    private ArrayList              paisaje;
    private SpriteCache            spriteCache;
    private BufferStrategy         strategy;
    private long                   usedTime;
    JFrame                         ventana;

    public GUI() {
        JPanel izquierdo = new JPanel();

        spriteCache = new SpriteCache();
        this.addMouseListener(new ProcMouse());
        JMenuBar  mb   = new JMenuBar();
        JMenu     menu = new JMenu("Choose");
        JMenuItem item1, item2;

        ventana = new JFrame("Simulador de Handoff");

        // JPanel    panel   = (JPanel) ventana.getContentPane();
        JPanel panel = new JPanel();

        // En la zona central colocamos los elementos mayores
        panel.setLayout(new GridLayout(1, 2));
        izquierdo.setLayout(new GridLayout(2, 1));
        item1 = new JMenuItem("Configurar");
        item1.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mousePressed(java.awt.event.MouseEvent evt) {
                jMenuItem1MouseClicked(evt);
            }
        });
        item2 = new JMenuItem("Iniciar");

        // Action listeners!!
        menu.add(item1);
        menu.add(item2);
        mb.add(menu);
        //ventana.setJMenuBar(mb);

        // setBounds(0, 0, Entorno.WIDTH, Entorno.HEIGHT);
        // panel.setPreferredSize(new Dimension(Entorno.WIDTH, Entorno.HEIGHT));
        // panel.setLayout(null);
        izquierdo.add(configPanel);
        //Grafico
        this.inicializaSeries();
        dataset     = createDataset();
        chart       = createChart(dataset);

        chartPanel = new ChartPanel(chart);
        izquierdo.add(chartPanel);

        panel.add(izquierdo);
        panel.add(this);
        ventana.setBounds(0, 0, Entorno.WIDTH * 2, Entorno.HEIGHT + 15);
        ventana.setVisible(true);
        ventana.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });

        // ventana.setResizable(false);
        ventana.add(panel);

        // ventana.add(bottomPanel);
        createBufferStrategy(2);
        strategy = getBufferStrategy();
        requestFocus();
    }


    public void configurar() {}

    public void initWorld() {
        paisaje = new ArrayList();
        BSs     = new ArrayList<BaseStation>();

        // Crea Estaciones Base.
        for (int i = 0; i < 2; i++) {
            for (int j = 0; j < 2; j++) {
                    BaseStation m = new BaseStation(this, 2*i+j+1);
                    m.setX(450 * i+40);
                    m.setY(40+j*450);
                    // m.setVx( (int)(Math.random()*20-10) );
                    BSs.add(m);
                
            }
        }
        // Agregar calles
        for (int i = 0; i < 2; i++) {

            Carretera c = new Carretera(this, "Avenida Willy Nº" + i, 0, 200 + i * 200, 1);

            paisaje.add(c);
            c = new Carretera(this, "Avenida Vitoko Nº" + i, 200 + i * 200, 0, 0);
            paisaje.add(c);
        }
        // Agregar Edifios
        // Se agregan en los cuadrantes enter las calles.
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                Edificio c = new Edificio(this, j + i * 3, 50 + 200 * i, 50 + 200 * j);
                paisaje.add(c);
                
            }
        }

        MD = new MobileDevice(this, "216545575255654");
        MD.setX(200);

        // m.setX( (int)(Math.random()*Entorno.WIDTH) );
        MD.setY(10);
    }

    private void jMenuItem1MouseClicked(MouseEvent evt) {

        // Aqui le decimos cual sera su frame padre, el titulo, y que sera bloqueante
    }

    public void updateWorld() {
        if (configPanel.iniciarSim()) {

            MD.act();
            //this.configPanel.setVisible(false);
            double maxPt = -10000000;
            int ID_MAX = -1;
            double ptTemp = 0;
            for (int i = 0; i < BSs.size(); i++) {
                BaseStation BS = BSs.get(i);

                long tempo = System.currentTimeMillis();
                ptTemp = BS.potenciaBS_MD(MD);
                if(ptTemp > maxPt){
                    maxPt = ptTemp;
                    ID_MAX = BS.getID();

                }
                switch(BS.getID()){
                    case 1:
                        series1.add(System.currentTimeMillis(),ptTemp);
                        break;
                    case 2:
                        series2.add(System.currentTimeMillis(),ptTemp);
                        break;
                    case 3:
                        series3.add(System.currentTimeMillis(),ptTemp);
                        break;
                    case 4:
                        series4.add(System.currentTimeMillis(),ptTemp);
                        break;
                    default:
                        break;
                }

            }
            if(MD.getBS_ID_HYS()!=ID_MAX){
                if(MD.getBS_ID_HYS()==0){
                    MD.setBS_ID_HYS(ID_MAX);
                    this.contadorCambios_HYS++; 
                }else
                    if((maxPt-10) >= BSs.get(MD.getBS_ID_HYS()-1).potenciaBS_MD(MD)){
                        MD.setBS_ID_HYS(ID_MAX);
                        this.contadorCambios_HYS++;
                    }
            }

            if(MD.getBS_ID_ABS()!=ID_MAX){
                MD.setBS_ID_ABS(ID_MAX);
                this.contadorCambios_ABS++;
            }

            configPanel.setContadores(contadorCambios_ABS, contadorCambios_HYS);
            createDataset();

           
        }else{
            switch(configPanel.getAccion()){
                case Config.MOVER_BS:
                    if(this.posicionX > 0){
                        BSs.get(configPanel.getBS()).setX(this.posicionX);
                        BSs.get(configPanel.getBS()).setY(this.posicionY);
                        configPanel.setAccion(Config.ESPERA);
                    }
                    break;
                case Config.PONER_EDIFICIO:
                    if(this.posicionX > 0){
                        Rectangle r2 = new Rectangle(posicionX,posicionY,1,1);
                        for(int i = 0;i < this.paisaje.size();i++){
                            Dibujable a1 = (Dibujable) paisaje.get(i);
                            if(a1 instanceof Edificio){
                                Edificio E1 = (Edificio)a1;
                                Rectangle r1 = a1.getBounds();
                                if (r1.intersects(r2)) {
                                    E1.setVisible();
                                    configPanel.setAccion(Config.ESPERA);

                                    break;
                                }
                            }
                        }
                    }
                    break;
                case Config.MARCAR_FIN:
                    if(this.posicionX>0){
                        Rectangle r2 = new Rectangle(posicionX,posicionY,1,1);
                        for(int i = 0;i < this.paisaje.size();i++){
                            Dibujable a1 = (Dibujable) paisaje.get(i);
                            if(a1 instanceof Carretera){
                                Rectangle r1 = a1.getBounds();
                                if (r1.intersects(r2)) {
                                    MD.setPunto(this.posicionX, this.posicionY, false);
                                    configPanel.setPunto(this.posicionX, this.posicionY, false);
                                    configPanel.setAccion(Config.ESPERA);
                                    break;
                                }
                            }
                        }

                    }
                    break;
                case Config.MARCAR_INICIO:
                    if(this.posicionX>0){
                        Rectangle r2 = new Rectangle(posicionX,posicionY,1,1);
                        for(int i = 0;i < this.paisaje.size();i++){
                            Dibujable a1 = (Dibujable) paisaje.get(i);
                            if(a1 instanceof Carretera){
                                Rectangle r1 = a1.getBounds();
                                Carretera c1 = (Carretera)a1;
                                if (r1.intersects(r2)) {
                                    if(c1.tipo == 1){
                                        MD.setX(posicionX);
                                        MD.setY(c1.getY());
                                    }else{
                                        MD.setX(c1.getX());
                                        MD.setY(posicionY);
                                    }
                                    MD.setPunto(MD.getX(), MD.getY(), true);
                                    MD.setPunto(650, 650, true);
                                    configPanel.setPunto(this.posicionX, this.posicionY, true);
                                    configPanel.setAccion(Config.ESPERA);
                                    break;
                                }
                            }
                        }

                    }
                    break;
                case Config.MARCAR_GIRO:
                    int nColiciones = 0;
                    int minX = 100000;
                    int minY = 100000;
                    if(this.posicionX>0){
                        Rectangle r2 = new Rectangle(posicionX,posicionY,1,1);
                        for(int i = 0;i < this.paisaje.size();i++){
                            Dibujable a1 = (Dibujable) paisaje.get(i);
                            if(a1 instanceof Carretera ){
                                Rectangle r1 = a1.getBounds();
                                Carretera c1 = (Carretera)a1;
                                if (r1.intersects(r2)) {
                                    if(c1.tipo == 1){
                                        minY = c1.getY();
                                    }else{
                                        minX = c1.getX();
                                    }
                                }
                            }
                        }
                        if(minY < 100000 && minX < 100000){

                            rutas.add(new Ruta(this,rutas.size(),minX,minY));
                        }

                    }
                    break;


            }

            this.posicionX = -1;
            this.posicionY = -1;
        }
    }

    public void calcularPotencia() {
        for (int i = 0; i < paisaje.size(); i++) {
            Dibujable a1 = (Dibujable) paisaje.get(i);
            Rectangle r1 = a1.getBounds();

            if (a1 instanceof BaseStation) {
                BaseStation b1 = (BaseStation) a1;
            }
        }
    }

    public void checkCollisions() {
        Rectangle playerBounds = MD.getBounds();

        for (int i = 0; i < paisaje.size(); i++) {
            Dibujable a1 = (Dibujable) paisaje.get(i);
            Rectangle r1 = a1.getBounds();

            if(MD.getFinX()-getX() < 50){
                if(a1 instanceof Carretera){
                    if (r1.intersects(playerBounds) && MD.getX() >= r1.getX() && MD.getY()>=r1.getY()) {
                        MD.collision(a1);
                        a1.collision(MD);
                    }
                }
            }

//            for (int j = i + 1; j < paisaje.size(); j++) {
//                Dibujable a2 = (Dibujable) paisaje.get(j);
//                Rectangle r2 = a2.getBounds();
//
//                if (r1.intersects(r2)) {
//                    a1.collision(a2);
//                    a2.collision(a1);
//                }
//            }
        }
    }

    public void paintWorld() {
        Graphics2D g = (Graphics2D) strategy.getDrawGraphics();

        g.setColor(Color.getHSBColor(35, 127, 127));
        g.fillRect(0, 0, getWidth(), getHeight());
        // Objetos del entorno
        for (int i = 0; i < paisaje.size(); i++) {

            Dibujable m = (Dibujable) paisaje.get(i);
            if(m instanceof Edificio){
                Edificio e1 = (Edificio)m;
                if(e1.getVisible()){
                    m.paint(g);
                }
            }else{
                m.paint(g);
            }
        }

        // Estaciones Bases
        for (int i = 0; i < BSs.size(); i++) {
            Dibujable m = (Dibujable) BSs.get(i);
            m.paint(g);
            g.setColor(Color.black);
            g.drawString("BS"+(i+1)+": ("+m.getX()+","+m.getY()+")", m.getX(), m.getY());
            
        }

        //Lineas
        for(int i = 0;i<this.rutas.size()-1;i++){
            Dibujable m = (Dibujable) rutas.get(i);
            m.paint(g);
        }

        // Mobil
        MD.paint(g);
        g.drawString("MD("+MD.getX()+","+MD.getY()+")-> ABS:BS"+MD.getBS_ID_ABS()+";HYS:BS"+MD.getBS_ID_HYS(), MD.getX(), MD.getY());
        g.setColor(Color.white);

//        if (usedTime > 0) {
//            g.drawString(String.valueOf(1000 / usedTime) + " fps", 0, Entorno.HEIGHT - 50);
//        } else {
//            g.drawString("--- fps", 0, Entorno.HEIGHT - 50);
//        }

        strategy.show();
    }

    public SpriteCache getSpriteCache() {
        return spriteCache;
    }

    public void game() {
        usedTime = 1000;
        initWorld();

        while (isVisible()) {
            long startTime = System.currentTimeMillis();

            updateWorld();
            
            checkCollisions();
            paintWorld();
            usedTime = System.currentTimeMillis() - startTime;

            try {
                Thread.sleep(SPEED);
            } catch (InterruptedException e) {}
        }
    }

    public static void main(String[] args) {
        GUI inv = new GUI();

        inv.game();
    }

    /**
     * Creates a sample dataset.
     *
     * @return a sample dataset.
     */
    private void inicializaSeries() {
         series1 = new XYSeries("EB1");
         series2 = new XYSeries("EB2");
         series3 = new XYSeries("EB3");
         series4 = new XYSeries("EB4");
    }

    private XYDataset createDataset() {
//        series1.add(1.0, 1.0);
//        series1.add(2.0, 4.0);
//        series1.add(3.0, 3.0);
//        series1.add(4.0, 5.0);
//        series1.add(5.0, 5.0);
//        series1.add(6.0, 7.0);
//        series1.add(7.0, 7.0);
//        series1.add(8.0, 8.0);
//        series2.add(1.0, 5.0);
//        series2.add(2.0, 7.0);
//        series2.add(3.0, 6.0);
//        series2.add(4.0, 8.0);
//        series2.add(5.0, 4.0);
//        series2.add(6.0, 4.0);
//        series2.add(7.0, 2.0);
//        series2.add(8.0, 1.0);
//        series3.add(3.0, 4.0);
//        series3.add(4.0, 3.0);
//        series3.add(5.0, 2.0);
//        series3.add(6.0, 3.0);
//        series3.add(7.0, 6.0);
//        series3.add(8.0, 3.0);
//        series3.add(9.0, 4.0);
//        series3.add(10.0, 3.0);

        final XYSeriesCollection dataset = new XYSeriesCollection();

        dataset.addSeries(series1);
        dataset.addSeries(series2);
        dataset.addSeries(series3);
        dataset.addSeries(series4);

        return dataset;
    }

    /**
     * Creates a chart.
     *
     * @param dataset  the data for the chart.
     *
     * @return a chart.
     */
    private JFreeChart createChart(final XYDataset dataset) {
        // create the chart...
        final JFreeChart chart = ChartFactory.createXYLineChart("Potencia Estacion Base - Mobil",    // chart title
            "t[s]",                                                                                  // x axis label
            "Potencia[db]",                                                                          // y axis label
            dataset,                                                                                 // data
            PlotOrientation.VERTICAL, true,                                                          // include legend
            true,                                                                                    // tooltips
            false                                                                               // urls
            );

        // NOW DO SOME OPTIONAL CUSTOMISATION OF THE CHART...
        chart.setBackgroundPaint(Color.white);

//      final StandardLegend legend = (StandardLegend) chart.getLegend();
        // legend.setDisplaySeriesShapes(true);
        // get a reference to the plot for further customisation...
        final XYPlot plot = chart.getXYPlot();

        plot.setBackgroundPaint(Color.lightGray);

        //plot.setAxisOffset(new Spacer(Spacer.ABSOLUTE, 5.0, 5.0, 5.0, 5.0));
        plot.setDomainGridlinePaint(Color.white);
        plot.setRangeGridlinePaint(Color.white);

        final XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer();

        renderer.setSeriesLinesVisible(0, false);
        renderer.setSeriesShapesVisible(1, false);

        plot.setRenderer(renderer);

        // change the auto tick unit selection to integer units only...
        final NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
        rangeAxis.setStandardTickUnits(NumberAxis.createStandardTickUnits());
        rangeAxis.setAutoRangeIncludesZero(true);
        // OPTIONAL CUSTOMISATION COMPLETED.
        return chart;
    }
}//~ Formatted by Jindent --- http://www.jindent.com
