package View;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Frame;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

import Controler.Parsor.ArduinoParsor;
import Controler.Parsor.JPenParsor;
import Controler.Parsor.ParsorListener;
import Model.IPoint;
import Model.Point;


public class DrawingFrame extends JFrame implements ParsorListener {

	private static final long serialVersionUID = 1L;
	public static final int SOURCE_DS = 0;
	public static final int SOURCE_TABLET = 1;

	public static int delayBetweenLines = 80; // in ms

	private ArduinoParsor arduinoParsor;
	private JPenParsor jPenParsor;

	private int source = SOURCE_DS;

	private long systemLastTime;
	private Point2D.Double lastPoint;
	private JPanel acquisitionPanel;
	private Graphics2D g2d;
	private long firstPointTime;

	private List<List<IPoint>> acquisitions;
	private List<IPoint> currentAcquisition;
	private JButton next;
	private OngletApprentissage ongletApprentissage;
	private OngletIdentification ongletIdentification;
	private int numberOfAcquisitions;
	private List<IPoint> fossaire;


	public DrawingFrame(OngletApprentissage ongletApprentissage, int numberOfAcquisitions, int source) {
		this(numberOfAcquisitions, source);
		this.ongletApprentissage = ongletApprentissage;

		newAcquisition();

	}

	public DrawingFrame(OngletIdentification ongletIdentification, int numberOfAcquisitions, int source) {
		this(numberOfAcquisitions, source);
		this.ongletIdentification = ongletIdentification;

		if(ongletIdentification != null 
				&& ongletIdentification.getUser() != null 
				&& ongletIdentification.getFaussaire()) {

			fossaire = ongletIdentification.getUser().getUserSignature().getAcquisitions().get(0).getAcquisitionPoints();
		}

		newAcquisition();
	}

	private DrawingFrame(final int numberOfAcquisitions, int source) {

		this.acquisitions = new ArrayList<List<IPoint>>();
		this.numberOfAcquisitions = numberOfAcquisitions;

		this.source = source;

		this.setTitle("Votre signature");
		this.setExtendedState(Frame.MAXIMIZED_BOTH);
		this.setLocationRelativeTo(null);
		this.setAlwaysOnTop(true);
		this.setVisible(true);


		next = new JButton();		

		next.addActionListener( new ActionListener(){
			public void actionPerformed(ActionEvent e){

				try {
					next.setEnabled(false);
					saveAcquisition();

					if(acquisitions.size() == numberOfAcquisitions) {
						if(arduinoParsor != null) {
							arduinoParsor.unsubscribe(DrawingFrame.this);
							arduinoParsor.close();
						}
						if(jPenParsor != null) {
							jPenParsor.unsubscribe(DrawingFrame.this);
						}

						if(ongletApprentissage != null) {
							ongletApprentissage.setAcquisitionsWorked();
						}
						if(ongletIdentification != null) {
							ongletIdentification.setAcquisitionWorked();
						}

						dispose();
					} else {
						newAcquisition();
					}
				} catch(IOException ex) {
					ex.printStackTrace();
				}
			}
		});

		addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				
				if(arduinoParsor != null) {
					arduinoParsor.unsubscribe(DrawingFrame.this);
					arduinoParsor.close();
				}
				if(jPenParsor != null) {
					jPenParsor.unsubscribe(DrawingFrame.this);
				}

				
				dispose();
			}
		});

		JButton clean = new JButton("Recommencer");
		clean.addActionListener( new ActionListener(){
			public void actionPerformed(ActionEvent e){
				newAcquisition();
			}
		});

		acquisitionPanel = new JPanel();
		acquisitionPanel.setLayout(new BorderLayout());
		acquisitionPanel.setBackground(Color.white);

		JPanel bot = new JPanel();

		bot.add(clean);
		bot.add(next);

		acquisitionPanel.add(bot, BorderLayout.SOUTH);
		this.setContentPane(acquisitionPanel);

		if(source == SOURCE_DS) {
			arduinoParsor = new ArduinoParsor();
			arduinoParsor.subscribe(this);
		} else {
			jPenParsor = new JPenParsor(acquisitionPanel);
			jPenParsor.subscribe(this);
		}	

		g2d = (Graphics2D)getGraphics();

		g2d.setRenderingHint(RenderingHints.KEY_RENDERING,
				RenderingHints.VALUE_RENDER_QUALITY);
		g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,
				RenderingHints.VALUE_STROKE_PURE);
		g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
				RenderingHints.VALUE_ANTIALIAS_ON);


	}

	private void clearScreen() {
		g2d.setColor(Color.WHITE);
		g2d.fillRect(0, 0, getWidth(), getHeight()-50);
	}

	private void newAcquisition(){
		clearScreen();
		firstPointTime = 0;
		lastPoint = null;
		systemLastTime = getSystemTime();
		currentAcquisition = new ArrayList<IPoint>();
		next.setEnabled(false);
		if(acquisitions.size() == numberOfAcquisitions - 1) {
			next.setText("Terminer");
		} else {
			next.setText("Suivant ("+(acquisitions.size()+1)+"/"+numberOfAcquisitions+")");
		}		

		if(fossaire != null) {
			new Thread() {
				public void run() {
					try {
						Thread.sleep(300);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					drawSignature(fossaire);	
				}
			}.start();

		}
	}

	public void saveAcquisition() {
		acquisitions.add(currentAcquisition);
	}

	public List<List<IPoint>> getAcquisitions(){
		return acquisitions;
	}

	@Override
	public void parsorCoordinates(Point2D.Double point, int pressure) {

		if(source == SOURCE_TABLET && pressure <= 0) {
			return;
		}

		if(getSystemTime() - systemLastTime > delayBetweenLines) {
			lastPoint = null;
		}

		addPoint(point);

		if(firstPointTime == 0) {
			firstPointTime = getSystemTime();
			next.setEnabled(true);
		}

		Point2D.Double loc = new Point2D.Double();
		loc.x = point.x;
		loc.y = point.y;

		currentAcquisition.add(new Point(loc, pressure, getSystemTime() - firstPointTime));	

		if(lastPoint == null) {
			lastPoint = new Point2D.Double();
		}

		systemLastTime = getSystemTime();
		lastPoint.x = point.x;
		lastPoint.y = point.y;
	}

	private long getSystemTime() {
		return System.currentTimeMillis();
	}

	public void addPoint(Point2D.Double point) {

		if(lastPoint != null) {
			g2d.setColor(Color.BLACK);			
			Point2D.Double tempPoint1 = new Point2D.Double(point.x+10, point.y+30);
			Point2D.Double tempPoint2 = new Point2D.Double(lastPoint.x+10, lastPoint.y+30);
			g2d.draw(new Line2D.Double(tempPoint1, tempPoint2));
		} 


	}

	private void drawSignature(List<IPoint> list) {

		IPoint lastPoint2 = null;

		for(IPoint point2 : list) {
			if(lastPoint2 != null && point2.getTime() - lastPoint2.getTime() < DrawingFrame.delayBetweenLines) {
				g2d.setColor(Color.LIGHT_GRAY);
				g2d.draw(new Line2D.Double(lastPoint2.getPoint(), point2.getPoint()));
			}

			lastPoint2 = point2;
		}

	}

}
