package net.minecraft.src.weasel.obj;


import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;

import net.minecraft.src.NBTTagCompound;
import net.minecraft.src.NBTTagList;
import net.minecraft.src.weasel.WeaselEngine;


/**
 * List of variables in the WeaselVM<br>
 * Variable list can be put into stack when CALL is executed,<br>
 * and it can also be written into NBT.
 * 
 * @author MightyPork
 * @copy (c) 2012
 */
public class WeaselVariableMap extends WeaselObject {

	/** Variable map */
	public LinkedHashMap<String, WeaselObject> map;

	/**
	 * clear the map.
	 */
	public void clear() {
		map.clear();
	}

	/**
	 * Unset a variable
	 * 
	 * @param name variable name
	 */
	public void unsetVariable(String name) {
		map.remove(name);
	}

	/**
	 * Store variable into map
	 * 
	 * @param name variable name
	 * @param object variable object to store
	 */
	public void setVariable(String name, WeaselObject object) {

		if (map.get(name) != null) {
			if (map.get(name).getType() != object.getType()) {
				throw new RuntimeException("Trying to store " + object.getType() + " object into a " + map.get(name).getType() + " variable.");
			}
		}

		map.put(name, object);
	}

//	/**
//	 * Store variable into map, ignoring old value data type.<br>
//	 * Used mainly for function return value.
//	 * 
//	 * @param name variable name
//	 * @param object variable object to store
//	 */
//	public void setVariableForceReplace(String name, WeaselObject object) {
//		map.remove(name);
//		map.put(name, object);
//	}

	/**
	 * Get variable from map
	 * 
	 * @param name variable name
	 * @return variable object
	 */
	public WeaselObject getVariable(String name) {
		return map.get(name);
	}

	/**
	 * List of weasel variables
	 */
	public WeaselVariableMap() {
		super(WeaselObjectType.VARIABLE_LIST);
		map = new LinkedHashMap<String, WeaselObject>();
	}

	@Override
	public NBTTagCompound writeToNBT(NBTTagCompound tag) {

		NBTTagList tags = new NBTTagList();
		for (Entry<String, WeaselObject> entry : map.entrySet()) {
			NBTTagCompound tag1 = WeaselObject.saveObjectToNBT(entry.getValue(), new NBTTagCompound());
			tag1.setString("VariableName", entry.getKey());
			tags.appendTag(tag1);
		}
		tag.setTag("VariableMap", tags);

		return tag;

	}

	@Override
	public WeaselVariableMap readFromNBT(NBTTagCompound tag) {

		NBTTagList tags = tag.getTagList("VariableMap");
		for (int i = 0; i < tags.tagCount(); i++) {
			NBTTagCompound tag1 = (NBTTagCompound) tags.tagAt(i);
			map.put(tag1.getString("VariableName"), WeaselObject.loadObjectFromNBT(tag1));
		}

		return this;

	}

	@Override
	public boolean equals(Object obj) {
		if (obj == null) {
			return false;
		}
		if (!this.getClass().equals(obj.getClass())) {
			return false;
		}

		return ((WeaselVariableMap) obj).map == map;
	}

	/**
	 * Get map of all variables, including native ones. 
	 * @param engine weasel engine
	 * @return map of variables
	 */
	public Map<String, WeaselObject> getAllVariables(WeaselEngine engine) {
		Map<String, WeaselObject> map1 = new HashMap<String, WeaselObject>(map);
		WeaselVariableMap map_native = engine.getNativeVariables();
		for (Entry<String, WeaselObject> entry : map_native.get().entrySet()) {
			map1.put(entry.getKey(), entry.getValue());
		}
		return map1;
	}

	@Override
	public int hashCode() {
		return map.hashCode();
	}

	@Override
	public String toString() {
		return "VARMAP(" + map + ")";
	}

	@Override
	public Map<String, WeaselObject> get() {
		return map;
	}

	@SuppressWarnings("unchecked")
	@Override
	public void set(Object obj) {
		if (obj == null || !(obj instanceof Map)) {
			throw new RuntimeException("Trying to store " + obj + " in a VariableMap variable.");
		}
		map = (LinkedHashMap<String, WeaselObject>) obj;
	}

	@Override
	public WeaselObject copy() {
		WeaselVariableMap map2 = new WeaselVariableMap();
		map2.set(map.clone());
		return map2;
	}


}
