package sso;

import java.util.*;
import java.sql.*;

public class Equipment extends Thing
{
	protected byte 		equipLocation;		// where this is equipped
	protected boolean	equipped;			// if this is equipped
	protected byte		equipSize;			// size of who may equip this
	protected boolean	lootable;			// if this may be looted
	protected int		repairDifficulty;	// skill target required to repair this
	protected String	repairSkill;		// skill needed to repair this

	/**
 	 * Constructor. Call a factory method instead.
	 */
	protected Equipment()
	{
		super();
	}

	/**
	 *  Factory method. Create a new piece of equipment.
	 */
	public static Equipment createEquipment()
	{
		Equipment e = new Equipment();
		e.init();
		return e;
	}

	/**
	 *  Initializer for new equipment.
	 */
	protected void init()
	{
		super.init();

		equipLocation = PC.LOC_NONE;
		equipped = false;
		equipSize = PC.SIZE_ANY;
		lootable = true;
		repairDifficulty = 25;
		repairSkill = "sso.skill.Tinker";
	}

	/**
	 *  Get the equipment location.
	 */
	public byte getEquipLocation()
	{
		return equipLocation;
	}

	/**
	 *  Alias for getEquipLocation().
	 *  @see getEquipLocation
	 */
	public byte getBodyLocation()
	{
		return getEquipLocation();
	}

	/**
	 *  Set the equipment location.
	 */
	public void setEquipLocation(byte loc)
	{
		equipLocation = loc;
		propChanged("equipLocation");
	}

	/**
	 *  Is the equipment equipped?
	 */
	public boolean isEquipped()
	{
		return equipped;
	}

	/**
	 *  Equip the equipment
	 *  Unequip any objects equipped in the same slot.
	 *  *** TODO *** Two handed items, one handed items (make sure unequip)
	 */
	public void equip()
	{
		if (isEquippable())
		{
			Vector ve = (Vector)((PC)getLocation()).getContents().clone();
			Equipment e;

			for (int i = 0; i < ve.size(); i++)
			{
				if (ve.elementAt(i) instanceof Equipment)
				{
					e = (Equipment)ve.elementAt(i);
					if (e.isEquipped() && e != this)
					{
						// special rule... HANDS
						// two handed items require BOTH hands free
						// *** TODO ***
						if (e.getBodyLocation() == getBodyLocation())
						{
							// unequip e
							e.unequip();
							
							// equip this
							equipped = true;
							propChanged("equipped");
						}
					}
				}
			}

			if (!equipped)
			{
				// if not equipped at this point, we can probably safely do so
				equipped = true;
				propChanged("equipped");
			}
		}
	}

	/**
	 *  Unequip the equipment
	 */
	public void unequip()
	{
		if (isEquippable())
		{
			equipped = false;
		}

		propChanged("equipped");
	}

	/**
	 *  Is the equipment equippable?
	 */
	public boolean isEquippable()
	{
		boolean eq = false;

		if (equipLocation != PC.LOC_NONE)
		{
			if (getLocation() instanceof PC)
			{
				if (((PC)getLocation()).getSize() == getEquipSize())
				{
					eq = true;
				}
			}
		}

		return true;
	}

	/**
	 *  Get the equipment size
	 */
	public byte getEquipSize()
	{
		return equipSize;
	}

	/**
	 *  Set the equipment size
	 */
	public void setEquipSize(byte size)
	{
		equipSize = size;
		propChanged("equipSize");
	}

	/**
	 *  Is the equipment lootable/stealable?
	 */
	public boolean isLootable()
	{
		return lootable;
	}

	/**
	 *  Set the lootable flag
	 */
	public void setLootable(boolean lootable)
	{
		this.lootable = lootable;
		propChanged("lootable");
	}

	/**
	 *  Get the repair difficulty target
	 */
	public int getRepairDifficulty()
	{
		return repairDifficulty;
	}

	/**
	 *  Set the repair difficulty target
	 */
	public void setRepairDifficulty(int target)
	{
		repairDifficulty = target;
		propChanged("repairDifficulty");
	}

	/**
	 *  Get the repair skill.
	 */
	public String getRepairSkill()
	{
		return repairSkill;
	}

	/**
	 *  Set the repair skill.
	 */
	public void setRepairSkill(String skill)
	{
		repairSkill = skill;
		propChanged("repairSkill");
	}

	/**
	 *  Repair the equipment, or at least try. Catastrophic failures may damage
	 *  the equipment further. Successful repairs will raise the rating of the
	 *  equipment by 1/10th the difference of the roll and the target.
	 *  Return true on success, false on failure.
	 */
	public boolean repair(PC craftsman)
	{
		Skill sk = craftsman.getSkill(repairSkill);
		boolean success = false;

		if (sk != null)
		{
			int roll = sk.roll();
			if (sk.getClass().getName() != repairSkill)
			{
				try
				{
					roll -=
					((Skill)(Class.forName(repairSkill).newInstance())).getDefaultPenalty();
				}
				catch (Exception e)
				{
					System.err.println("Skill heirarchy may be broken for " +
					repairSkill + ": " + e.getMessage());
				}
			}

			roll = roll - repairDifficulty;

			if (roll >= 0)
			{
				setRating(getRating() + (roll / 10) + 1);
				success = true;
			}
			else
			{
				if (roll < -25)
				{
					// catastrophic failure
					setRating(getRating() + (roll / 10) - 1);
				}
			}

		}

		return success;
	}

	/**
	 *  Set the rating. Check for object destruction.
	 */
	public void setRating(int rating)
	{
		if (rating > base_rating)
		{
			// don't allow objects to become supercharged
			rating = base_rating;
			super.setRating(rating);
		}
		else if (rating <= 0)
		{
			// object destroyed
			// this will, for now, be done quietly
			// perhaps in the future, an event should be tied to this
			// definitely, an unregister event should be fired by Persistant or
			// GameObject
			unregister();
		}
		else
		{
			super.setRating(rating);
		}
	}
	
	/**
	 *  Create the rows required to store this object
	 */
	protected void createRows()
	{
		super.createRows();

		Statement stmt = null;

		try
		{
			stmt = Persistant.getStatement();

			stmt.executeUpdate("INSERT INTO Equipment (equipment_id, equip_location, equipped, equip_size, lootable, repair_diff, repair_skill) VALUES (" + id + ", 0, 0, 0, 0, 0, 0)");

			stmt.close();
			stmt = null;
		}
		catch (SQLException e)
		{
			System.err.println("Trying to create Equipment (" + id + "): " +
			e.getMessage());
		}

		if (stmt != null)
		{
			try
			{
				stmt.close();
			}
			catch (SQLException e)
			{
				//
			}

			stmt = null;
		}
	}

	/**
	 *  Store this Equipment
	 */
	public void store()
	{
		super.store();

		Statement stmt = null;

		try
		{
			stmt = Persistant.getStatement();

			stmt.executeUpdate("UPDATE Equipment SET equipment_id=" + id + ", equip_location=" + equipLocation + ", equipped=" + (equipped ? "1" : "0") + ", equip_size=" + equipSize + ", lootable=" + (lootable ?  "1" : "0") + ", repair_diff=" + repairDifficulty + ", repair_skill='" + repairSkill + "'");
			
			stmt.close();
			stmt = null;
		}
		catch (SQLException e)
		{
			System.err.println("Trying to store Equipment (" + id + "): " +
			e.getMessage());
		}

		if (stmt != null)
		{
			try
			{
				stmt.close();
			}
			catch (SQLException e)
			{
				//
			}

			stmt = null;
		}

	}

	public static Equipment loadEquipment(int id)
	{
		Equipment e = null;

		if (Registry.isLoaded(id))
		{
			e = (Equipment)Registry.get(id);
		}
		else
		{
			e = new Equipment();
			e.id = id;
			e.load();
		}

		return e;
	}

	/**
	 *  Load an instance of Equipment
	 */
	protected void load()
	{
		super.load();

		Statement stmt = null;
		ResultSet rs = null;

		try
		{
			stmt = Persistant.getStatement();

			rs = stmt.executeQuery("SELECT * FROM Equipment WHERE equipment_id=" + id);

			while (rs.next())
			{
				equipLocation = (byte)rs.getInt("equip_location");
				equipped = (rs.getInt("equipped") == 1 ? true : false);
				equipSize = (byte)rs.getInt("equip_size");
				lootable = (rs.getInt("lootable") == 1 ? true : false);
				repairDifficulty = rs.getInt("repair_diff");
				repairSkill = rs.getString("repair_skill");
			}

			rs.close();
			rs = null;

			stmt.close();
			stmt = null;
		}
		catch (SQLException e)
		{
			System.err.println("Trying to load equipment (" + id + "): " +
			e.getMessage());
		}

		if (rs != null)
		{
			try
			{
				rs.close();
			}
			catch (SQLException e)
			{
				//
			}

			rs = null;
		}

		if (stmt != null)
		{
			try
			{
				stmt.close();
			}
			catch (SQLException e)
			{
				//
			}

			stmt = null;
		}
	}

	/**
	 *  Remove the object from the database.
	 */
	public void unregister()
	{
		Statement stmt = null;

		try
		{
			stmt = Persistant.getStatement();

			stmt.executeUpdate("DELETE FROM Equipment WHERE equipment_id=" + id);

			stmt.close();
			stmt = null;
		}
		catch (SQLException e)
		{
			System.err.println("Trying to unregister Equipment (" + id + "): "
			+ e.getMessage());
		}

		if (stmt != null)
		{	
			try
			{
				stmt.close();
			}
			catch (SQLException e)
			{
				//
			}

			stmt = null;
		}

		super.unregister();
	}

	/**
	 *  Tester
	 */
	public static void main(String [] args)
	{
		Equipment e = Equipment.createEquipment();
		e.store();

		int id = e.getID();

		e = null;

		try
		{
			Thread.sleep(15000);
		}
		catch (InterruptedException ie)
		{
			//
		}

		e = Equipment.loadEquipment(id);

		System.out.println(e.getID());
		
		e.unregister();
		e = null;
	}
}		

