/**
 * <p>
 * Copyright © 2009-2010, Bruce-Robert Pocock
 * </p>
 * <p>
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or (at
 * your option) any later version.
 * </p>
 * <p>
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License for more details.
 * </p>
 * <p>
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 * </p>
 * 
 * @author brpocock
 */

package org.starhope.appius.user;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;

import org.json.JSONException;
import org.json.JSONObject;
import org.starhope.appius.game.AppiusClaudiusCaecus;
import org.starhope.appius.game.inventory.ClothingItem;
import org.starhope.appius.game.inventory.InventoryItem;
import org.starhope.appius.sql.SQLPeerEnum;
import org.starhope.appius.types.Colour;
import org.starhope.appius.util.AppiusConfig;

/**
 * The avatar class defines a type of avatar which can be used by a game
 * player or NPC. Different avatar classes may use different physical
 * models, accept different clothing, &c. For example, different alien
 * races or mythical species might be represented by different avatar
 * classes.
 * 
 * @author brpocock
 */
public class AvatarClass extends SQLPeerEnum {

	/**
	 * A cache of whether the avatar class can be colorised
	 */
	final private static HashMap <Integer, Boolean> canColor = new HashMap <Integer, Boolean> ();
	/**
	 * A cache of the default base colour for the avatar class
	 */
	private static final HashMap <Integer, Long> defaultBaseColor = new HashMap <Integer, Long> ();
	/**
	 * A cache of the default extra/highlight/feature colour for the
	 * avatar class
	 */
	private static final HashMap <Integer, Long> defaultExtraColor = new HashMap <Integer, Long> ();
	/**
	 * A cache of the default pattern/hair/additional colour for the
	 * avatar class
	 */
	private static final HashMap <Integer, Long> defaultPatternColor = new HashMap <Integer, Long> ();
	/**
	 * A cache of the default pattern/hairstyle type for the avatar
	 * class
	 */
	final private static HashMap <Integer, Integer> defaultPatternID = new HashMap <Integer, Integer> ();
	/**
	 * A cache of avatar class filenames
	 */
	final private static HashMap <Integer, String> filenames = new HashMap <Integer, String> ();
	/**
	 * A cache of whether each avatar class is available to free users
	 */
	final private static HashMap <Integer, Boolean> forFree = new HashMap <Integer, Boolean> ();
	/**
	 * A cache of whether each avatar class is available to paid users
	 */
	final private static HashMap <Integer, Boolean> forVIT = new HashMap <Integer, Boolean> ();
	/**
	 * Java serialisation unique ID
	 */
	private static final long serialVersionUID = -5006183249551211836L;

	/**
	 * WRITEME: document this method (brpocock, Aug 27, 2009)
	 * 
	 * @param newID WRITEME
	 * @return WRITEME
	 */
	public static AvatarClass getByID (final int newID) {
		return new AvatarClass (newID);
	}

	/**
	 * TODO: document this method (brpocock, Dec 11, 2009)
	 *
	 * @param avatarTitle WRITEME
	 * @return WRITEME
	 */
	private static int getIDForAvatarTitle (final String avatarTitle) {
		if (avatarTitle.equals ("zap"))
			return 1;
		else if (avatarTitle.equals ("dottie"))
			return  2;
		else if (avatarTitle.equals ("superstar"))
			return  3;
		else if (avatarTitle.equals ("lilmc"))
			return  4;
		else if (avatarTitle.equals ("sparkle"))
			return  5;
		else if (avatarTitle.equals ("moo"))
			return  6;
		else if (avatarTitle.equals ("cupid"))
			return 7;
		else if (avatarTitle.equals ("flora"))
			return 8;
		else
			return  6;
	}

	/**
	 * Demolish caches
	 */
	public static void invalidateCache () {
		AvatarClass.canColor.clear ();
		AvatarClass.defaultBaseColor.clear ();
		AvatarClass.defaultExtraColor.clear ();
		AvatarClass.defaultPatternColor.clear ();
		AvatarClass.filenames.clear ();
		AvatarClass.forFree.clear ();
		AvatarClass.forVIT.clear ();
	}

	/**
	 * @param id Instantiate the AvatarClass represented by this ID
	 *        number.
	 */
	public AvatarClass (final int id) {
		super (AvatarClass.class, id);
	}

	/**
	 * @param avatarTitle WRITEME
	 */
	public AvatarClass (final String avatarTitle) {
		super (AvatarClass.class, AvatarClass.getIDForAvatarTitle (avatarTitle));
		prepCache ();
	}

	/**
	 * This is an overriding method.
	 * 
	 * @param set The ResultSet containing this AvatarClass object's
	 *        values
	 * @throws SQLException if the database has sadness upon us
	 * 
	 * @see org.starhope.appius.sql.SQLPeerEnum#cache(java.sql.ResultSet)
	 */
	@Override
	protected void cache (final ResultSet set) throws SQLException {
		while (set.next ()) {
			final int id = set.getInt ("id");
			System.err.println ("Caching a resultset for AvatarClass #"
					+ id);
			getEnumeration ().put (id, set.getString ("title"));
			AvatarClass.filenames.put (id, set.getString ("filename"));
			AvatarClass.forFree.put (id, set.getString ("forFree")
					.equals ("Y"));
			AvatarClass.forVIT.put (id, set.getString ("forVIT")
					.equals ("Y"));
			AvatarClass.defaultBaseColor.put (id, set
					.getLong ("defaultBaseColor"));
			AvatarClass.defaultExtraColor.put (id, set
					.getLong ("defaultExtraColor"));
			AvatarClass.defaultPatternID.put (id, set
					.getInt ("defaultPatternID"));
			AvatarClass.defaultPatternColor.put (id, set
					.getLong ("defaultPatternColor"));
			AvatarClass.canColor.put (id, set.getString ("canColor")
					.equals ("Y"));
		}
	}

	/**
	 * Return whether this avatar class can be colorised (2 planes) or
	 * not.
	 * 
	 * @return Whether this avatar class can be colorised
	 */
	public boolean canColor () {
		System.err.print ("canColor.size:"
				+ AvatarClass.canColor.size ());
		if (AvatarClass.canColor.size () == 0) {
			prepCache ();
		}
		System.err.println ("=>" + AvatarClass.canColor.size ());
		return AvatarClass.canColor.get (instance);
	}

	/**
	 * 
	 * This is an overriding method.
	 * 
	 * @see org.starhope.appius.sql.SQLPeerDatum#flush()
	 */
	@Override
	public void flush () {
		PreparedStatement update = null;
		try {
			update = AppiusConfig
			.getDatabaseConnection ()
			.prepareStatement (
					"UPDATE avatarClasses SET title=?, filename=?, "
					+ "forFree=?, forVIT=?, "
					+ "defaultBaseColor=?, defaultExtraColor=?, "
					+ "defaultPattern=?, defaultPatternColor=?, canColor=? "
					+ "WHERE id=?");
			update.setString (1, this.getString ());
			update.setString (2, getFilename ());
			update.setString (3, isForFree () ? "Y" : "N");
			update.setString (4, isForVIT () ? "Y" : "N");
			update.setLong (5, getDefaultBaseColor ().toLong ());
			update.setLong (6, getDefaultExtraColor ().toLong ());
			update.setString (7, getDefaultPattern ().toString ());
			update.setLong (8, getDefaultPatternColor ().toLong ());
			update.setString (9, canColor () ? "Y" : "N");
			update.setInt (10, instance);
			update.executeUpdate ();
		} catch (final SQLException e) {
			throw AppiusClaudiusCaecus.fatalBug (e);
		} finally {
			if (null != update) {
				try {
					update.close ();
				} catch (final SQLException e) {
					AppiusClaudiusCaecus.reportBug (e);
				}
			}
		}
	}

	/**
	 * TODO: document this method (brpocock, Oct 13, 2009)
	 * 
	 * @param avatarNum WRITEME
	 * @return WRITEME
	 */
	public String getAvatarString (final int avatarNum) {
		if (avatarNum == 1)
			return "zap";
		else if (avatarNum == 2)
			return "dottie";
		else if (avatarNum == 3)
			return "superstar";
		else if (avatarNum == 4)
			return "lilmc";
		else if (avatarNum == 5)
			return "sparkle";
		else if (avatarNum == 6)
			return "moo";
		else if (avatarNum == 7)
			return "cupid";
		else if (avatarNum == 8)
			return "cupid";
		else
			return "moo";
	}

	/**
	 * @return WRITEME
	 */
	public Colour getDefaultBaseColor () {
		if (AvatarClass.defaultBaseColor.size () == 0) {
			prepCache ();
		}
		return new Colour (AvatarClass.defaultBaseColor.get (instance));
	}

	/**
	 * @return WRITEME
	 */
	public Colour getDefaultExtraColor () {
		if (AvatarClass.defaultExtraColor.size () == 0) {
			prepCache ();
		}
		return new Colour (AvatarClass.defaultExtraColor.get (instance));
	}

	/**
	 * @return WRITEME
	 */
	public ClothingItem getDefaultPattern () {
		if (AvatarClass.defaultPatternColor.size () == 0) {
			prepCache ();
		}
		final ClothingItem pattern = (ClothingItem) InventoryItem
		.getByID (AvatarClass.defaultPatternID.get (instance));
		pattern.setColor (new Colour (AvatarClass.defaultPatternColor
				.get (instance)));
		return pattern;
	}

	/**
	 * @return default pattern color
	 */
	public Colour getDefaultPatternColor () {
		if (AvatarClass.defaultPatternColor.size () == 0) {
			prepCache ();
		}
		return new Colour (AvatarClass.defaultPatternColor
				.get (instance));
	}

	/**
	 * @return SWF filename/URL
	 */
	public String getFilename () {
		if (AvatarClass.filenames.size () == 0) {
			prepCache ();
		}
		return AvatarClass.filenames.get (instance);
	}

	/**
	 * This is an overriding method.
	 * 
	 * @see org.starhope.appius.sql.SQLPeerEnum#getStatement(java.sql.Connection)
	 */
	@Override
	protected PreparedStatement getStatement (
			final Connection connection) {
		try {
			return connection
			.prepareStatement ("SELECT * FROM avatarClasses");
		} catch (final SQLException e) {
			throw AppiusClaudiusCaecus.fatalBug (e);
		}
	}

	/**
	 * @return true if this is available for free users
	 */
	public boolean isForFree () {
		if (AvatarClass.forFree.size () == 0) {
			prepCache ();
		}
		return AvatarClass.forFree.get (instance);
	}

	/**
	 * @return true if this is available for paid users
	 */
	public boolean isForVIT () {
		if (AvatarClass.forVIT.size () == 0) {
			prepCache ();
		}
		return AvatarClass.forVIT.get (instance);
	}

	/**
	 * This is an overriding method.
	 * 
	 * @see org.starhope.appius.sql.SQLPeerDatum#set(java.sql.ResultSet)
	 */
	@Override
	protected void set (final ResultSet rs) throws SQLException {
		AppiusClaudiusCaecus.reportBug ("Method should be unreachable");
	}

	/**
	 * @return this object cast as an ActionScript Object for the
	 *         client.
	 */
	@Override
	public JSONObject toJSON () {
		final JSONObject self = super.toJSON ();
		try {
			self.put ("avatarClassID", this.getID ());
			self.put ("title", this.getString ());
			self.put ("filename", getFilename ());
			self.put ("forFree", isForFree ());
			self.put ("forVIT", isForVIT ());
		} catch (final JSONException e) {
			// Default catch action, report bug (brpocock, Aug 17, 2009)
			AppiusClaudiusCaecus.reportBug (e);
		}
		return self;
	}

	/**
	 * 
	 * String representation is currently the JSON data
	 * 
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString () {
		return toJSON ().toString ();
	}
}
