package scriptbuilder.gui.panels;

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseEvent;
import javax.swing.JPanel;
import javax.swing.event.MouseInputAdapter;
import scriptbuilder.gui.ScriptBuilderFrame;
import scriptbuilder.gui.ScriptBuilderGuiConstants;
import scriptbuilder.gui.drawers.EventIconDrawer;
import scriptbuilder.structures.ScriptIncident;
import scriptbuilder.structures.SimulationScript;

/**
 * Represents the underlying panel on the main timeline. All the
 * IncidentTimelinePanel objects sit over it. This panel draws all the
 * per-minute ticks on the timeline, and adjusts and scales them as necessary.
 *
 * @author Greg Eddington <geddingt@calpoly.edu>
 * @author Bryan McGuffin
 */
public class TimelineTickPanel extends JPanel
{

    private int longestLength = ScriptBuilderGuiConstants.TICK_TIMELINE_SMALLEST_LENGTH;
    private int x, y;
    private boolean focused = false;

    public void setZoom(float zoom)
    {
        repaint();
    }

    /**
     * Listener for the mouse. Is notified when the mouse enters, exits, or
     * moves around on the panel.
     */
    public class TimelineTickMouseListener extends MouseInputAdapter
    {

        /**
         * When the mouse enters the panel, the panel gets focus.
         *
         * @param e the mouse event
         */
        @Override
        public void mouseEntered(MouseEvent e)
        {
            focused = true;
        }

        /**
         * When the mouse leaves the panel, the panel loses focus and refreshes.
         *
         * @param e the mouse event
         */
        @Override
        public void mouseExited(MouseEvent e)
        {
            focused = false;
            repaint();
        }

        /**
         * When the mouse moves around in the panel, the panel refreshes and
         * updates its mouse tracker.
         *
         * @param e
         */
        @Override
        public void mouseMoved(MouseEvent e)
        {
            x = e.getX();
            y = e.getY();

            repaint();
        }
    }

    /**
     * Constructor. Set up the mouse listener.
     */
    public TimelineTickPanel()
    {
        super();

        TimelineTickMouseListener mouseListener
                = new TimelineTickMouseListener();
        addMouseMotionListener(mouseListener);
        addMouseListener(mouseListener);
    }

    /**
     * Update the panel's dimensions based on number of events, zoom level, and
     * which events are collapsed.
     *
     * @param script The main script model
     */
    public void update(SimulationScript script)
    {
        longestLength = ScriptBuilderGuiConstants.TICK_TIMELINE_SMALLEST_LENGTH;

        // Get the stats on the incidents
        int height = ScriptBuilderGuiConstants.TICK_TOP_MARGIN * 4;
        for (ScriptIncident incident : script.incidents)
        {
            if (incident != null)
            {
                height += incident.collapsed
                        ? ScriptBuilderGuiConstants.TIMELINE_OPENED_HEIGHT
                        : ScriptBuilderGuiConstants.TIMELINE_OPENED_HEIGHT;
                if ((incident.length + incident.offset) > longestLength)
                {
                    longestLength = incident.length + incident.offset;
                }
            }
        }

        Dimension newSize = new Dimension(longestLength
                / ScriptBuilderGuiConstants.HORIZONTAL_TICK_RESOLUTION
                * ScriptBuilderGuiConstants.PIXEL_WIDTH_PER_HORIZONTAL_TICK
                + ScriptBuilderGuiConstants.TICK_TIMELINE_LEFT_MARGIN + 50,
                height);
        this.setPreferredSize(newSize);
        this.setSize(newSize);

        this.invalidate();
    }

    /**
     * Refresh the panel. Redraw the ticks based on zoom level, panel
     * dimensions, and offset. If the user is trying to add an event, draw that
     * event's icon under the mouse.
     *
     * @param g The graphics component
     */
    @Override
    public void paint(Graphics g)
    {
        super.paint(g);

        Graphics2D g2d = (Graphics2D) g;

        // Draw the horizontal line
        g2d.setFont(ScriptBuilderGuiConstants.TIMELINE_TICK_TIME_FONT);
        g2d.setColor(ScriptBuilderGuiConstants.TIMELINE_TICK_COLOR);
        g2d.fillRect(0, ScriptBuilderGuiConstants.TICK_TIMELINE_TOP_MARGIN,
                longestLength, ScriptBuilderGuiConstants.TICK_TIMELINE_HEIGHT);

        // Draw the ticks
        int longestLengthPlusMargin = longestLength
                / ScriptBuilderGuiConstants.HORIZONTAL_TICK_RESOLUTION
                * ScriptBuilderGuiConstants.PIXEL_WIDTH_PER_HORIZONTAL_TICK
                + ScriptBuilderGuiConstants.TICK_TIMELINE_LEFT_MARGIN;

        // Minutes
        g2d.setColor(ScriptBuilderGuiConstants.MINOR_TICK_COLOR);
        int seconds = 0;
        for (int i = ScriptBuilderGuiConstants.TICK_TIMELINE_LEFT_MARGIN;
                i <= longestLengthPlusMargin;
                i += ScriptBuilderGuiConstants.PIXEL_WIDTH_PER_HORIZONTAL_TICK, seconds += ScriptBuilderGuiConstants.HORIZONTAL_TICK_RESOLUTION)
        {
            g2d.drawLine(i, ScriptBuilderGuiConstants.TICK_TOP_MARGIN,
                    i, ScriptBuilderGuiConstants.TICK_HEIGHT);
        }

        // Major Ticks
        g2d.setColor(ScriptBuilderGuiConstants.TIMELINE_TICK_COLOR);
        seconds = 0;
        for (int i = ScriptBuilderGuiConstants.TICK_TIMELINE_LEFT_MARGIN;
                i <= longestLengthPlusMargin;
                i += ScriptBuilderGuiConstants.PIXEL_WIDTH_PER_HORIZONTAL_TICK
                * ScriptBuilderGuiConstants.TICKS_PER_MAJOR_TICK, seconds += ScriptBuilderGuiConstants.HORIZONTAL_TICK_RESOLUTION
                * ScriptBuilderGuiConstants.TICKS_PER_MAJOR_TICK)
        {
            g2d.drawLine(i, ScriptBuilderGuiConstants.TICK_TOP_MARGIN,
                    i, ScriptBuilderGuiConstants.TICK_HEIGHT);

        }

        paintChildren(g);

        if (focused
                && ((ScriptBuilderFrame) this.getTopLevelAncestor()).currentEventType != null)
        {
            EventIconDrawer.DrawEventIcon(g2d,
                    ((ScriptBuilderFrame) this.getTopLevelAncestor()).currentEventType,
                    x, y);
        }
    }
}
