package ui.view;

import ui.controller.Control;
import ui.model.Model;

import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.plaf.basic.BasicSliderUI;
import java.awt.*;
import java.awt.event.*;

/**
 * This Class represents a Panel where the User can start and stop the
 * Simulation. He Can also reset the Simulation and click through every
 * Iteration.
 * 
 * @author Gruppe14
 */
public class TimePanel extends JPanel {

	private static final long serialVersionUID = 1L;
	final JButton playBtn = new JButton();
	final JButton timeResetBtn = new JButton();
	final JButton timeForwardBtn = new JButton();
	;
	final JButton timeBackwardBtn = new JButton();
	private final JPanel btnAndSpeedPanel = new JPanel();
	private final JPanel speedPanel = new JPanel();
	private final JPanel timeBtnPanel = new JPanel();
	JSlider timeSlider = new JSlider() {
		/**
		 *
		 */
		private static final long serialVersionUID = 1L;

		{
			// Make the slider jump to mouse position on left click
			MouseListener[] listeners = getMouseListeners();
			for (MouseListener l : listeners)
				removeMouseListener(l); // remove UI-installed TrackListener
			final BasicSliderUI ui = (BasicSliderUI) getUI();
			BasicSliderUI.TrackListener tl = ui.new TrackListener() {
				// this is where we jump to absolute value of click
				@Override
				public void mouseClicked(MouseEvent e) {
					Point p = e.getPoint();
					int value = ui.valueForXPosition(p.x);

					setValue(value);
				}

				// disable check that will invoke scrollDueToClickInTrack
				@Override
				public boolean shouldScroll(int dir) {
					return false;
				}
			};
			addMouseListener(tl);
		}
	};
	private Model model;
	private Control controller;
	private int dragResetIteration = 0;
	private JLabel simSpeedLabel = new JLabel("Speed:");
	private JSlider speedSlider = new JSlider();
	private Timer timer;
	private boolean running = false;

	/**
	 * Constructor.
	 * 
	 * @param mod
	 *            the Model
	 * @param cont
	 *            the Controller
	 */
	public TimePanel(Model mod, Control cont) {
		super();
		this.model = mod;
		this.controller = cont;

		// One Iteration
		timer = new Timer(0, new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent ae) {
				timeSlider.setValue(timeSlider.getValue() + 1);
				controller.setCurIteration(timeSlider.getValue());
				timer.setDelay(model.getTimerSpeed());
				if (timeSlider.getValue() == model.getIterations() - 1) {
					running = false;
					playBtn.setIcon(new ImageIcon(new ImageIcon(this.getClass().getResource("/Button_Images/play.png"))
							.getImage().getScaledInstance(30, 30, Image.SCALE_SMOOTH)));
					timer.stop();
				}
			}
		});

		// Time Slider. Panels and Buttons
		this.setLayout(new BorderLayout(0, 0));
		this.setBorder(null);
		// Slider
		timeSlider.setPaintTicks(true);
		timeSlider.setPaintLabels(true);
		timeSlider.setMinorTickSpacing(1);
		timeSlider.setMajorTickSpacing(5);
		timeSlider.setToolTipText(Languages.getLanguage()[93]);
		timeSlider.setMaximum(model.getIterations() - 1);
		timeSlider.setValue(0);
		timeSlider.addChangeListener(changeEvent -> controller.setCurIteration(timeSlider.getValue()));

		timeSlider.addMouseListener(new MouseAdapter() {
			@Override
			public void mousePressed(MouseEvent e) {
				dragResetIteration = model.getCurIteration();
			}
		});

		timeSlider.addMouseMotionListener(new MouseAdapter() {
			@Override
			public void mouseDragged(MouseEvent e) {
				if (dragResetIteration != model.getCurIteration()) {
					controller.resetSimulation();
					if (running) {
						playBtn.doClick();
					}
				}
			}
		});

		// Panel
		timeBtnPanel.setBorder(null);
		timeBtnPanel.setLayout(new FlowLayout(FlowLayout.CENTER));

		// Buttons
		playBtn.setToolTipText(Languages.getLanguage()[89]);

		playBtn.setContentAreaFilled(false);
		playBtn.setBorderPainted(false);
		playBtn.setBorder(null);
		playBtn.setIcon(new ImageIcon(Util.loadImage(this, "/Button_Images/play.png",30,30)));
		playBtn.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				running = !running;
				playBtn.setIcon(new ImageIcon(Util.loadImage(this,"/Button_Images/pause.png",30,30)));//relocated this here. as it was duplicate before.
				if (running) {
					if (!model.getIsSimRunning()) {
						controller.setIsSimRunning(true);
					}
					timer.start();
					timer.setDelay(model.getTimerSpeed());
					//playBtn.setIcon(new ImageIcon(Util.loadImage(this,"/Button_Images/pause.png",30,30)));
				} else {
					timer.stop();
					//playBtn.setIcon(new ImageIcon(Util.loadImage(this,"/Button_Images/pause.png",30,30)));
				}
			}
		});
		timeResetBtn.setToolTipText(Languages.getLanguage()[90]);

		timeResetBtn.setContentAreaFilled(false);
		timeResetBtn.setBorder(null);
		timeResetBtn.setIcon(new ImageIcon(Util.loadImage(this, "/Button_Images/reset.png", 30, 30)));
		timeResetBtn.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent ae) {
				timeSlider.setValue(timeSlider.getMinimum());
				controller.setCurIteration(timeSlider.getValue());
				// controller.calculateStateForCurrentTimeStep();
				controller.resetSimulation();
				if (running) {
					playBtn.doClick();
				}
			}
		});
		timeForwardBtn.setToolTipText(Languages.getLanguage()[91]);

		timeForwardBtn.setContentAreaFilled(false);
		timeForwardBtn.setBorder(null);
		timeForwardBtn.setIcon(new ImageIcon(Util.loadImage(this,"/Button_Images/forward.png",30,30)));
		timeForwardBtn.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent ae) {
				if (!model.getIsSimRunning()) {
					controller.setIsSimRunning(true);
				}
				timeSlider.setValue(timeSlider.getValue() + 1);
				controller.setCurIteration(timeSlider.getValue());
			}
		});
		timeBackwardBtn.setToolTipText(Languages.getLanguage()[92]);

		timeBackwardBtn.setBorder(null);
		timeBackwardBtn.setIcon(new ImageIcon(Util.loadImage(this, "/Button_Images/backward.png", 30,30)));
		timeBackwardBtn.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent ae) {
				timeSlider.setValue(timeSlider.getValue() - 1);
				controller.setCurIteration(timeSlider.getValue());
			}
		});

		timeBtnPanel.add(playBtn);
		timeBtnPanel.add(Box.createRigidArea(new Dimension(10, 0)));
		timeBtnPanel.add(timeResetBtn);
		timeBtnPanel.add(Box.createRigidArea(new Dimension(10, 0)));
		timeBtnPanel.add(timeForwardBtn);

		// Speed Panel
		speedPanel.add(simSpeedLabel);
		speedPanel.add(speedSlider);
		speedSlider.setPaintTicks(true);
		speedSlider.setPaintLabels(true);
		speedSlider.setMaximum(5000);
		speedSlider.setMinimum(500);
		speedSlider.setValue(1000);
		// speedSlider.setMajorTickSpacing(100);
		speedSlider.addChangeListener(new ChangeListener() {
			@Override
			public void stateChanged(ChangeEvent e) {
				controller.setTimerSpeed(speedSlider.getValue());
				speedSlider.setToolTipText("Speed: " + speedSlider.getValue());
			}
		});

		// Buttons and Speed Panel
		btnAndSpeedPanel.setLayout(new BorderLayout(0, 0));
		btnAndSpeedPanel.setBorder(null);
		btnAndSpeedPanel.add(timeBtnPanel, BorderLayout.NORTH);
		btnAndSpeedPanel.add(speedPanel, BorderLayout.CENTER);

		this.add(btnAndSpeedPanel, BorderLayout.WEST);
		this.add(timeSlider);

		//Disable Keys
		timeSlider.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, false), "UP_ARROW");
		timeSlider.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, false), "DOWN_ARROW");
		timeSlider.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN, 0, false), "PAGE_DOWN");
		timeSlider.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP, 0, false), "PAGE_UP");
		timeSlider.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_END, 0, false), "END");
		timeSlider.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_HOME, 0, false), "HOME");
		
		// Left arrow Key
		timeSlider.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, false), "LEFT_ARROW");
		timeSlider.getActionMap().put("LEFT_ARROW", new AbstractAction() {
			private static final long serialVersionUID = 1L;

			@Override
			public void actionPerformed(ActionEvent e) {
				timeSlider.setValue(timeSlider.getValue() - 1);
				controller.resetSimulation();
			}
		});
		
		//Right arrow Key
		timeSlider.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, false), "Right_ARROW");
		timeSlider.getActionMap().put("Right_ARROW", new AbstractAction() {
			private static final long serialVersionUID = 1L;

			@Override
			public void actionPerformed(ActionEvent e) {
				if (!model.getIsSimRunning()) {
					controller.setIsSimRunning(true);
				}
				timeSlider.setValue(timeSlider.getValue() + 1);
			}
		});
	}

	/**
	 * Retunrs the TimeSlider.
	 * 
	 * @return the TimeSlider
	 */
	public JSlider getTimeSlider() {
		return timeSlider;
	}
}
