package hud.inventory;

import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;

import org.python.core.PyFloat;
import org.python.core.PyFunction;
import org.python.core.PyInteger;

import _texture.loader.Textures;
import engine.Game;
import engine.MouseInput;
import hud.SecondaryHUD;
import interfaces.ItemIDs;
import interfaces.Python;
import player.Player;

/**  ------------- Nihilne ------------
    *** @author Mitch Weaver - 2016 ***
      ~~~~ All Rights Reserved ~~~~ */

public final class Inventory implements ItemIDs, Python {

	public static final int INVENTORY_WIDTH = 750, INVENTORY_HEIGHT = 110, SLOT_WIDTH = 84, SLOT_HEIGHT = 78;
	public static final Rectangle INVENTORY_BOUNDS = new Rectangle(0, 0, INVENTORY_WIDTH, INVENTORY_HEIGHT);
	
	public static final void init() {
		Player.inventorySlots = new InventorySlot[8];
		Player.inventorySlots[0] = (new InventorySlot(1, 0, 0, new Point(37, 22),  new Rectangle(0, 0, SLOT_WIDTH, SLOT_HEIGHT)));
		Player.inventorySlots[1] = (new InventorySlot(2, 0, 0, new Point(120, 22), new Rectangle(0, 0, SLOT_WIDTH, SLOT_HEIGHT)));
		Player.inventorySlots[2] = (new InventorySlot(3, 0, 0, new Point(205, 22), new Rectangle(0, 0, SLOT_WIDTH, SLOT_HEIGHT)));
		Player.inventorySlots[3] = (new InventorySlot(4, 0, 0, new Point(288, 22), new Rectangle(0, 0, SLOT_WIDTH, SLOT_HEIGHT)));
		Player.inventorySlots[4] = (new InventorySlot(5, 0, 0, new Point(370, 22), new Rectangle(0, 0, SLOT_WIDTH, SLOT_HEIGHT)));
		Player.inventorySlots[5] = (new InventorySlot(6, 0, 0, new Point(454, 22), new Rectangle(0, 0, SLOT_WIDTH, SLOT_HEIGHT)));
		Player.inventorySlots[6] = (new InventorySlot(7, 0, 0, new Point(538, 22), new Rectangle(0, 0, SLOT_WIDTH, SLOT_HEIGHT)));
		Player.inventorySlots[7] = (new InventorySlot(8, 0, 0, new Point(626, 22), new Rectangle(0, 0, SLOT_WIDTH, SLOT_HEIGHT)));
		initJythonScripts();
	}
	

/**************** ON CLICK *****************************************************************************************/
	public synchronized static final void onLeftClick() {
		SecondaryHUD.onLeftClick();
		
		// SLOT SWAPPING!
		/** @param i: The slot you are currently holding 
		 *  @param e: The slot you are trying to click on */
		for (final InventorySlot i : Player.inventorySlots) {
			// IF THE SLOT ISN'T CLICKED OR IS EMPTY DON'T BOTHER
			if (i.itemId == NULL_ITEM || !i.mouseClicked) continue;
			for (final InventorySlot e : Player.inventorySlots) {
				// IF THE SECOND SLOT CONTAINS THE MOUSE POINTER, AND THE TWO SLOTS AREN'T THE SAME, SWAP!
				if (e.bounds.contains(MouseInput.mouseXY)) {
					final int     tempId         = i.itemId;
					final int     tempQ          = i.quantity;
					final boolean tempEquippable = i.equippable;
					final float   tempDurability = i.durability;
					i.itemId    				 = e.itemId;
					i.quantity   				 = e.quantity;
					i.equippable 				 = e.equippable;
					i.durability 				 = e.durability;
					e.itemId     				 = tempId;
					e.quantity   				 = tempQ;
					e.equippable 			     = tempEquippable;
					e.durability 				 = tempDurability;
					e.mouseClicked = false;
					if(e.itemId == NULL_ITEM) resetMouseClicked();
					changeSettings();
					return; // NOTE: YOU MUST RETURN HERE OR IT WONT WORK!
				}
			}
		}
		
		// GRAPHICAL SLOT MOVING!
		for (final InventorySlot i : Player.inventorySlots) { if(i.itemId == NULL_ITEM) continue;
			// SET MOUSELCICKED TO TRUE
			if (i.bounds.contains(MouseInput.mouseXY)) {
				resetMouseClicked(); // ONLY WANT 1 ITEM TO BE MOUSE CLICKED AT A TIME
				i.mouseClicked = true;
				break;
			} 
			// IF HOLDING AN ITEM, AND CLICK OUTSIDE OF THE INVENTORY BOUNDS --- DROP
			else if (i.mouseClicked && !INVENTORY_BOUNDS.contains(MouseInput.mouseXY)) {
				dropItem(i.itemId, i.quantity, i.durability, i.slotNumber);
				i.mouseClicked = false;
				break;
			} 
			// ELSE IF YOU JUST CLICKED SOMEWHERE IN THE INVEN WITHOUT ON A SLOT LIKE AN IDIOT
			else {
				i.mouseClicked = false;
				i.pos.x = 37 + (SLOT_WIDTH * (i.slotNumber - 1)); i.pos.y = 22;
			}
		}
		
		// FIXES BUGS -- ALWAYS RUN THIS
		changeSettings();
	}
/*************** END ON CLICK *****************************************************************************************/
	
/************************************** TICK AND RENDER ***************************************************************************************************/
	private static int weightTimer; private static final int WEIGHT_TIMER_AMOUNT = 12;
	public final static void tick() {
		for (final InventorySlot i : Player.inventorySlots) 
			if (i.mouseClicked) { i.pos.x = MouseInput.mouseXY.x - SLOT_WIDTH/2; i.pos.y = MouseInput.mouseXY.y - SLOT_HEIGHT/2; }

		if (--weightTimer <= 0) {
			InvenHelper.calcWeight(); weightTimer = WEIGHT_TIMER_AMOUNT;
			/* REMOVE ITEMS WHEN DURABILITY GOES BELOW OR EQUALS ZERO */
			for (final InventorySlot i : Player.inventorySlots) if (i.itemId != NULL_ITEM && i.durability <= 0) removeItem(i.itemId, i.quantity, i.slotNumber);
			for (final InventorySlot i : Player.equipmentSlots) if (i.itemId != NULL_ITEM && i.durability <= 0) removeEquipment(i.itemId, i.quantity, i.slotNumber);
		}
	}
	
	private static InventorySlot tempSlot; private static int render_count = 3; /** @param render_count: no fucking idea why its 3, wrote this ages ago */
	public final static void render(final Graphics2D g2dCopy, final Graphics2D slotRenderer) {
		try { // draw base inventory / highlights if mouse hovered
			for (final InventorySlot i : Player.inventorySlots) {
				g2dCopy.drawImage(Textures.hudSheet[0], 0, 0, null); // BASE;
				if (i.bounds.contains(MouseInput.mouseXY)) {
					g2dCopy.drawImage(Textures.hudSheet[render_count], 0, 0, null); // highlighted
					break;
				} render_count++;
			}

			//NOTE:: quantities / etc are drawn in invenslot.render()
			
			// Render Player.inventorySlots
			for (final InventorySlot i : Player.inventorySlots) 
				if (!i.mouseClicked) i.render(g2dCopy); else tempSlot = i;
			

			if (tempSlot != null) tempSlot.render(slotRenderer);

			render_count = 3; /* reset counter */
			tempSlot = null;
		} catch (Exception e) { e.printStackTrace(); }
	}
	
/************************************** END TICK AND RENDER *****************************************************************************************************/

/********************************* ADDING AND REMOVING ITEMS ****************************************************************************************************/
	public final synchronized static void dropItem(final int itemId, final int quantity, final float durability, final int slotNumber) {
		drop_item.__call__(new PyInteger(itemId), new PyInteger(quantity), new PyFloat(durability), new PyInteger(slotNumber));
	}

	  public final synchronized static void addItem(final int itemId, final int quantity, final float durability) {
		add_item.__call__(new PyInteger(itemId), new PyInteger(quantity), new PyFloat(durability));
	} public final synchronized static void addItem(final int itemId, final int quantity) { addItem(itemId, quantity, 100); }
	  public final synchronized static void addItem(final int itemId) { addItem(itemId, 1, 100); }

	public final synchronized static void removeItem(final int itemId, final int quantity, final int slotNumber) {
		remove_item_with_slot_number.__call__(new PyInteger(itemId), new PyInteger(quantity), new PyInteger(slotNumber));
	}
	public final synchronized static void removeItem(int itemId, int quantity) {
		remove_item.__call__(new PyInteger(itemId), new PyInteger(quantity));
	}

	public final synchronized static void removeEquipment(final int itemId, final int quantity, final int slotNumber) {
		remove_equipment.__call__(new PyInteger(itemId), new PyInteger(quantity), new PyInteger(slotNumber));
	}
/********************************** END ADDING AND REMOVING ITEMS *********************************************************************************************************/
	
/**************************************** MISC ******************************************************************************************************************/
	public final static void changeSettings() {
		INVENTORY_BOUNDS.x = (int)(Game.game.getWidth() * 0.5f - INVENTORY_WIDTH * 0.5f);
		INVENTORY_BOUNDS.y = Game.game.getHeight() - INVENTORY_HEIGHT;

		for (final InventorySlot i : Player.inventorySlots) {
			if(!i.mouseClicked) { 
				i.pos.x = 37 + (SLOT_WIDTH * (i.slotNumber - 1)); i.pos.y = 22;
				i.bounds.x = i.pos.x + Game.game.getWidth() / 2 - INVENTORY_WIDTH / 2;
				i.bounds.y = Game.game.getHeight() - i.pos.y - SLOT_HEIGHT;
			}
			if(i.itemId == NULL_ITEM) i.mouseClicked = false;
		}

		SecondaryHUD.changeSettings();
	}
	
	public final static boolean isFull(final int itemId, final int quantity) {
		return isFull.__call__(new PyInteger(itemId), new PyInteger(quantity)).asInt() == 1;
	}
	public final static boolean contains(final int itemId, final int quantity) {
		return contains.__call__(new PyInteger(itemId), new PyInteger(quantity)).asInt() == 1;
	}
	
	public final static void resetMouseClicked() { for (final InventorySlot i : Player.inventorySlots) i.mouseClicked = false; }

		/*************** JYTHON STUFF ***********************************************************************************/
		private static PyFunction add_item, remove_item, remove_item_with_slot_number, remove_equipment, drop_item, contains, isFull;
		private static final void initJythonScripts() {
			add_item = pi.get("add_item", PyFunction.class);
			remove_item = pi.get("remove_item", PyFunction.class);
			remove_item_with_slot_number = pi.get("remove_item_with_slot_number", PyFunction.class);
			remove_equipment = pi.get("remove_equipment", PyFunction.class);
			drop_item = pi.get("drop_item", PyFunction.class);
			contains = pi.get("inventory_contains", PyFunction.class);
			isFull = pi.get("inventory_is_full", PyFunction.class);
		}
		/************* END JYTHON STUFF ***********************************************************************************/
	
	public final synchronized static void cleanUp() {
		Player.inventorySlots = null; tempSlot = null;
		add_item = remove_item = remove_item_with_slot_number = remove_equipment = drop_item = contains = isFull = null;
	}
/******************************************* END MISC *********************************************************************************************************/
	
}
