package engine;

import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;

import engine.Game.STATE;
import hud.Clock;
import hud.Map;
import hud.RightClickMenu;
import hud.SecondaryHUD;
import hud.SecondaryHUD.TAB;
import hud.constructionmenu.ConstructionItem;
import hud.constructionmenu.ConstructionMenu;
import hud.constructionmenu.ConstructionMenuCategory;
import hud.inventory.Inventory;
import hud.inventory.InventorySlot;
import player.MouseMovement;
import player.Player;
import utils.Utils;
import world.DroppedItem;
import world.Tile;
import worldGen.WorldGenerator;

/*  ------------- Nihilne ------------
    * Created by Mitch Weaver - 2016 *
      ~~~~ All Rights Reserved ~~~~ */

public final class MouseInput implements MouseListener, MouseWheelListener, MouseMotionListener {

	public static final Point mouseXY = new Point(0, 0), rightClickPos = new Point(0, 0);
	public static final Point clickPos = new Point(0, 0);
	public static final Point adjustedMouseXY = new Point(0,0);
	public static final Point adjustedClickPos = new Point(0, 0);
	public static final Point adjustedRightClickPos = new Point(0,0);
	private static final Point TEMP = new Point(0,0);
	
	public static boolean mouseClicked, mousePressed, mouseRightClicked, mouseDragged;

	public final void mouseClicked(MouseEvent e) {
		
		if (e.getButton() == 2) { Game.scaleFactor = Game.MAX_SCALEFACTOR; } // middle click

		if (e.getButton() == 3) {
			if(Game.state == STATE.GAME) {
				rightClickPos.x = e.getX(); rightClickPos.y = e.getY();
				adjustedRightClickPos.x = adjustedMouseXY.x; adjustedRightClickPos.y = adjustedMouseXY.y;
				RightClickMenu.OVERRIDE_F = RightClickMenu.OVERRIDE_SPACE = false;
				RightClickMenu.determineText();
			}
		}

		if (e.getButton() == 1) {
			clickPos.x = e.getX(); clickPos.y = e.getY();
			if (Game.state == STATE.GAME) {
				if(!WorldGenerator.WORLD_GENERATED) return;
				
				Player.using = Player.attacking = false;
				
				if(ConstructionItem.PLACING){
					MouseMovement.PLACING_STRUCTURE = true; 
					Tile.pointToCheck.x = MouseInput.adjustedClickPos.x;
					Tile.pointToCheck.y = MouseInput.adjustedClickPos.y;
					return; 
				}
				
				if (RightClickMenu.menuOpen()) { RightClickMenu.onClick(); return; }
				else RightClickMenu.OVERRIDE_F = RightClickMenu.OVERRIDE_SPACE = false;
				
				Inventory.onLeftClick(); 
				ConstructionMenuCategory.onClick();
				
				
				mouseXY.x = e.getX(); mouseXY.y = e.getY();
				TEMP.x = (int)(mouseXY.x * Math.cos(-Utils._45 * (Game.rotation - 1)) - (mouseXY.y * Math.sin(-Utils._45 * (Game.rotation - 1))));
				TEMP.y = (int)(mouseXY.x * Math.sin(-Utils._45 * (Game.rotation - 1)) + (mouseXY.y * Math.cos(-Utils._45 * (Game.rotation - 1))));
				adjustedMouseXY.x = (int)(TEMP.x  / Game.scaleFactor - Camera.x);
				adjustedMouseXY.y = (int)(TEMP.y  / Game.scaleFactor - Camera.y);
				
				if(!validClick()) return;
				
				Player.keepWalkingX = Player.keepWalkingY = true;
				adjustedClickPos.x = adjustedMouseXY.x; adjustedClickPos.y = adjustedMouseXY.y;
			} else if (Game.state == STATE.MENU) Game.menu.onClick();
			  else if (Game.state == STATE.SETTINGS) Game.settings.onClick();
			  else if (Game.state == STATE.PAUSED) PauseMenu.onClick();
			  else if (Game.state == STATE.MAP) { Map.hasBeenClicked = true; }
		}
	}
	
	public final static void tick() {
		if (mousePressed) {
			if (Game.state == STATE.GAME) {
				if (RightClickMenu.menuOpen()) { return; }
				if(!WorldGenerator.WORLD_GENERATED) return;
				clickPos.x = mouseXY.x; clickPos.y = mouseXY.y;
				
				// if the click on the component is inside any inventories / menus etc, do not calc mouse movement
				if (!validClick()) return;

				Player.keepWalkingX = Player.keepWalkingY = true;
				
				adjustedClickPos.x = adjustedMouseXY.x;
				adjustedClickPos.y = adjustedMouseXY.y;
			}
		}
		
		if(MouseMovement.PLACING_STRUCTURE && (!Player.keepWalkingX || !Player.keepWalkingY)){
			// REFUND ITEM COSTS
			for(int i = 0; i < ConstructionItem.TEMP.price.length; i++)
			if(Inventory.isFull(ConstructionItem.TEMP.price[i].itemId, ConstructionItem.TEMP.price[i].quantity)) DroppedItem.dropItemsWithOffset(ConstructionItem.TEMP.price[i].itemId, ConstructionItem.TEMP.price[i].quantity, 40, Player.center.x, Player.center.y, 50);
			else Inventory.addItem( ConstructionItem.TEMP.price[i].itemId,  ConstructionItem.TEMP.price[i].quantity, 50);
			
			//CANCEL all booleans
			ConstructionItem.PLACING = Tile.drawHighLighted = MouseMovement.PLACING_STRUCTURE = false;
			
			//RESET TILES
			Tile.resetAllHighlighted();
		}
	}

	public final static boolean validClick() {
		// if currently holding an item, don't move
		for (InventorySlot i : Player.inventorySlots) if (i.mouseClicked) return false;
			
		// if in inventory
		if (Inventory.INVENTORY_BOUNDS.contains(clickPos)) return false;

		// if in secondary hud
		if (SecondaryHUD.tab == TAB.MINIMIZED && SecondaryHUD.minimizedBounds.contains(clickPos)) return false;
		else if (!(SecondaryHUD.tab == TAB.MINIMIZED) && SecondaryHUD.maximizedBounds.contains(clickPos)) return false;

		// if inside clock
		if (MouseInput.clickPos.x > (Game.game.getWidth() / 1.08 - Clock.width / 2) && MouseInput.clickPos.x < (Game.game.getWidth() / 1.08 + Clock.width / 2))
			if (MouseInput.clickPos.y < (Game.game.getHeight() / 7.75 + Clock.height / 2) && MouseInput.clickPos.y > (Game.game.getHeight() / 7.75 - Clock.height / 2))
				return false;

		// if inside construction tabs
		if(ConstructionMenu.bounds.contains(clickPos)) return false;
		
		// if inside construction menu
		for(ConstructionMenuCategory cmg : ConstructionMenuCategory.categories)
			if(cmg.selected && cmg.bounds.contains(clickPos) || ConstructionMenuCategory.menuBounds.contains(clickPos)) return false;
		
		return true;
	}

	public final void mousePressed(MouseEvent e) {
		if (e.getButton() == 1 && (Game.state == STATE.GAME || Game.state == STATE.MAP)) mousePressed = true;
	}

	public final void mouseReleased(MouseEvent e) {
		mousePressed = Map.clicked = false;
	}

	public final void mouseEntered(MouseEvent e) {
	}	

	public final void mouseExited(MouseEvent e) {
	}

	private final static double MAX_MAP = 12;
	public final void mouseWheelMoved(MouseWheelEvent e) {
		if(Game.state == STATE.GAME){
			if(!WorldGenerator.WORLD_GENERATED) return;
			Game.scaleFactor += -e.getPreciseWheelRotation() / 10;
			Game.scaleFactor = Utils.clamp(Game.scaleFactor, Game.MIN_SCALEFACTOR, Game.MAX_SCALEFACTOR);
		} else if(Game.state == STATE.MAP){
			Map.scaleFactor += -e.getPreciseWheelRotation() / 5;
			Map.scaleFactor = Utils.clamp(Map.scaleFactor, 0.75d, MAX_MAP);
		}
	}

	public final void mouseDragged(MouseEvent e) {
			mouseXY.x = e.getX(); mouseXY.y = e.getY(); /* NOTE: YOU DO NEED THIS DO NOT DELETE! */
			if(Game.state == STATE.GAME){
				TEMP.x = (int)(mouseXY.x * Math.cos(-Utils._45 * (Game.rotation - 1)) - (mouseXY.y * Math.sin(-Utils._45 * (Game.rotation - 1))));
				TEMP.y = (int)(mouseXY.x * Math.sin(-Utils._45 * (Game.rotation - 1)) + (mouseXY.y * Math.cos(-Utils._45 * (Game.rotation - 1))));
				adjustedMouseXY.x = (int)(TEMP.x  / Game.scaleFactor - Camera.x);
				adjustedMouseXY.y = (int)(TEMP.y  / Game.scaleFactor - Camera.y);
			} else if(Game.state == STATE.MAP) {
					if (Map.mapBounds.contains(mouseXY.x, mouseXY.y)){
						if(!Map.clicked){ clickPos.x = mouseXY.x; clickPos.y = mouseXY.y; }
						Map.clicked = Map.hasBeenClicked = true; 
				}
			}
	}

	public final void mouseMoved(MouseEvent e) {
		mouseXY.x = e.getX(); mouseXY.y = e.getY();
		TEMP.x = (int)(mouseXY.x * Math.cos(-Utils._45 * (Game.rotation - 1)) - (mouseXY.y * Math.sin(-Utils._45 * (Game.rotation - 1))));
		TEMP.y = (int)(mouseXY.x * Math.sin(-Utils._45 * (Game.rotation - 1)) + (mouseXY.y * Math.cos(-Utils._45 * (Game.rotation - 1))));
		adjustedMouseXY.x = (int)(TEMP.x  / Game.scaleFactor - Camera.x);
		adjustedMouseXY.y = (int)(TEMP.y  / Game.scaleFactor - Camera.y);
	}

}