package io.github.rowak.nanoleafdesktop.ui.panel.panelcanvas;

import java.awt.Cursor;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;

import javax.swing.SwingUtilities;

import io.github.rowak.nanoleafapi.Aurora;
import io.github.rowak.nanoleafapi.Panel;
import io.github.rowak.nanoleafapi.StatusCodeException;

public class PanelActionListener extends MouseAdapter
{
	private int lastXDiff;
	private int deviceIndex;
	private Panel[][] panels, tempPanels;
	private Aurora[] devices;
	private Point mouseLast;
	private PanelCanvas canvas;
	
	public PanelActionListener(PanelCanvas canvas,
			Panel[][] panels, Aurora[] devices)
	{
		this.canvas = canvas;
		this.panels = panels;
		this.devices = devices;
		tempPanels = clonePanels(panels);
	}
	
	public Panel[][] getTempPanels()
	{
		return tempPanels;
	}
	
	public Panel[][] getPanels()
	{
		return panels;
	}
	
	private Panel[][] clonePanels(Panel[][] original)
	{
		Panel[][] temp = new Panel[original.length][];
		for (int i = 0; i < original.length; i++)
		{
			temp[i] = new Panel[original[i].length];
			for (int j = 0; j < original[i].length; j++)
			{
				Panel p = original[i][j];
				temp[i][j] = new Panel(p.getId(),
						p.getX(), p.getY(), p.getOrientation());
			}
		}
		return temp;
	}
	
	private void movePanelsUsingMouse(Point mouse)
	{
		if (deviceIndex != -1)
		{
			// ******* "Snappy" layouts DISABLED **********
//			int xdiff = roundToNearest(mouse.x - mouseLast.x, 150f/2f);
//			int ydiff = roundToNearest(mouse.y - mouseLast.y, 130f/2f);
			int xdiff = mouse.x - mouseLast.x;
			int ydiff = mouse.y - mouseLast.y;
			
			Point[] offset = canvas.getPanelOffset();
			offset[deviceIndex].setLocation(xdiff, ydiff);
			
			canvas.repaint();
		}
	}
	
	private void rotatePanelsUsingMouse(Point mouse)
	{
		if (deviceIndex != -1)
		{
			int xdiff = roundToNearest((mouse.x - mouseLast.x)/3, 10);
			int rotation = canvas.getTempRotation(deviceIndex) + xdiff - lastXDiff;
			canvas.setTempRotation(rotation, deviceIndex);
			lastXDiff = xdiff;
			canvas.repaint();
		}
	}
	
	private void scalePanelsUsingMouse(int rotationdiff)
	{
		float scaleFactor = canvas.getScaleFactor();
		scaleFactor += rotationdiff * 0.05f;
		if (scaleFactor > 0)
		{
			canvas.setScaleFactor(scaleFactor);
			canvas.repaint();
		}
	}
	
	@Override
	public void mousePressed(MouseEvent e)
	{
		if (mouseLast == null)
		{
			mouseLast = e.getPoint();
			canvas.setCursor(new Cursor(Cursor.MOVE_CURSOR));
			deviceIndex = getDeviceIndex(e.getPoint());
		}
	}
	
	@Override
	public void mouseReleased(MouseEvent e)
	{
		if (lastXDiff != 0)
		{
			canvas.setRotation(canvas.getTempRotation(
					deviceIndex), deviceIndex);
		}
		
		mouseLast = null;
		lastXDiff = 0;
		tempPanels = clonePanels(panels);
		if (deviceIndex != -1)
		{
			Point[] offset = canvas.getPanelOffset();
			final int di = deviceIndex;
			for (int i = 0; i < tempPanels[deviceIndex].length; i++)
			{
				tempPanels[di][i].setX(tempPanels[di][i].getX() + offset[di].x);
				tempPanels[di][i].setY(tempPanels[di][i].getY() + offset[di].y);
			}
			offset[deviceIndex] = new Point(0, 0);
			deviceIndex = -1;
		}
			
		panels = clonePanels(tempPanels);
		canvas.setPanels(panels);
		try
		{
			canvas.checkAuroraState();
		}
		catch (StatusCodeException sce)
		{
			sce.printStackTrace();
		}
		canvas.repaint();
		canvas.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
	}
	
	@Override
	public void mouseDragged(MouseEvent e)
	{
		if (mouseLast != null)
		{
			if (SwingUtilities.isLeftMouseButton(e))
			{
				movePanelsUsingMouse(e.getPoint());
			}
			else if (SwingUtilities.isRightMouseButton(e))
			{
				rotatePanelsUsingMouse(e.getPoint());
			}
		}
	}
	
	@Override
	public void mouseWheelMoved(MouseWheelEvent e)
	{
		scalePanelsUsingMouse(e.getWheelRotation());
	}
	
	private int getDeviceIndex(Point mouse)
	{
		for (int i = 0; i < tempPanels.length; i++)
		{
			String deviceType = getDeviceType(devices[i]);
			for (Panel p : tempPanels[i])
			{
				PanelShape shape = null;
				if (deviceType.equals("aurora"))
				{
					int o = p.getOrientation();
					if (o == 0 || Math.abs(o) % 120 == 0)
					{
						shape = new UprightPanel(p.getX(),
								p.getY(), canvas.getRotation(i));
					}
					else
					{
						shape = new InvertedPanel(p.getX(),
								p.getY(), canvas.getRotation(i));
					}
				}
				else if (deviceType.equals("canvas"))
				{
					shape = new SquarePanel(p.getX(),
							p.getY(), canvas.getRotation(i));
				}
				
				if (shape != null && shape.contains(mouse))
				{
					return i;
				}
			}
		}
		return -1;
	}
	
	private String getDeviceType(Aurora device)
	{
		String name = device.getName().toLowerCase();
		if (name.contains("light panels") ||
				name.contains("aurora"))
		{
			return "aurora";
		}
		else if (name.contains("canvas"))
		{
			return "canvas";
		}
		return "";
	}
	
	private int roundToNearest(int num, float factor)
	{
		return (int)(Math.ceil(num / (float)factor) * factor);
	}
}