package com.rs.game.player.content;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.rs.cache.Cache;
import com.rs.cache.loaders.ClientScriptMap;
import com.rs.cache.loaders.ItemDefinitions;
import com.rs.game.World;
import com.rs.game.WorldObject;
import com.rs.game.item.Item;
import com.rs.game.player.Player;
import com.rs.game.player.actions.Bonfire;
import com.rs.game.player.actions.Bonfire.Log;
import com.rs.game.player.actions.Cooking;
import com.rs.game.player.actions.Cooking.Cookables;
import com.rs.game.player.actions.Firemaking;
import com.rs.game.player.actions.Firemaking.Fire;
import com.rs.game.player.actions.Fletching2;
import com.rs.game.player.actions.Fletching2.FletchData;
import com.rs.game.player.actions.GemCutting;
import com.rs.game.player.actions.GemCutting.Gem;
import com.rs.game.player.content.grandExchange.GrandExchange;
import com.rs.utils.ItemExamines;

public final class SkillsDialogue {
	

	private static final Map<Integer, SkillDialogue> skillDialogues = new HashMap<Integer, SkillDialogue>();
	
	private static int[] NO_MENU_CATEGORIES = {7050, 7048, 7049, 7046, 7047, 7070, 7069, 7065, 7064, 7063, 7077, 7078, 7103, 7102, 7096, 7093, 7092, 7106, 8076, 7104, 7105, 7556, 8002, 6921, 6934, 6935, 6938, 6936, 6937, 7512, 6972, 6973, 6974, 6975, 6969, 6970, 6971, 6979, 6977, 6976, 6980, 6986, 6990, 6989, 8858, 8856, 8857, 8854, 8855, 8853, 6808, 6840, 6830, 6831, 6829, 6868, 6898, 6674, 7278, 7277, 7276, 7275, 8697, 6770, 6771, 6768, 6769, 6774, 6775, 6772, 6773, 6778, 6779, 6776, 6777, 6762, 6761, 6767, 6766, 6765, 6764};
	
	public static class SkillDialogue {
		
		private int menuCSMapId, menuNamesCSMapId;
		private SkillCategory[] categories;
		
		private SkillDialogue(int id) {
			menuCSMapId = id;

			if(id == -1) {
				menuNamesCSMapId = -1;
				categories = new SkillCategory[NO_MENU_CATEGORIES.length];
				for(int i = 0; i < categories.length; i++) 
					categories[i] = new SkillCategory(NO_MENU_CATEGORIES[i]);
			}else{
				menuNamesCSMapId = id+ (menuCSMapId == 6852 || menuCSMapId == 6853 || menuCSMapId == 7551 ? 2 : 1) ;
				ClientScriptMap csmap = ClientScriptMap.getMap(id);
				categories = new SkillCategory[csmap.getSize()];
				for(int i = 0; i < categories.length; i++) 
					categories[i] = new SkillCategory(csmap.getIntValue(i));
			}
		}
		
		public SkillCategory getCategory(int id) {
			for(SkillCategory c : categories)
				if(c.getItemsCSMapId() == id)
					return c;
			return null;
		}
		
		public SkillCategory[] getCategorys() {
			return categories;
		}
	}
	
	private static final int SKILL_VAR = 1168, CATEGORY_VAR = 1169, PRODUCT_VAR = 1170, MAX_QUANTITY_VAR_BIT = 1002, CURRENT_QUANTITY_VAR_BIT = 1003;
	
	private static int[] SKILL_DIALOGUES = {-1, 5773, 6675, 6780, 6784, 6794, 6803, 6809, 6821, 6823, 6832, 6838, 6848, 6852, 6853, 6861, 6869, 6877, 6879, 6894, 6896, 6919, 6939, 6941, 6943, 6945, 6981, 6987, 7004, 7006, 7008, 7010, 7012, 7042, 7051, 7057, 7059, 7061, 7079, 7081, 7094, 7113, 7551, 7800, 7812};
	
	
	public static class SkillCategory {
		
		private int itemsCSMapId;
		private int categorySpriteId;
		private int[] items;
		
		private SkillCategory(int id) {
			setItemsCSMapId(id);
			categorySpriteId = ClientScriptMap.getMap(6817).getIntValue(id);
			ClientScriptMap csmap = ClientScriptMap.getMap(id);
			setItems(new int[csmap.getSize()]);
			for(int i = 0; i < getItems().length; i++) 
				getItems()[i] = csmap.getIntValue(i);
		}

		public int[] getItems() {
			return items;
		}

		public void setItems(int[] items) {
			this.items = items;
		}

		public int getItemsCSMapId() {
			return itemsCSMapId;
		}

		public void setItemsCSMapId(int itemsCSMapId) {
			this.itemsCSMapId = itemsCSMapId;
		}
	}
	
	public static SkillDialogue getSkillDialogue(int id) {
		SkillDialogue d = skillDialogues.get(id);
		if(d == null) 
			skillDialogues.put(id, d = new SkillDialogue(id));
		return d;
	}
	

	
	
	public static enum CategoryTypes {
		
		COOKING(14145)
		, CRAFTING(14149)
		, FARMING(14153)
		, FIREMAKING(14157)
		, FLETCHING(14161)
		, HERBLORE(14165)
		, MAGIC(14169)
		, RUNECRAFTING(14173)
		, SMITHING(14177)
		, SUMMOMING(14181)
		, WOODCUTTING(14185)
		, REWARDS(14193)
		, WATER(14197)
		, DIVINATION(20390)
		;
		
		private int spriteId;
		
		private CategoryTypes(int spriteId) {
			this.spriteId = spriteId;
		}
	}
	
	//1169 var
	public static void main(String[] args) throws IOException {
		Cache.init();
	/*	for(SmeltingBar s : Smelting.SmeltingBar.values())
		System.out.println(findSkillDialogue(s.getItemsRequired()[0].getId(), s.getSkillType() == Skills.CRAFTING ? CategoryTypes.CRAFTING : CategoryTypes.SMITHING, 0, false));
	*/	
		System.out.println(findSkillDialogueByProduce(48));
	}
	
	/*
	 * not recommended since material repeats
	 * so it doesnt always get correctly
	 * */
	public static SkillDialogue findSkillDialogueByMaterial(int materialId, CategoryTypes type, int index, boolean skipNoMenu) {
		int idx = 0;
		for(int i = skipNoMenu ? 1 : 0; i < SKILL_DIALOGUES.length; i++) {
			SkillDialogue d = getSkillDialogue(SKILL_DIALOGUES[i]);
			SkillCategory c = getCategoryWithMaterial(d, materialId);
			if(c == null || (type != null && c.categorySpriteId != type.spriteId))
				continue;
			//System.out.println(d.menuCSMapId+", "+c.getItemsCSMapId()+", "+c.categorySpriteId+", "+materialId);
			if(idx++ == index) 
				return d;
		}
		return null;
	}
	
	
	
	/*
	 * 100% safe. produce is only one for each dialogue
	 * */
	public static SkillDialogue findSkillDialogueByProduce(int produceId) {
		for(int i = 0; i < SKILL_DIALOGUES.length; i++) {
			SkillDialogue d = getSkillDialogue(SKILL_DIALOGUES[i]);
			for(SkillCategory c : d.categories) {
				for(int id : c.getItems())
					if(produceId == id) {
						//System.out.println("here you go "+d.menuCSMapId+", "+c.itemsCSMapId);
						return d;
					}
			}
		}
		return null;
	}
	
	private static SkillCategory getCategoryWithProduce(SkillDialogue sd, int produceId) {
		for(SkillCategory sc : sd.categories) {
			for(int id : sc.getItems()) {
				if(produceId == id)
					return sc;
			}
		}
		return null;
	}
	
	
	/*
	 * -1 = playermade fire, -2 ingame cook fire.
	 */
	public static boolean selectTool(Player player, int materialId) {
		List<ToolReference> tools = new ArrayList<ToolReference>();
		
		if(materialId < 0) {
			tools.add(new ToolReference(25637, Cooking.getCook(player)));
			if(materialId == -2)
				tools.add(new ToolReference(24291, Bonfire.Log.LOG));
		}else{
			FletchData fletch = Fletching2.isFletching(materialId);
			if(fletch != null)
				tools.add(new ToolReference(fletch.getSecondary(), fletch));
			Fire firemake = Firemaking.getFire(materialId);
			if(firemake != null)
				tools.add(new ToolReference(590, firemake));
			Log log = Bonfire.getLog(materialId);
			if(log != null)
				tools.add(new ToolReference(24291, log));
			Gem gem = GemCutting.getGem(materialId);
			if(gem != null)
				tools.add(new ToolReference(1755, gem));
		}
		if(tools.size() == 0)
			return false;
		if(tools.size() == 1)
			tools.get(0).select(player);
		else {
			player.getPackets().sendHideIComponent(1371, 20, false);
			player.getDialogueManager().startDialogue("ChooseAToolD", "What do you want to use on the "+(materialId == -1 ? "fire" : ItemDefinitions.getItemDefinitions(materialId).getName())+"?", tools.toArray(new ToolReference[tools.size()]));
		}
		return true;
	
	}
	
	public static void backToSelect(Player player) {
		ItemDefinitions defs = ItemDefinitions.getItemDefinitions( player.getVarsManager().getValue(PRODUCT_VAR));
		int materialId = defs.getCSOpcode(2655);
		if(materialId != 0)
			selectTool(player, materialId);
	}
	
	public static class ToolReference {
		
		private int toolId;
		private Object target;
		
		private ToolReference(int toolId, Object target) {
			this.toolId = toolId;
			this.target = target;
		}
		
		public int getToolId() {
			return toolId;
		}
		
		public WorldObject findFire(Player player) {
			for(int x = -1; x <= 1; x++) {
				for(int y = -1; y <= 1; y++) {
					WorldObject o = World.getObjectWithType(player.transform(x, y, 0), 10);
					if(o != null && o.getDefinitions().name.equals("Fire"))
						return o;
				}
			}
			return null;
			
		}
		
		public void select(Player player) {
		//	System.out.println("called "+(target instanceof FletchData));
			if(target instanceof FletchData) {
				player.getDialogueManager().startDialogue("FletchingD", target);
			}else if (target instanceof Cookables)  {
				WorldObject fire = findFire(player);
				if(fire == null) 
					return;
				player.faceObject(fire);
				player.getDialogueManager().startDialogue("CookingD", target, fire);
			}else if (target instanceof Log) {
				WorldObject fire = findFire(player);
				if(fire == null) 
					return;
				player.faceObject(fire);
				Bonfire.addLogs(player, fire);
			}else if (target instanceof Fire) {
				player.getActionManager().setAction(new Firemaking((Fire) target));
			}else if (target instanceof Gem) 
				GemCutting.cut(player, (Gem) target);
		}
	}
	
	public static void sendSkillDialogueByMaterial(Player player, int material, CategoryTypes type, int index, boolean skipNoMenu) {
		SkillDialogue d = findSkillDialogueByMaterial(material, type, index, skipNoMenu);
		if(d == null) 
			return;		
		sendSkillDialogue(player, d, getCategoryWithMaterial(d, material));
	}
	
	public static void sendSkillDialogueByProduce(Player player, int produceId) {
		SkillDialogue d = findSkillDialogueByProduce(produceId);
		if(d == null) 
			return;		
		sendSkillDialogue(player, d, getCategoryWithProduce(d, produceId));
	}
	
	
	//recommend using the other one for skills. this one is manual
	public static void sendSkillDialogue(final Player player, SkillDialogue sd, SkillCategory sc) {
		if(sc == null) 
			sc = sd.categories[0];
		player.getVarsManager().sendVar(SKILL_VAR, sd.menuCSMapId);
		setCategory(player, sc);
		player.getPackets().sendCSVarInteger(2222, sd.menuNamesCSMapId);
		player.getInterfaceManager().sendCentralInterface(1370);
		player.getInterfaceManager().setInterface(true, 1370, 62, 1371);
		player.getPackets().sendIComponentSettings(1371, 62, 0, sd.categories.length, 2);
		player.getPackets().sendIComponentSettings(1371, 44, 0, 500, 2);
		player.getPackets().sendIComponentSettings(1371, 36, 0, 1, 2359296);
		player.getPackets().sendIComponentSettings(1371, 143, 0, 1, 2);
		player.setCloseInterfacesEvent(new Runnable() {
			@Override
			public void run() {
				player.getVarsManager().sendVar(SKILL_VAR, -1);
				player.getVarsManager().sendVar(CATEGORY_VAR, -1);
				player.getVarsManager().sendVar(PRODUCT_VAR, -1);
				player.getVarsManager().sendVarBit(MAX_QUANTITY_VAR_BIT, 0);
				player.getVarsManager().sendVarBit(CURRENT_QUANTITY_VAR_BIT, 0);
			}
		});

	}
	
	private static SkillCategory getCategoryWithMaterial(SkillDialogue sd, int materialId) {
		for(SkillCategory sc : sd.categories) {
			for(int itemId : sc.getItems()) {
				ItemDefinitions defs = ItemDefinitions.getItemDefinitions(itemId);
				if(defs.getCSOpcode(2655) == materialId)
					return sc;
			}
		}
		return null;
	}
	
	public static void setCategoryByIndex(Player player, int index) {
		int skill = player.getVarsManager().getValue(SKILL_VAR);
		if(skill == 0)
			return;
		SkillDialogue sd = getSkillDialogue(skill);
		if(sd == null || index >= sd.categories.length)
			return;
		setCategory(player, sd.categories[index]);
	}
	
	private static void setCategory(Player player, SkillCategory sc) {
		player.getVarsManager().sendVar(CATEGORY_VAR, sc.getItemsCSMapId());
		int bestProduct = -1;
		l: for(int i = sc.getItems().length-1; i >= 0; i--) { //best product for lvl with material
			ItemDefinitions defs = ItemDefinitions.getItemDefinitions(sc.getItems()[i]);
			int skillId = ClientScriptMap.getMap(681).getIntValue(defs.getCSOpcode(2640));
			int level =  defs.getCSOpcode(2645);
			int multiplierQuantity = defs.getCSOpcode(2653);
			if((skillId == -1 || player.getSkills().getLevel(skillId) >= level)) {
				for(int i2 = 0; i2 < 3; i2++) {
					int material = defs.getCSOpcode(2655+i2);
					int amount = defs.getCSOpcode(2665+i2);
					if(material != 0 && !(player.getInventory().containsItem(material, amount * (multiplierQuantity == 0 ? 1 : multiplierQuantity))))
						continue l;
				}
				bestProduct = i;
				break;
			}
		}
		if(bestProduct == -1) { //best product for lvl if no mat
			bestProduct = 0;
			for(int i = sc.getItems().length-1; i >= 0; i--) {
				ItemDefinitions defs = ItemDefinitions.getItemDefinitions(sc.getItems()[i]);
				int skillId = ClientScriptMap.getMap(681).getIntValue(defs.getCSOpcode(2640));
				int level =  defs.getCSOpcode(2645);
				if(skillId == -1 || player.getSkills().getLevel(skillId) >= level) {
					bestProduct = i;
					break;
				}
			}
		}
		setProduct(player, sc.getItems()[bestProduct]);
	}
	
	
	public static void setProductByIndex(Player player, int index) {
		int skill = player.getVarsManager().getValue(SKILL_VAR);
		if(skill == 0) 
			return;
		
		SkillCategory sc = getSkillDialogue(skill).getCategory(player.getVarsManager().getValue(CATEGORY_VAR));
		if(sc == null || index >= sc.getItems().length) 
			return;
		
		setProduct(player, sc.getItems()[index]);
	}
	
	
	private static void setProduct(Player player, int result) {
		player.getVarsManager().sendVar(PRODUCT_VAR, result);
		setMaxQuantity(player, result);
		Item item = new Item(result, 1);
		player.getPackets().sendCSVarString(2391, ItemExamines.getExamine(item));
		boolean tradeable = ItemConstants.isTradeable(item);
		player.getPackets().sendCSVarInteger(2223, tradeable ? 1 : 0);
		if(tradeable)
			player.getPackets().sendCSVarInteger(2224, GrandExchange.getPrice(result));
	}
	
	private static void setMaxQuantity(Player player, int result) {
		ItemDefinitions defs = ItemDefinitions.getItemDefinitions(result);
		int maxQuantity = 0;
		int skillId = ClientScriptMap.getMap(681).getIntValue(defs.getCSOpcode(2640));
		int level =  defs.getCSOpcode(2645);
		int multiplierQuantity = defs.getCSOpcode(2653);
		if(player.getSkills().getLevel(skillId) >= level) {
			boolean allMatsStackable = true;
			for(int i2 = 0; i2 < 3; i2++) {
				int material = defs.getCSOpcode(2655+i2);
				int amount = defs.getCSOpcode(2665+i2);
				if(material == 0)
					break;
				if(multiplierQuantity != 0) 
					amount *= multiplierQuantity;
				ItemDefinitions mat = ItemDefinitions.getItemDefinitions(material);
				if(!mat.isStackable())
					allMatsStackable = false;
				int amt = player.getInventory().getAmountOf(material) / amount;
				if(i2 == 0 || amt < maxQuantity)
					maxQuantity = amt;
				
			}
			if(allMatsStackable && maxQuantity > 10) 
				maxQuantity = 10;
		}
		
		player.getVarsManager().sendVarBit(MAX_QUANTITY_VAR_BIT, maxQuantity);
		setCurrentQuantity(player, maxQuantity);
	}
	
	public static void setCurrentQuantity(Player player, boolean increase) {
		setCurrentQuantity(player, player.getVarsManager().getBitValue(CURRENT_QUANTITY_VAR_BIT) + (increase ? 1 : -1));
	}
	
	public static void setCurrentQuantity(Player player, int quantity) {
		int max = player.getVarsManager().getBitValue(MAX_QUANTITY_VAR_BIT);
		if(quantity > max)
			quantity = max;
		else if (quantity < 1)
			quantity = 1;
		player.getVarsManager().sendVarBit(CURRENT_QUANTITY_VAR_BIT, quantity);
	}

	public static class SkillDialogueResult {
		
		private int productId, quantity;
		
		private SkillDialogueResult(int productId, int quantity) {
			this.productId = productId;
			this.quantity = quantity;
		}
		
		public int getProduce() {
			return productId;
		}
		
		public int getQuantity() {
			return quantity;
		}
	}
	
	public static SkillDialogueResult getResult(Player player) {
		SkillDialogueResult result = new SkillDialogueResult(player.getVarsManager().getValue(PRODUCT_VAR), player.getVarsManager().getBitValue(CURRENT_QUANTITY_VAR_BIT));
		player.closeInterfaces();
		return result;
		
	}
	
	public static final int MAKE = 0, MAKE_SETS = 1, COOK = 2, ROAST = 3,
		OFFER = 4, SELL = 5, BAKE = 6, CUT = 7, DEPOSIT = 8,
		MAKE_NO_ALL_NO_CUSTOM = 9, TELEPORT = 10, SELECT = 11, TAKE = 13, STRUNG = 12;

public static interface ItemNameFilter {

	public String rename(String name);
}

public static void sendSkillsDialogue(Player player, int option, String explanation, int maxQuantity, int[] items, ItemNameFilter filter) {
	sendSkillsDialogue(player, option, explanation, maxQuantity, items, filter, true);
}

public static void sendSkillsDialogue(Player player, int option, String explanation, int maxQuantity, int[] items, ItemNameFilter filter, boolean sendQuantitySelector) {
	player.getInterfaceManager().sendChatBoxInterface(905);
	player.getPackets().sendInterface(true, 905, 4, 916);
	if(!sendQuantitySelector) {
		maxQuantity = -1;
		player.getPackets().sendHideIComponent(916, 4, true);
		player.getPackets().sendHideIComponent(916, 9, true);
	}else{
		if (option != MAKE_SETS && option != MAKE_NO_ALL_NO_CUSTOM)
			player.getPackets().sendUnlockIComponentOptionSlots(916, 8, -1, 0,
					0); // unlocks all option
	}
	player.getPackets().sendIComponentText(916, 1, explanation);
	player.getPackets().sendGlobalConfig(754, option);
	for (int i = 0; i < 10; i++) {
		if (i >= items.length) {
			player.getPackets().sendGlobalConfig(
					i >= 6 ? (1139 + i - 6) : 755 + i, -1);
			continue;
		}
		player.getPackets().sendGlobalConfig(
				i >= 6 ? (1139 + i - 6) : 755 + i, items[i]);
		String name = ItemDefinitions.getItemDefinitions(items[i])
				.getName();
		if (filter != null)
			name = filter.rename(name);
		player.getPackets().sendGlobalString(
				i >= 6 ? (280 + i - 6) : 132 + i, name);
	}
	setMaxQuantity(player, maxQuantity);
	setQuantity(player, maxQuantity);
}

public static void handleSetQuantityButtons(Player player, int componentId) {
	if (componentId == 5)
		setQuantity(player, 1, false);
	else if (componentId == 6)
		setQuantity(player, 5, false);
	else if (componentId == 7)
		setQuantity(player, 10, false);
	else if (componentId == 8)
		setQuantity(player, getMaxQuantity(player), false);
	else if (componentId == 19)
		setQuantity(player, getQuantity(player) + 1, false);
	else if (componentId == 20)
		setQuantity(player, getQuantity(player) - 1, false);
}

public static void setQuantity(Player player, int quantity) {
	setQuantity(player, quantity, true);
}

public static void setQuantity(Player player, int quantity, boolean refresh) {
	int maxQuantity = getMaxQuantity(player);
	if (quantity > maxQuantity)
		quantity = maxQuantity;
	else if (quantity < 0)
		quantity = 0;
	player.getTemporaryAttributtes()
			.put("SkillsDialogueQuantity", quantity);
	if (refresh)
		player.getPackets().sendConfigByFile(8095, quantity);
}

public static int getMaxQuantity(Player player) {
	Integer maxQuantity = (Integer) player.getTemporaryAttributtes().get("SkillsDialogueMaxQuantity");
	if (maxQuantity == null)
		return 0;
	return maxQuantity;
}

public static int getQuantity(Player player) {
	Integer quantity = (Integer) player.getTemporaryAttributtes().get("SkillsDialogueQuantity");
	if (quantity == null)
		return 0;
	return quantity;
}

public static int getItemSlot(int componentId) {
	if (componentId < 14)
		return 0;
	return componentId - 14;
}

private SkillsDialogue() {

}

public static void sendSkillsDialogue(Player player, int option, String explanation, int maxQuantity, int[] product, Object filter) {
    sendSkillsDialogue(player, option, explanation, maxQuantity, product, filter);
}
}
