/**
 *  Graphic stores information about a graphic image.
 */
package sso;

import java.sql.*;
import java.util.*;
import sso.event.*;

public class Graphic extends Persistant
{
	protected int		x_width;				// defines bounding box
	protected int		y_length;
	protected int		z_height;
	protected String[][]	image_uri;
	protected Vector	propertyChangeListeners;

	/**
	 *  Constructor. Never called directly.
	 *  Use a factor method instead.
	 */
	protected Graphic()
	{
		super();
		image_uri = new String[GameObject.FACING_DIR_COUNT][GameObject.FACING_MOD_COUNT];
		propertyChangeListeners = new Vector();
System.out.println("Graphic() constructor called.");
	}

	/**
	 *  Factory method. Intended for creating new objects.
	 *  For loading objects from the database, use the loadGraphic() method.
	 */
	public static Graphic createGraphic()
	{
		Graphic g = new Graphic();

		g.init();

		return g;
	}

	/**
	 *  Initializer for factory method.
	 */
	protected void init()
	{
System.out.println("Graphic.init() called.");
		super.init();

		// units in tiles
		x_width = 1;
		y_length = 1;
		z_height = 1;

		// init the image_uris
		for (int i = 0; i < GameObject.FACING_DIR_COUNT; i++)
		{
			for (int j = 0; j < GameObject.FACING_MOD_COUNT; j++)
			{
				image_uri[i][j] = new String();
			}
		}

	}

	/**
	 *  Get width.
	 */
	public int getWidth()
	{
		return x_width;
	}

	/**
	 *  Set width.
	 */
	public void setWidth(int width)
	{
		x_width = width;
		propChange("x_width");
	}

	/**
	 *  Get length.
	 */
	public int getLength()
	{
		return y_length;
	}

	/**
	 *  Set length.
	 */
	public void setLength(int length)
	{
		y_length = length;
		propChange("y_length");
	}

	/**
	 *  Get height.
	 */
	public int getHeight()
	{
		return z_height;
	}

	/**
	 *  Set height.
	 */
	public void setHeight(int height)
	{
		z_height = height;
		propChange("z_height");
	}

	/**
	 *  Get graphic.
	 */
	public String getURI(int mode)
	{
		return image_uri[getDirectionIndex(mode)][getModifierIndex(mode)];
	}

	/**
	 *  Set graphic.
	 */
	public void setURI(int mode, String uri)
	{
		image_uri[getDirectionIndex(mode)][getModifierIndex(mode)] = uri;
		propChange("image_uri");
	}

	/**
	 *  Helpful method for determining facing graphic.
	 */
	public int getDirectionIndex(int mode)
	{
		if ((mode & GameObject.NORTH) == GameObject.NORTH)
		{
			return 0;
		}
		else if ((mode & GameObject.EAST) == GameObject.EAST)
		{
			return 1;
		}
		else if ((mode & GameObject.SOUTH) == GameObject.SOUTH)
		{
			return 2;
		}
		else if ((mode & GameObject.WEST) == GameObject.WEST)
		{
			return 3;
		}

		// out of range index error will be raised
		return -1;
	}

	/**
	 *  Helpful method for determining facing graphic.
	 */
	public int getModifierIndex(int mode)
	{
		if ((mode & GameObject.STAND) == GameObject.STAND)
		{
			return 0;
		}
		else if ((mode & GameObject.SIT) == GameObject.SIT)
		{
			return 1;
		}
		else if ((mode & GameObject.LIE) == GameObject.LIE)
		{
			return 2;
		}
		else if ((mode & GameObject.DEAD) == GameObject.DEAD)
		{
			return 3;
		}
		else if ((mode & GameObject.WALK) == GameObject.WALK)
		{
			return 4;
		}
		else if ((mode & GameObject.RUN) == GameObject.RUN)
		{
			return 5;
		}

		// out of range index error will be raised
		return -1;
	}

	/**
	 *  Get a default graphic object (promote reuse).
	 */
	protected static Graphic getDefaultGraphic()
	{
		// gets the default Graphic out of the database
		return Graphic.loadGraphic(Registry.ID_DEFAULT_GRAPHIC);
	}
	
	/**
	 *  Create the rows needed to store the graphic.
	 */
	protected void createRows()
	{
System.out.println("Graphic.createRows() called.");
		super.createRows();

		Statement stmt = null;

		try
		{
			stmt = Persistant.getStatement();

			stmt.executeUpdate("INSERT INTO Graphic (graphic_id, width, length, height) VALUES (" + id + ", 1, 1, 1)");

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

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

			stmt = null;
		}
	}
	
	/**
	 *  Store the graphic in the database.
	 */
	public void store()
	{
System.out.println("Graphic.store() called.");
		Statement stmt = null;

		try
		{
			stmt = Persistant.getStatement();

			// update the graphic URIs first
			stmt.executeUpdate("DELETE FROM Graphic_URIs WHERE graphic_id=" + id);

			// re-add the graphics
			int i, j, mode;
			
			for (i = 0; i < GameObject.FACING_DIR_COUNT; i++)
			{
				for (j = 0; j < GameObject.FACING_MOD_COUNT; j++)
				{
					mode = 0;

					switch (i)
					{
						case 0:
							mode |= GameObject.NORTH;
							break;
						case 1:
							mode |= GameObject.EAST;
							break;
						case 2:
							mode |= GameObject.SOUTH;
							break;
						case 3:
							mode |= GameObject.WEST;
							break;
					}

					switch (j)
					{
						case 0:
							mode |= GameObject.STAND;
							break;
						case 1:
							mode |= GameObject.SIT;
							break;
						case 2:
							mode |= GameObject.LIE;
							break;
						case 3:
							mode |= GameObject.DEAD;
							break;
						case 4:
							mode |= GameObject.WALK;
							break;
						case 5:
							mode |= GameObject.RUN;
							break;
					}

					stmt.executeUpdate("INSERT INTO Graphic_URIs (graphic_id, mode, uri) VALUES (" + id + ", " + mode + ", '" + image_uri[i][j] + "')");
				
				}
			}

			// update the graphic table
			stmt.executeUpdate("UPDATE Graphic SET width=" + x_width + ", length=" + y_length + ", height=" + z_height + " WHERE graphic_id=" + id);

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

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

			stmt = null;
		}

System.out.print("calling super.store()...");
		super.store();
	}

	/**
	 *  Load the graphic from the database.
	 */
	public static Graphic loadGraphic(int id)
	{
		Graphic g = null;

		if (Registry.isLoaded(id))
		{
			g = (Graphic)Registry.get(id);
		}
		else
		{
			g = new Graphic();
			g.id = id;
			g.load();
		}

		return g;
	}

	/**
	 *  Internals for loading Graphic.
	 */
	protected void load()
	{
		super.load();

		Statement stmt = null;
		ResultSet rs = null;
		
		try
		{
			stmt = Persistant.getStatement();

			rs = stmt.executeQuery("SELECT * FROM Graphic WHERE graphic_id=" +
			getID());

			while (rs.next())
			{
				x_width = rs.getInt("width");
				y_length = rs.getInt("length");
				z_height = rs.getInt("height");
			}

			rs.close();
			rs = null;
			
			// load the graphic uris
			
			rs = stmt.executeQuery("SELECT * FROM Graphic_URIs WHERE graphic_id=" + getID());

			int mode;

			while (rs.next())
			{
				mode = rs.getInt("mode");
				image_uri[getDirectionIndex(mode)][getModifierIndex(mode)] = rs.getString("uri");
			}

			rs.close();
			rs = null;

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

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

			stmt = null;
		}
	}

	/**
	 *  Unregister Graphic
	 */
	public void unregister()
	{
		Statement stmt = null;
		ResultSet rs = null;

		try
		{
			stmt = Persistant.getStatement();

			// first, clean out references from existing GameObjects
			rs = stmt.executeQuery("SELECT id FROM GameObject WHERE graphic_id=" + id);

			GameObject go;

			while (rs.next())
			{
				go = GameObject.loadGameObject(rs.getInt("id"));
				// dummy graphic
				go.setGraphic(Graphic.createGraphic());
			}

			go = null;

			rs.close();
			rs = null;

			stmt.executeUpdate("DELETE FROM Graphic_URIs WHERE graphic_id=" + id);

			stmt.executeUpdate("DELETE FROM Graphic WHERE graphic_id=" + id);

			// to keep GameObjects from bombing out later
			stmt.executeUpdate("UPDATE GameObject SET graphic_id=-1 WHERE graphic_id=" + id);
		}
		catch (SQLException e)
		{
			System.err.println("Trying to delete Graphic (" + 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;
		}

		super.unregister();
	}
	// EVENTS
	/**
	 *  Register the property change listeners.
	 */
	public void addPropertyChangeListener(PropertyChangeListener pl)
	{
		propertyChangeListeners.addElement(pl);
	}

	/**
	 *  Unregister a property change listener.
	 */
	public void removePropertyChangeListener(PropertyChangeListener pl)
	{
		propertyChangeListeners.removeElement(pl);
	}
	
	/**
	 *  Fire a property change event.
	 */
	protected void propChange(String propname)
	{
		PropertyChangeEvent pe = new PropertyChangeEvent(this, propname);

		Vector vl = (Vector)propertyChangeListeners.clone();

		for (int i = 0; i < vl.size(); i++)
		{
			((PropertyChangeListener)vl.elementAt(i)).notifyPropertyChange(pe);
		}
	}
}

