package hud;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.font.TextAttribute;
import java.util.ArrayList;
import java.util.ConcurrentModificationException;
import java.util.Hashtable;

import animations.PlayerAnimationUtils;
import engine.Game;
import engine.Handler;
import engine.MouseInput;
import fonts.fonts;
import hud.SecondaryHUD.TAB;
import hud.constructionmenu.ConstructionMenu;
import hud.constructionmenu.ConstructionMenuCategory;
import hud.inventory.InvenHelper;
import hud.inventory.Inventory;
import hud.inventory.InventorySlot;
import interfaces.Colors;
import interfaces.Entity;
import interfaces.ItemIDs;
import interfaces.Mob;
import lighting.RadialLight;
import player.Player;
import player.PlayerAttackSequence;
import utils.Circle;
import utils.Point2f;
import utils.Utils;
import world.Boulder;
import world.DroppedItem;
import world.Flower;
import world.Sapling;
import world.TallGrass;
import world.Tree;

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

public final class RightClickMenu implements ItemIDs {
	
	/***************** XXX! *******************/
	
	// This class uses an ArrayList to store the lines
	// This list is cleared upon each click
	// To add any lines to the right-click menu
	// you must first "list.add(new Line());" before
	// referencing your new line.
	
	/******************************************/
	
	private static final int DROP = 0, STORE = 1, RETRIEVE = 2, EQUIP = 3, UNEQUIP = 4, EAT = 5,
			COOK = 6, ATTACK = 7, PICK_UP = 8, HARVEST = 9, CHOP = 10, MINE = 11, PICK = 12; 
	
	
	// ************************************************************************* //
	// * * * * * * * *   Abandon all hope ye who enter here.  * * * * * *  * * * //
	// ************************************************************************* //

	private static final int l = 9, h = 18;
	private static int numLines, width;
	private static Circle clickBounds = new Circle(new Point2f(0,0), 20); // the bounds for containing things in right click
	private static Rectangle menuBounds = new Rectangle(0, 0, 0, 0);
	public static ArrayList<Line> lines;
	public static String[] actions, items; // items is by item id
	public static boolean OVERRIDE_SPACE, OVERRIDE_F;
	
	private static Integer LOCATION = null;
	private static final int WORLD = 1, HUD = 2;
	
	public synchronized final static void init() {
		items = Utils.makeStringArrayFromLinesOfTextFile("/itemTexts.nihil");
		actions = Utils.makeStringArrayFromLinesOfTextFile("/actionTexts.nihil");

		lines = new ArrayList<Line>();
	}
	
	public final static void determineText() {
		if(okayToOpenWorldMenu()) {
			LOCATION = WORLD; int count = 0;
			/*********************** GOALS ********************/
			// 1: Set click bounds to the current click pos
			// 2: Loop first through all mobs in handler, if any found add 'attack' + their class to the top
			// 3: Then add the "Walk Here", this will be at the top should there not have been any mobs found.
			// 4: Repeat through the rest of the handler sets in desired order.
			// 5: When finished, add the 'exit' option to the bottom.
			/**************************************************/
			
			clickBounds.center.x = MouseInput.adjustedRightClickPos.x; // can't convert from Point to Point2f
			clickBounds.center.y = MouseInput.adjustedRightClickPos.y; // this works just fine

			try { for(final Mob i : Handler.mobs) if(i.discovered && Handler.AREA_RECT.contains(i.center.x, i.center.y) && i.alive()) {
				if(clickBounds.contains(i.center)) {
					lines.add(new Line());
					lines.get(count++).set(i.toString(), actions[ATTACK]);
				} } } catch (ConcurrentModificationException cme) { clearAll(); determineText(); }
			
			try { for(final DroppedItem i : Handler.droppedItems) if(i.discovered && Handler.AREA_RECT.contains(i.center.x, i.center.y)) {
				if(clickBounds.contains(i.center)) {
					lines.add(new Line());
					lines.get(count++).set(items[i.itemId - 1], actions[PICK_UP]);
				} } } catch (ConcurrentModificationException cme) { clearAll(); determineText(); }
			
			try { for(final Sapling i : Handler.saplings) if(i.discovered && Handler.AREA_RECT.contains(i.center.x, i.center.y)) {
				if(!i.alive) continue;
				if(clickBounds.contains(i.center)) {
					lines.add(new Line());
					lines.get(count++).set("sapling", actions[PICK]);
				} } } catch (ConcurrentModificationException cme) { clearAll(); determineText(); }
			
			try { for(final TallGrass i : Handler.grass) if(i.discovered && Handler.AREA_RECT.contains(i.center.x, i.center.y)) {
				if(!i.alive) continue;
				if(clickBounds.contains(i.center)) {
					lines.add(new Line());
					lines.get(count++).set("grass", actions[PICK]);
				} } } catch (ConcurrentModificationException cme) { clearAll(); determineText(); }
			
			try { for(final Flower i : Handler.flowers) if(i.discovered && Handler.AREA_RECT.contains(i.center.x, i.center.y)) {
				if(!i.alive) continue;
				if(clickBounds.contains(i.center)) {
					lines.add(new Line());
					lines.get(count++).set("flower", actions[HARVEST]);
				} } } catch (ConcurrentModificationException cme) { clearAll(); determineText(); }
			
			if(InvenHelper.isPickaxe(Player.equipmentSlots[HAND_SLOT].itemId)) {
				try { for(final Boulder i : Handler.boulders) if(i.discovered && Handler.AREA_RECT.contains(i.center.x, i.center.y)) {
					if(!i.alive) continue;
					if(clickBounds.contains(i.center)) {
						lines.add(new Line());
						lines.get(count++).set("boulder", actions[MINE]);
					} } } catch (ConcurrentModificationException cme) { clearAll(); determineText(); }
			}
			
			if(InvenHelper.isAxe(Player.equipmentSlots[HAND_SLOT].itemId)) {
				try { for(final Tree i : Handler.trees) if(i.discovered && Handler.AREA_RECT.contains(i.center.x, i.center.y)) {
					if(!i.alive) continue;
					if(Utils.intersects(i.bounds, clickBounds)) {
						lines.add(new Line());
						lines.get(count++).set("tree", actions[CHOP]);
					} } } catch (ConcurrentModificationException cme) { clearAll(); determineText(); }
			}
			
			addWalkHere();
			addExit(); // adds the 'exit' to the bottom of the menu
		}
		
		// HUD RIGHT CLICK MENU
		else if (okayToOpenHUDMenu()) {
			LOCATION = HUD; int count = 0;
			
			for (final InventorySlot i : Player.inventorySlots) { if (i.itemId == NULL_ITEM) continue;
			
				if (i.bounds.contains(MouseInput.rightClickPos)) {
					// EQUIP
					if (i.equippable) {
						lines.add(new Line());
						lines.get(count++).set(items[i.itemId - 1], actions[EQUIP]);
					}
	
					// DROP
					lines.add(new Line());
					lines.get(count++).set(items[i.itemId - 1], actions[DROP]);
	
					break; /* break because we found the slot that contains mouse pos */
				}
			}
			count = 0;
			for (final InventorySlot i : Player.equipmentSlots) { if (i.itemId == NULL_ITEM) continue;
				if (i.bounds.contains(MouseInput.rightClickPos)) {
					// UNEQUIP
					lines.add(new Line());
					lines.get(count++).set(items[i.itemId - 1], actions[UNEQUIP]);
	
					break; /* break because we found the slot that contains mouse pos */
				}
			}
			addExit(); // adds the 'exit' to the bottom of the menu
		}
		// MUST BE INVALID CLICK, CLEAR MENU
		else clearAll();
	}

	private static Point2f tempCenter;
	private static Tree tempTree;
	private static Boulder tempBoulder;
	private static DroppedItem tempItem;
	private static Entity tempEntity;
	private static Mob tempMob;
	public final static void tick() {
		if(!OVERRIDE_SPACE && !OVERRIDE_F) {
			tempTree = null; tempBoulder = null; tempItem = null; tempEntity = null; tempMob = null; tempCenter = null;
			return;
		}
		
		if(tempTree != null) {
			if(tempTree.alive && InvenHelper.isAxe(Player.equipmentSlots[HAND_SLOT].itemId)) {
				tempCenter = tempTree.center;
				if(!Utils.intersects(Player.center, Player.radius, tempTree.center, tempTree.chopRadius)) {
						Player.keepWalkingX = Player.keepWalkingY = true;
						 MouseInput.adjustedClickPos.x = (int)tempTree.center.x; 
						 MouseInput.adjustedClickPos.y = (int)tempTree.center.y;
				} else { OVERRIDE_SPACE = Player.using = true; Player.keepWalkingX = Player.keepWalkingY = false; }
			} else { tempCenter = null; tempTree = null; OVERRIDE_SPACE = Player.using = false; }
		}
		
		else if(tempBoulder != null) {
			if(tempBoulder.alive && InvenHelper.isPickaxe(Player.equipmentSlots[HAND_SLOT].itemId)) {
				tempCenter = tempBoulder.center;
				if(!Utils.intersects(Player.center, Player.radius, tempBoulder.center, tempBoulder.mineRadius)) {
						Player.keepWalkingX = Player.keepWalkingY = true;
						 MouseInput.adjustedClickPos.x = (int)tempBoulder.center.x; 
						 MouseInput.adjustedClickPos.y = (int)tempBoulder.center.y;
				} else { OVERRIDE_SPACE = Player.using = true; Player.keepWalkingX = Player.keepWalkingY = false; }
			} else { tempCenter = null; tempBoulder = null; OVERRIDE_SPACE = Player.using = false; } 
		}
		
		else if(tempItem != null) {
			tempCenter = tempItem.center;
				if(!Utils.intersects(Player.center, Player.radius, tempItem.center, tempItem.radius)) {
						Player.keepWalkingX = Player.keepWalkingY = true;
						 MouseInput.adjustedClickPos.x = (int)tempItem.center.x; 
						 MouseInput.adjustedClickPos.y = (int)tempItem.center.y;
				} else { 
					if(!Inventory.isFull(tempItem.itemId, tempItem.quantity)) {
						tempCenter = null; 
						Inventory.addItem(tempItem.itemId, tempItem.quantity, tempItem.durability); 
						Handler.droppedItems.remove(tempItem); tempItem = null; 
						Player.keepWalkingX = Player.keepWalkingY = false; 
					}
				}
		}
		
		else if(tempEntity != null) {
			if(tempEntity.alive) {
				tempCenter = tempEntity.center;
				if(!Utils.intersects(Player.center, Player.radius, tempEntity.center, tempEntity.radius)) {
						Player.keepWalkingX = Player.keepWalkingY = true;
						 MouseInput.adjustedClickPos.x = (int)tempEntity.center.x; 
						 MouseInput.adjustedClickPos.y = (int)tempEntity.center.y;
				} else { OVERRIDE_SPACE = Player.using = true; Player.keepWalkingX = Player.keepWalkingY = false; }
			} else { tempCenter = null; tempEntity = null; OVERRIDE_SPACE = Player.using = false; }
		}
		
		else if(tempMob != null) {
			if(tempMob.health > 0) {
				tempCenter = tempMob.center;
				if(!Utils.intersects(Player.center, Player.radius, tempMob.center, tempMob.radius)) {
					Player.keepWalkingX = Player.keepWalkingY = true;
					MouseInput.adjustedClickPos.x = (int)tempMob.center.x; 
					MouseInput.adjustedClickPos.y = (int)tempMob.center.y;
				} else { if(!Player.attacking) PlayerAttackSequence.start(); }
			} else {  tempCenter = null; tempMob = null; }
		}
		
		// DIRECTION / FACING TOWARD TARGETED OBJECT
		if(tempCenter != null) {
			
			int temp = (Utils.direction(Player.center, tempCenter) + (Game.rotation - 1));
			if(temp > 8) temp-=8;
			Player.facing = temp;
			
		}
		
		
	}

	public final synchronized static void onClick() {
		if (!menuOpen() || LOCATION == null) return;
		
		if (LOCATION == WORLD) {
			for (final Line i : lines) { if (i.isEmpty()) continue;
				if (i.bounds.contains(MouseInput.mouseXY)) {
					
					// EXIT
					if (i.action.toString().equals("exit")) { clearAll(); return; }
					
					// WALK HERE
					else if (i.action.toString().equals("walk here")) {
						Player.keepWalkingX = Player.keepWalkingY = true;
						MouseInput.adjustedClickPos.x = MouseInput.adjustedRightClickPos.x; 
						MouseInput.adjustedClickPos.y = MouseInput.adjustedRightClickPos.y;
					}
					
					// CHOP
					else if (i.action.toString().equals(actions[CHOP])) {
						try { for(final Tree T : Handler.trees) if(T.discovered && Handler.AREA_RECT.contains(T.center.x, T.center.y)) {
							if(!T.alive) continue; // don't show chop option if its already cut down
							if(Utils.intersects(T.bounds, clickBounds)) {
								tempTree = T; OVERRIDE_SPACE = true; break;
							} } } catch (ConcurrentModificationException cme) { }
					}
					
					// MINE
					else if (i.action.toString().equals(actions[MINE])) {
						try { for(final Boulder T : Handler.boulders) if(T.discovered && Handler.AREA_RECT.contains(T.center.x, T.center.y)) {
							if(!T.alive) continue; // don't show chop option if its already cut down
							if(Utils.intersects(T.center, T.mineRadius, clickBounds.center, clickBounds.radius)) {
								tempBoulder = T; OVERRIDE_SPACE = true; break;
							} } } catch (ConcurrentModificationException cme) { }
					}
					
					// "PICK UP" --- (dropped items)
					else if (i.action.toString().equals(actions[PICK_UP])) {
						try { for(final DroppedItem T : Handler.droppedItems) if(T.discovered && Handler.AREA_RECT.contains(T.center.x, T.center.y)) {
							if(Utils.intersects(T.center, T.radius, clickBounds.center, clickBounds.radius)) {
								if(items[T.itemId-1].equals(i.item.toString())) { tempItem = T; OVERRIDE_SPACE = true; break; }
							} } } catch (ConcurrentModificationException cme) { }
					}
					
					// "PICK" || "HARVEST"
					else if (i.action.toString().equals(actions[PICK]) || i.action.toString().equals(actions[HARVEST])) {
						if(i.item.toString().equals("grass")) {
							try { for(final TallGrass T : Handler.grass) if(T.discovered && Handler.AREA_RECT.contains(T.center.x, T.center.y)) {
								if(Utils.intersects(T.center, T.radius, clickBounds.center, clickBounds.radius)) {
									tempEntity = T; OVERRIDE_SPACE = true; break;
								} } } catch (ConcurrentModificationException cme) { }
						} 
						else if(i.item.toString().equals("sapling")) {
							try { for(final Sapling T : Handler.saplings) if(T.discovered && Handler.AREA_RECT.contains(T.center.x, T.center.y)) {
								if(Utils.intersects(T.center, T.radius, clickBounds.center, clickBounds.radius)) {
									tempEntity = T; OVERRIDE_SPACE = true; break;
								} } } catch (ConcurrentModificationException cme) { }
						}
						else if(i.item.toString().equals("flower")) {
							try { for(final Flower T : Handler.flowers) if(T.discovered && Handler.AREA_RECT.contains(T.center.x, T.center.y)) {
								if(Utils.intersects(T.center, T.radius, clickBounds.center, clickBounds.radius)) {
									tempEntity = T; OVERRIDE_SPACE = true; break;
								} } } catch (ConcurrentModificationException cme) { }
						}
					}
					
					// "ATTACK"
					else if (i.action.toString().equals(actions[ATTACK])) {
						if(!InvenHelper.hasWeapon()) break;
						
						try { for(final Mob T : Handler.mobs) if(T.discovered && Handler.AREA_RECT.contains(T.center.x, T.center.y)) {
							if(Utils.intersects(T.center, T.radius, clickBounds.center, clickBounds.radius)) {
								if(T.toString().equals(i.item.toString())) { tempMob = T; OVERRIDE_F = true; break; }
							} } } catch (ConcurrentModificationException cme) { }
					}
				}
			}
		} 
		
/*****************************************************************************************************************/
		
		   else if (LOCATION == HUD) {
			   
				int whichInvenSlot = 0; int whichEquipmentSlot = 0;
		
				for (final InventorySlot i : Player.inventorySlots) if (i.bounds.contains(MouseInput.rightClickPos)) whichInvenSlot = i.slotNumber;
				for (final InventorySlot i : Player.equipmentSlots) if (i.bounds.contains(MouseInput.rightClickPos)) whichEquipmentSlot = i.slotNumber;
				
				for (final Line i : lines) { if (i.isEmpty()) continue;
					if (i.bounds.contains(MouseInput.mouseXY)) {
						// Exit
						if (i.action.toString().equals("exit")) { clearAll(); return; }
		
						// Equip
						else if (i.action.toString().equals((actions[EQUIP]))) {
							for (final InventorySlot slot : Player.inventorySlots) 
								if (slot.slotNumber == whichInvenSlot) {
									int slotToEquipTo = InvenHelper.calcEquipSlot(slot.itemId);
									int tempId = slot.itemId; float tempDurability = slot.durability;
									
									RadialLight.determineLight(slot.itemId);
		
									slot.itemId = Player.equipmentSlots[slotToEquipTo].itemId;
									slot.durability = Player.equipmentSlots[slotToEquipTo].durability;
		
									
									RadialLight.removeLight(slot.itemId);
									
									Player.equipmentSlots[slotToEquipTo].itemId = tempId;
									Player.equipmentSlots[slotToEquipTo].durability = tempDurability;
									Player.equipmentSlots[slotToEquipTo].quantity = 1;
									slot.mouseClicked = false;
									
									PlayerAnimationUtils.resetAll(); clearAll(); 
									Inventory.changeSettings();
									return;
								}
						}
					
		
						// UNEQUIP
						else if (i.action.toString().equals((actions[UNEQUIP]))) {
							for (InventorySlot slot : Player.equipmentSlots) {
								if (slot.slotNumber == whichEquipmentSlot) 
									for (final InventorySlot s : Player.inventorySlots) {
										if (s.itemId == NULL_ITEM) { // first slot that is empty, switch
											s.itemId = slot.itemId;
											s.durability = slot.durability;
											s.equippable = true;
											s.mouseClicked = false;
											s.quantity = 1;
											s.equippable = true;
											
											RadialLight.removeLight(slot.itemId);
											
											slot.itemId = NULL_ITEM;
											slot.durability = -1;
											slot.quantity = 0;
											
											PlayerAnimationUtils.resetAll(); clearAll();
											Inventory.changeSettings();
											return;
										}
									}
							}}
						
		
						// Drop
						else if (i.action.toString().equals((actions[DROP]))) {
							for (final InventorySlot slot : Player.inventorySlots) 
								if (slot.slotNumber == whichInvenSlot) {
									Inventory.dropItem(slot.itemId, slot.quantity, slot.durability, slot.slotNumber);
									clearAll();
									return;
								}
						}
					}
				}
		}
		
		clearAll();
	}
	
	public final static void render(Graphics2D g2d) {
		if (!menuOpen() || LOCATION == null) return;
		
		try {
			width = numLines = 0;
			for (final Line i : lines) {
				if (i.isEmpty()) continue;
				
				if((i.item.length() + i.action.length()) * l > width) 
					width = (i.item.length() + i.action.length()) * l;
				
				numLines++;
			}
	
			width += 6; /* the # is for the space at the end */
	
			menuBounds.x = (int) (MouseInput.rightClickPos.x - width / 6.5);
			menuBounds.y = (int) (MouseInput.rightClickPos.y - h / 3.05);
			menuBounds.width = width;
			menuBounds.height = h * numLines;
	
			if (menuBounds.contains(MouseInput.mouseXY)) {
				updateLineBounds();
	
				for (int i = 0; i < lines.size(); i++) {
					if (lines.get(i).isEmpty()) continue;
	
					// DRAW BOX
					if (!(lines.get(i).bounds.contains(MouseInput.mouseXY))) g2d.setColor(Color.BLACK);
					else g2d.setColor(Colors.menuGray);
	
					g2d.fillRect((int) (MouseInput.rightClickPos.x - width / 6.5), (int) (MouseInput.rightClickPos.y + i * h - h / 3.05), width, h);
	
					g2d.setFont(fonts.ponderosa20);
	
					if (!lines.get(i).action.toString().equals("exit") && !lines.get(i).action.toString().equals("walk here")) {
					// DRAW ACTION
						if(!(lines.get(i).action.toString().equals(actions[ATTACK]) && !InvenHelper.hasWeapon())) {
							g2d.setColor(Color.white);
							g2d.drawString(lines.get(i).action.toString(), (int) (MouseInput.rightClickPos.x + 3 - width / 6.5),
									(int) (((MouseInput.rightClickPos.y) + (h * 0.8)) + i * h - h / 3.05));
						} else {
							// STRIKE THROUGH ATTACK IF DONT HAVE WEAPON
							Hashtable<TextAttribute, Object> map = new Hashtable<TextAttribute, Object>();
							map.put(TextAttribute.STRIKETHROUGH, TextAttribute.STRIKETHROUGH_ON);
							g2d.setFont(fonts.ponderosa20.deriveFont(map));
							
							g2d.setColor(Colors.pastelRed);
							g2d.drawString(lines.get(i).action.toString().substring(0, (lines.get(i).action.toString().indexOf(" "))),
									(int) (MouseInput.rightClickPos.x + 3 - width / 6.5),
									(int) (((MouseInput.rightClickPos.y) + (h * 0.8)) + i * h - h / 3.05));
							
							g2d.setFont(fonts.ponderosa20); // RESET FONT
						}
	
					// DRAW ITEM
						g2d.setColor(Color.orange);
						g2d.drawString(lines.get(i).item.toString(), (int) (lines.get(i).action.toString().length()*l + MouseInput.rightClickPos.x + 3 - width / 6.5),
								(int) (((MouseInput.rightClickPos.y) + (h * 0.8)) + i * h - h / 3.05));
					} else {
						// DRAW EXIT / WALK HERE
						g2d.setColor(Color.lightGray);
						g2d.drawString(lines.get(i).action.toString(), (int) (MouseInput.rightClickPos.x + 3 - width / 6.5),
								(int) (((MouseInput.rightClickPos.y) + (h * 0.8)) + i * h - h / 3.05));
					}
				}
	
				g2d.setColor(Color.darkGray);
				g2d.draw(menuBounds);
				
				for (final Line i : lines) try { if (!i.isEmpty()) g2d.draw(i.bounds); } catch(ConcurrentModificationException cme) {}
				
				if(LOCATION == WORLD && Game.drawCollisionBounds || Game.drawRightClickBounds) {
					g2d.setColor(Color.orange);
					g2d.drawOval((int)(MouseInput.rightClickPos.x-clickBounds.radius), (int)(MouseInput.rightClickPos.y-clickBounds.radius), (int)clickBounds.radius*2, (int)clickBounds.radius*2);
				}
				
			} else { clearAll(); return; }
		} catch (Exception e) { clearAll(); } // from CME's to Nulls to IOOB's, all things can happen from adding / removing lines while rendering
											  // just catch and miss the frame, no big deal. Not much can do about it.
	}
	
	public final static boolean okayToOpenWorldMenu() {
		if (!menuOpen()) return false; // don't open menu if already open

		// if currently holding an item, don't open
		for (final InventorySlot i : Player.inventorySlots) if (i.mouseClicked) return false;
					
		// if in inventory
		if (Inventory.INVENTORY_BOUNDS.contains(MouseInput.rightClickPos)) return false;

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

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

		// if inside construction tabs
		if(ConstructionMenu.bounds.contains(MouseInput.rightClickPos)) return false;
				
		return true;
	}

	public final static boolean okayToOpenHUDMenu() {
		if (!menuOpen()) return false; // don't open menu if already open

		for (InventorySlot i : Player.inventorySlots) { /* don't show menu if holding item */
			if (i.bounds.contains(MouseInput.rightClickPos)) {
				if (i.mouseClicked || (i.itemId == NULL_ITEM)) {
					MouseInput.rightClickPos.x = MouseInput.rightClickPos.y = -1;
					return false;
				}
			}
		}

		for (InventorySlot i : Player.equipmentSlots) { /* don't show menu if holding item */
			if (i.bounds.contains(MouseInput.rightClickPos)) {
				if (i.mouseClicked || (i.itemId == NULL_ITEM)) {
					MouseInput.rightClickPos.x = MouseInput.rightClickPos.y = -1;
					return false;
				}
			}
		}

		// if not in inventory
		if (!Inventory.INVENTORY_BOUNDS.contains(MouseInput.rightClickPos)) {
			// and not in secondary hud
			if (SecondaryHUD.tab == TAB.MINIMIZED) {  return false;
			} else if (!(SecondaryHUD.tab == TAB.MINIMIZED)) if (!(SecondaryHUD.maximizedBounds.contains(MouseInput.rightClickPos))) return false;

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

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

	public final static boolean menuOpen() { return (MouseInput.rightClickPos.x >= 0 || MouseInput.rightClickPos.y >= 0); }

	public final static void addExit() {
		for (final Line i : lines) if (i.action.toString().equals("exit")) i.clear();

		lines.add(new Line());
		for (int i = 0; i < lines.size(); i++) {
			if (!lines.get(i).isEmpty()) continue;
			else {  lines.get(i).set(" ", "exit");  return; }
		}
	}
	
	public final static void addWalkHere() {
		for (final Line i : lines) if (i.action.toString().equals("walk here")) i.clear();

		lines.add(new Line());
		for (int i = 0; i < lines.size(); i++) {
			if (!lines.get(i).isEmpty()) continue;
			else {  lines.get(i).set(" ", "walk here");  return; }
		}
	}

	private final static void updateLineBounds() {
		for (int i = 0; i < lines.size(); i++) {
			if (lines.get(i).isEmpty()) continue;
			lines.get(i).bounds.x = (int) (MouseInput.rightClickPos.x - width / 6.5);
			lines.get(i).bounds.y = (int) (MouseInput.rightClickPos.y + i * h - h / 3.05);
			lines.get(i).bounds.width = width;
		}
	}

	private final static class Line { /* daughter class */
		private final StringBuilder action, item;
		private final Rectangle bounds;

		private Line() {
			action = new StringBuilder("");
			item = new StringBuilder("");
			bounds = new Rectangle(0, 0, 0, h);
		}

		private final void set(String _item, String _action) {
			item.setLength(0);
			action.setLength(0);
			action.append(_action);
			item.append(_item);
		}

		private final void clear() {
			action.setLength(0);
			item.setLength(0);
		}

		private final boolean isEmpty() { return (item.length() <= 0 || action.length() <= 0); }
	}

	private final static void clearAll() {
		for(int i = 0; i < lines.size(); i++) lines.get(i).clear();
		lines.clear();
		MouseInput.rightClickPos.x = MouseInput.rightClickPos.y = -1;
		LOCATION = null;
	}

	public final synchronized static void cleanUp() {
		clearAll(); LOCATION = null; lines = null; items = actions = null; clickBounds = null; menuBounds = null;
	}
}
