/**
 * <p>
 * Copyright © 2010, Res Interactive, LLC
 * </p>
 * 
 * @author brpocock@star-hope.org
 */
package com.tootsville.game;

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

import org.json.JSONObject;
import org.starhope.appius.except.NotFoundException;
import org.starhope.appius.except.UserDeadException;
import org.starhope.appius.game.AppiusClaudiusCaecus;
import org.starhope.appius.game.GameEvent;
import org.starhope.appius.game.Zone;
import org.starhope.appius.geometry.Coord3D;
import org.starhope.appius.room.Room;
import org.starhope.appius.user.AbstractUser;
import org.starhope.appius.util.AppiusConfig;

/**
 * Tootlympics scoreboard and torch-lighting magic with Superstar
 * 
 * @author brpocock@star-hope.org
 */
public class Tootlympics extends GameEvent {

	/**
	 * Java Serialisation
	 */
	private static final long serialVersionUID = 3524007638280001765L;

	/**
	 * WRITEME: document this field (brpocock@star-hope.org, Feb 12,
	 * 2010) bottom (Tootlympics)
	 */
	int bottom = -1;

	/**
	 * WRITEME: document this field (brpocock@star-hope.org, Feb 12,
	 * 2010) left (Tootlympics)
	 */
	int left = -1;

	/**
	 * Time to next refresh scoreboard
	 */
	private long nextUpdate = 0;

	/**
	 * WRITEME: document this field (brpocock@star-hope.org, Feb 12,
	 * 2010) right (Tootlympics)
	 */
	int right = -1;

	/**
	 * WRITEME: document this field (brpocock@star-hope.org, Feb 12,
	 * 2010) top (Tootlympics)
	 */
	int top = -1;
	
	/**
	 * Instantiate the Tootlympics into a Zone
	 * 
	 * @param z The Zone into which it should be instantiated
	 */
	public Tootlympics (final Zone z) {
		super (z, 't');
		Room firstVillage;
		try {
			firstVillage = z.getRoomByName ("tootlympicsFirstVillage");
		} catch (NotFoundException e1) {
			throw new RuntimeException (e1);
		}
		firstVillage.setVariable ("anim~torch", "1");
		rooms.add (firstVillage);
		firstVillage.add (this);
		try {
			scoreWatchRooms.add (z
					.getRoomByName ("tootlympicsScoreBoard"));
		} catch (NotFoundException e1) {
			throw new RuntimeException (e1);
		}
		try {
			left = AppiusConfig
					.getInt ("com.tootsville.game.Tootlympics.torch.left");
			right = AppiusConfig
					.getInt ("com.tootsville.game.Tootlympics.torch.right");
			top = AppiusConfig
					.getInt ("com.tootsville.game.Tootlympics.torch.top");
			bottom = AppiusConfig
					.getInt ("com.tootsville.game.Tootlympics.torch.bottom");
		} catch (final NumberFormatException e) {
			AppiusClaudiusCaecus
					.reportBug (
							"Caught a NumberFormatException in Tootlympics user var update",
							e);

		} catch (final NotFoundException e) {
			AppiusClaudiusCaecus
					.reportBug (
							"Caught a NotFoundException in Tootlympics user var update",
							e);

		}
	}
	
	/**
	 * This is an overriding method.
	 * 
	 * @see org.starhope.appius.room.RoomListener#acceptGameAction(org.starhope.appius.user.AbstractUser,
	 *      org.json.JSONObject)
	 */
	@Override
	public void acceptGameAction (final AbstractUser u,
			final JSONObject action) {
		/* No op */
	}
	
	/**
	 * This is an overriding method.
	 * 
	 * @see org.starhope.appius.room.RoomListener#acceptOutOfBandMessage(org.starhope.appius.user.AbstractUser,
	 *      org.starhope.appius.room.Room, org.json.JSONObject)
	 */
	@Override
	public void acceptOutOfBandMessage (final AbstractUser sender,
			final Room room, final JSONObject body) {
		/* No op */
	}
	
	/**
	 * This is an overriding method.
	 * 
	 * @see org.starhope.appius.room.RoomListener#acceptPublicMessage(org.starhope.appius.user.AbstractUser,
	 *      java.lang.String)
	 */
	@Override
	public void acceptPublicMessage (final AbstractUser from,
			final String message) {
		/* No op */
	}

	/**
	 * @see org.starhope.appius.room.RoomListener#acceptUserAction(org.starhope.appius.room.Room, org.starhope.appius.user.AbstractUser)
	 */
	@Override
	public void acceptUserAction (final Room r, final AbstractUser u) {
		// no op
	}

	/**
	 * This is an overriding method.
	 *
	 * @see org.starhope.appius.game.GameEvent#acceptUserVariableUpdate(org.starhope.appius.user.AbstractUser,
	 *      java.lang.String, java.lang.String)
	 */
	@Override
	public void acceptUserVariableUpdate (final AbstractUser user,
			final String varName, final String varValue) {
		super.acceptUserVariableUpdate (user, varName, varValue);
		/*
		 * User 116 is Superstar. If he's stopped moving, check his
		 * position
		 */
		final int userID = user.getUserID ();
		if (116 == userID && "d".equals (varName)) {
			final Coord3D from = user.getLocation ();
			final Coord3D to = user.getTarget ();
			final double x = from.getX ();
			final double y = from.getY ();
			final double targetX = to.getX ();
			final double targetY = to.getY ();
			if (Math.abs (x - targetX) > 2
					|| Math.abs (y - targetY) > 2) {
				/* Still moving. Ignore */
				return;
			}

			if (left <= x && right >= x && top <= y && bottom >= y) {
				rooms.first ().setVariable ("anim~torch", "2");
			}
		}

		/*
		 * User 99236 is Shade. Shade has the power of darkness, so he
		 * can shoot the torch out.
		 */
		if (99236 == userID && "s".equals (varName)) {

			final String [] shotInfo = varValue.split ("~");
			final double targetX = Double.parseDouble (shotInfo [2]);
			final double targetY = Double.parseDouble (shotInfo [3]);

			if (left <= targetX) {
				rooms.first ().setVariable ("anim~torch", "1");
			}

			AppiusClaudiusCaecus.blather ("Shade shot to " + targetX
					+ "," + targetY);
		}
	}

	/**
	 * This is an overriding method.
	 *
	 * @see org.starhope.appius.game.GameEvent#getGameEventPrefix()
	 */
	@Override
	public String getGameEventPrefix () {
		return "tootlympics";
	}

	/**
	 * This is an overriding method.
	 *
	 * @see org.starhope.appius.util.HasName#getName()
	 */
	@Override
	public String getName () {
		return "Tootlympics";
	}

	/**
	 * This is an overriding method.
	 *
	 * @see org.starhope.appius.game.GameEvent#tick(long, long)
	 */
	@Override
	public void tick (final long currentTime, final long deltaTime)
			throws UserDeadException {
		if (nextUpdate < currentTime) {
			updateScores ();
		}
		super.tick (currentTime, deltaTime);
	}

	/**
	 * This is an overriding method.
	 *
	 * @see org.starhope.appius.game.GameEvent#updateRoomVars()
	 */
	@Override
	protected void updateRoomVars () {
		/* No! Don't! */
	}

	/**
	 * This is an overriding method.
	 *
	 * @see org.starhope.appius.game.GameEvent#updateScores()
	 */
	@Override
	protected void updateScores () {
		nextUpdate = System.currentTimeMillis () + 60 * 1000;

		Connection con = null;
		PreparedStatement st = null;
		ResultSet rs = null;
		try {
			con = AppiusConfig.getDatabaseConnection ();
			/*
			 * This statement filters out spurious bronze medals being
			 * awarded by
			 */
			st = con
					.prepareStatement ("SELECT u.userName, SUM(e.medalType = 2) AS golds, SUM(e.medalType = 1) AS silvers, SUM(e.medalType = 0) AS bronzes, ( SUM(e.medalType = 2) * 10 + SUM(e.medalType = 1) * 5 + SUM(e.medalType = 0) ) AS score FROM events AS e LEFT JOIN users AS u ON u.ID=e.creatorID WHERE e.medalType IS NOT NULL AND e.medalType >= 0 AND e.medalType <= 2 AND WEEK(e.completionTimestamp + INTERVAL 1 DAY,0) = WEEK(NOW() + INTERVAL 1 DAY,0) AND e.eventTypeID NOT IN (149,150) GROUP BY u.userName ORDER BY score DESC LIMIT 10");
			st.execute ();
			rs = st.getResultSet ();
			int place = 0;
			while (rs.next ()) {
				++place;
				scoreWatchRooms.first ().setVariable (
						"hs~" + place,
						rs.getString ("userName") + "~"
								+ rs.getInt ("golds") + "~"
								+ rs.getInt ("silvers") + "~"
								+ rs.getInt ("bronzes"));
			}
		} catch (final SQLException e) {
			AppiusClaudiusCaecus.reportBug (
					"Caught a SQLException in tick", e);
		} finally {
			if (null != rs) {
				try {
					rs.close ();
				} catch (final SQLException e) { /* No op */
				}
			}
			if (null != st) {
				try {
					st.close ();
				} catch (final SQLException e) { /* No op */
				}
			}
			if (null != con) {
				try {
					con.close ();
				} catch (final SQLException e) { /* No op */
				}
			}
		}
		super.updateScores ();
	}

}
