package ch.epfl.isochrone.gui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
import javax.swing.JViewport;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.event.MouseInputAdapter;

import ch.epfl.isochrone.geo.PointOSM;
import ch.epfl.isochrone.geo.PointWGS84;
import ch.epfl.isochrone.tiledmap.CachedTileProvider;
import ch.epfl.isochrone.tiledmap.ColorTable;
import ch.epfl.isochrone.tiledmap.IsochroneTileProvider;
import ch.epfl.isochrone.tiledmap.OSMTileProvider;
import ch.epfl.isochrone.tiledmap.TileProvider;
import ch.epfl.isochrone.tiledmap.TransparentTileProvider;
import ch.epfl.isochrone.timetable.Date;
import ch.epfl.isochrone.timetable.Date.Month;
import ch.epfl.isochrone.timetable.FastestPathTree;
import ch.epfl.isochrone.timetable.Graph;
import ch.epfl.isochrone.timetable.SecondsPastMidnight;
import ch.epfl.isochrone.timetable.Stop;
import ch.epfl.isochrone.timetable.TimeTable;
import ch.epfl.isochrone.timetable.TimeTableReader;

public final class IsochroneTL {
    private static final String OSM_TILE_URL = "http://b.tile.openstreetmap.org/";
    private static final int INITIAL_ZOOM = 11;
    private static final PointWGS84 INITIAL_POSITION = new PointWGS84(Math.toRadians(6.476), Math.toRadians(46.613));
    private static final String INITIAL_STARTING_STOP_NAME = "Lausanne-Flon";
    private static final int INITIAL_DEPARTURE_TIME = SecondsPastMidnight.fromHMS(6, 8, 0);
    private static final Date INITIAL_DATE = new Date(1, Month.OCTOBER, 2013);
    private static final int WALKING_TIME = 5 * 60;
    private static final double WALKING_SPEED = 1.25;

    private final TiledMapComponent tiledMapComponent;
    
    private Point pointSouris;
    private Point pointCarte = new Point(0,0);

    public IsochroneTL() throws IOException {
        TileProvider bgTileProvider = new CachedTileProvider(new OSMTileProvider(new URL(OSM_TILE_URL)));
        tiledMapComponent = new TiledMapComponent(INITIAL_ZOOM);
        
        TimeTableReader ttr = new TimeTableReader("/time-table/");
        TimeTable tt = ttr.readTimeTable();
        
        Stop departure = null;
        for (Stop s : tt.stops()) {
            if (s.name().equals(INITIAL_STARTING_STOP_NAME)) {
                departure = s;
            }
        }

        Graph g = ttr.readGraphForServices(tt.stops(),
                tt.servicesForDate(INITIAL_DATE), WALKING_TIME, WALKING_SPEED);

        FastestPathTree f = g.fastestPaths(departure, INITIAL_DEPARTURE_TIME);
        
        
        
        List<Color> listeCouleur = new ArrayList<Color>();
        listeCouleur.add(new Color(255 ,0 ,0));
        listeCouleur.add(new Color(255 ,122 ,0));
        listeCouleur.add(new Color(255 ,255 ,0));
        listeCouleur.add(new Color(122 ,255 ,0));
        listeCouleur.add(new Color(0 ,255 ,0));
        listeCouleur.add(new Color(0 ,122 ,122));
        listeCouleur.add(new Color(0 ,0 ,255));
        listeCouleur.add(new Color(0 ,0 ,122));
        listeCouleur.add(new Color(0 ,0 ,0));
        ColorTable tableCouleur = new ColorTable(300,listeCouleur);
        
        TileProvider trTileProvider = new CachedTileProvider(new TransparentTileProvider(0.5, new IsochroneTileProvider(f, tableCouleur, WALKING_SPEED)));
        
        tiledMapComponent.addTileProvider(bgTileProvider);
        tiledMapComponent.addTileProvider(trTileProvider);
    }

    private JComponent createCenterPanel() {
        final JViewport viewPort = new JViewport();
        viewPort.setView(tiledMapComponent);
        PointOSM startingPosOSM = INITIAL_POSITION.toOSM(tiledMapComponent.zoom());
        viewPort.setViewPosition(new Point(startingPosOSM.roundedX(), startingPosOSM.roundedY()));
        
        tiledMapComponent.setSize(tiledMapComponent.getPreferredSize());
        
        tiledMapComponent.view=viewPort;

        final JPanel copyrightPanel = createCopyrightPanel();

        final JLayeredPane layeredPane = new JLayeredPane();
        layeredPane.setPreferredSize(new Dimension(400, 300));

        layeredPane.add(viewPort, new Integer(0));
        layeredPane.add(copyrightPanel, new Integer(1));

        layeredPane.addComponentListener(new ComponentAdapter() {
            @Override
            public void componentResized(ComponentEvent e) {
                Rectangle newBounds = layeredPane.getBounds();
                
                viewPort.setBounds(newBounds);
                copyrightPanel.setBounds(newBounds);

                viewPort.revalidate();
                copyrightPanel.revalidate();
            }
        });
        
        layeredPane.addMouseListener(new MouseInputAdapter() {
            @Override
            public void mousePressed(MouseEvent e) {
                pointSouris = e.getPoint();
                pointCarte = viewPort.getViewPosition();
            }
        });
        
        layeredPane.addMouseMotionListener(new MouseInputAdapter() {
            @Override
            public void mouseDragged(MouseEvent e) {
                pointCarte.x += pointSouris.x - e.getPoint().x;
                pointCarte.y += pointSouris.y - e.getPoint().y;
                pointSouris = e.getPoint();
                viewPort.setViewPosition(pointCarte);
            }
        });
        
        layeredPane.addMouseWheelListener(new MouseInputAdapter() {
            @Override
            public void mouseWheelMoved(MouseWheelEvent e) {
                //TiledMapComponent t = tiledMapComponent;
                tiledMapComponent.setZoom(tiledMapComponent.zoom()-e.getWheelRotation());
                //Point p = SwingUtilities.convertPoint(t, e.getPoint(), null);
                
                pointCarte = viewPort.getViewPosition();
                
                pointCarte.x += e.getPoint().x;
                pointCarte.y += e.getPoint().y;

                pointCarte.x = (int)(pointCarte.x*Math.pow(2, -e.getWheelRotation()));
                pointCarte.y = (int)(pointCarte.y*Math.pow(2, -e.getWheelRotation()));
                
                pointCarte.x -= e.getPoint().x;
                pointCarte.y -= e.getPoint().y;
                
                System.out.println(pointCarte.x);
                
                
                viewPort.setViewPosition(pointCarte);
                tiledMapComponent.repaint();
                
                
            }
        });

        // TODO déplacement de la carte à la souris
        // TODO zoom de la carte à la souris (molette)

        JPanel centerPanel = new JPanel(new BorderLayout());
        centerPanel.add(layeredPane, BorderLayout.CENTER);
        return centerPanel;
    }

    private JPanel createCopyrightPanel() {
        Icon tlIcon = new ImageIcon(getClass().getResource("/images/tl-logo.png"));
        String copyrightText = "Données horaires 2013. Source : Transports publics de la région lausannoise / Carte : © contributeurs d'OpenStreetMap";
        JLabel copyrightLabel = new JLabel(copyrightText, tlIcon, SwingConstants.CENTER);
        copyrightLabel.setOpaque(true);
        copyrightLabel.setForeground(new Color(1f, 1f, 1f, 0.6f));
        copyrightLabel.setBackground(new Color(0f, 0f, 0f, 0.4f));
        copyrightLabel.setBorder(BorderFactory.createEmptyBorder(3, 0, 5, 0));

        JPanel copyrightPanel = new JPanel(new BorderLayout());
        copyrightPanel.add(copyrightLabel, BorderLayout.PAGE_END);
        copyrightPanel.setOpaque(false);
        return copyrightPanel;
    }

    private void start() {
        JFrame frame = new JFrame("Isochrone TL");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        frame.getContentPane().setLayout(new BorderLayout());
        frame.getContentPane().add(createCenterPanel(), BorderLayout.CENTER);

        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    new IsochroneTL().start();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });
    }
}
