/**
 * <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.via;

import java.util.Collection;
import java.util.concurrent.ConcurrentHashMap;

import org.json.JSONException;
import org.json.JSONObject;
import org.starhope.appius.except.GameLogicException;
import org.starhope.appius.game.AbstractRoom;
import org.starhope.appius.game.AppiusClaudiusCaecus;
import org.starhope.appius.types.AbstractZone;
import org.starhope.appius.user.AbstractUser;

/**
 * 
 * TODO: The documentation for this type (RemoteZone) is incomplete.
 * (brpocock, Nov 5, 2009)
 * 
 * @author brpocock
 * 
 */
public class RemoteZone implements AbstractZone,
ViaMunita <AbstractZone> {

	/**
	 * WRITEME: document this field (brpocock, Jan 11, 2010) knownZones
	 * (RemoteZone)
	 */
	private static ConcurrentHashMap <String, AbstractZone> knownZones = new ConcurrentHashMap <String, AbstractZone> ();

	/**
	 * TODO: document this method (brpocock, Jan 11, 2010)
	 * 
	 * @param remoteZoneName WRITEME
	 * @return WRITEME
	 */
	public static AbstractZone getByName (final String remoteZoneName) {
		if (RemoteZone.knownZones.containsKey (remoteZoneName))
			return RemoteZone.knownZones.get (remoteZoneName);

		return null; // FIXME
	}

	/**
	 * The port number of the remote Appius server
	 */
	private final int remotePort;
	/**
	 * The hostname of the remote Appius server
	 */
	private final String remoteServer;
	/**
	 * The zone to which this one is a peer
	 */
	private final String remoteZone;


	/**
	 * @param url The URL of the remote Zone
	 */
	public RemoteZone (final String url) {
		remoteServer = Via.getServerNameFromURL (url);
		remotePort = Via.getPortNumberFromURL (url);
		final String path = Via.getPathFromURL (url);
		if ( !path.startsWith ("Zone/"))
			throw AppiusClaudiusCaecus.fatalBug ("URL is not a Zone: "
					+ url);
		remoteZone = path.substring (path.indexOf ("Zone/") + 5);
	}

	/**
	 * This is an overriding method.
	 * 
	 * @see org.starhope.appius.types.AbstractZone#activate()
	 */
	public void activate () {
		Via.rpc (this, "activate");
	}

	/**
	 * This is an overriding method.
	 * 
	 * @see org.starhope.appius.types.AbstractZone#add(org.starhope.appius.game.AbstractRoom)
	 */
	public void add (final AbstractRoom room) {
		Via.rpc (this, "add", room);
	}

	/**
	 * @see org.starhope.appius.types.AbstractZone#clearAllBadges()
	 */
	public void clearAllBadges () {
		Via.rpc (this, "clearAllBadges");
	}

	/**
	 * @see org.starhope.appius.types.AbstractZone#clearAllBadges(org.starhope.appius.game.AbstractRoom)
	 */
	public void clearAllBadges (final AbstractRoom roomByName) {
		Via.rpc (this, "clearAllBadges", roomByName);
	}

	/**
	 * @see org.starhope.appius.types.AbstractZone#clearBadge(java.lang.String)
	 */
	public void clearBadge (final String badgeName)
	throws GameLogicException {
		Via.rpc (this, "clearBadge", badgeName);
	}

	/**
	 * @see org.starhope.appius.types.AbstractZone#compareTo(org.starhope.appius.types.AbstractZone)
	 */
	public int compareTo (final AbstractZone other) {
		return ((Integer) Via.rpc (this, "compareTo", other))
		.intValue ();
	}

	/**
	 * This is an overriding method.
	 * 
	 * @see org.starhope.appius.types.AbstractZone#destroy()
	 */
	public void destroy () {
		Via.rpc (this, "destroy");
	}

	/**
	 * This is an overriding method.
	 * 
	 * @see org.starhope.appius.types.AbstractZone#destroyRoom(org.starhope.appius.game.AbstractRoom)
	 */
	public void destroyRoom (final AbstractRoom room) {
		Via.rpc (this, "destroyRoom", room);
	}

	/**
	 * @see org.starhope.appius.types.AbstractZone#getAllUsersIDsInZone()
	 */
	@SuppressWarnings ("unchecked")
	public Collection <Integer> getAllUsersIDsInZone () {
		return (Collection <Integer>) Via.rpc (this,
		"getAllUserIDsInZone");
	}

	/**
	 * This is an overriding method.
	 * 
	 * @see org.starhope.appius.types.AbstractZone#getAllUsersInZone()
	 */
	@SuppressWarnings ("unchecked")
	public Collection <AbstractUser> getAllUsersInZone () {
		return (Collection <AbstractUser>) Via.rpc (this,
		"getAllUsersInZone");
	}

	/**
	 * This is an overriding method.
	 * 
	 * @see org.starhope.appius.types.AbstractZone#getHost()
	 */
	public String getHost () {
		return remoteServer;
	}

	/**
	 * This is an overriding method.
	 * 
	 * @see org.starhope.appius.types.AbstractZone#getMaxUsers()
	 */
	public int getMaxUsers () {
		return ((Integer) Via.rpc (this, "getMaxUsers",
				new Object [] {})).intValue ();
	}

	/**
	 * This is an overriding method.
	 * 
	 * @see org.starhope.appius.types.AbstractZone#getName()
	 */
	public String getName () {
		return remoteZone;
	}

	/**
	 * @see org.starhope.appius.types.AbstractZone#getNextLobby()
	 */
	public AbstractRoom getNextLobby () {
		return (AbstractRoom) Via.rpc (this, "getNextLobby");
	}

	/**
	 * This is an overriding method.
	 * 
	 * @see org.starhope.appius.types.AbstractZone#getPort()
	 */
	public int getPort () {
		return remotePort;
	}

	/**
	 * This is an overriding method.
	 * 
	 * @see org.starhope.appius.types.AbstractZone#getRoom(java.lang.Integer)
	 */
	public AbstractRoom getRoom (final Integer room) {
		return (AbstractRoom) Via.rpc (this, "getRoom", room);
	}

	/**
	 * This is an overriding method.
	 * 
	 * @see org.starhope.appius.types.AbstractZone#getRoomByName(java.lang.String)
	 */
	public AbstractRoom getRoomByName (final String string) {
		return (AbstractRoom) Via.rpc (this, "getRoomByName", string);
	}

	/**
	 * This is an overriding method.
	 * 
	 * @see org.starhope.appius.types.AbstractZone#getRoomList()
	 */
	@SuppressWarnings ("unchecked")
	public Collection <AbstractRoom> getRoomList () {
		return (Collection <AbstractRoom>) Via
		.rpc (this, "getRoomList");
	}

	/**
	 * This is an overriding method.
	 * 
	 * @see org.starhope.appius.types.AbstractZone#getRoomListSFSXML()
	 */
	public String getRoomListSFSXML () {
		return (String) Via.rpc (this, "getRoomListSFSXML");
	}

	/**
	 * This is an overriding method.
	 * 
	 * @see org.starhope.appius.types.AbstractZone#getRoomMaxUsers()
	 */
	public int getRoomMaxUsers () {
		return ((Integer) Via.rpc (this, "getRoomMaxUsers",
				new Object [] {})).intValue ();

	}

	/**
	 * This is an overriding method.
	 * 
	 * @see org.starhope.appius.types.AbstractZone#getURL()
	 */
	public String getURL () {
		return (String) Via.rpc (this, "getURL");
	}

	/**
	 * This is an overriding method.
	 * 
	 * @see org.starhope.appius.types.AbstractZone#getUserByName(java.lang.String)
	 */
	public AbstractUser getUserByName (final String buddy) {
		return (AbstractUser) Via.rpc (this, "getUserByName", buddy);
	}

	/**
	 * This is an overriding method.
	 * 
	 * @see org.starhope.appius.types.AbstractZone#getUserRoom(AbstractUser)
	 */
	public AbstractRoom getUserRoom (final AbstractUser user) {
		return (AbstractRoom) Via.rpc (this, "getUserRoom", user);
	}

	/**
	 * This is an overriding method.
	 * 
	 * @see org.starhope.appius.via.ViaMunita#getViaAppiaHostname()
	 */
	public String getViaAppiaHostname () {
		return remoteServer;
	}

	/**
	 * This is an overriding method.
	 * 
	 * @see org.starhope.appius.via.ViaMunita#getViaAppiaRemoteEndpointID()
	 */
	public String getViaAppiaRemoteEndpointID () {
		return "Zone/" + remoteZone;
	}

	/**
	 * This is an overriding method.
	 * 
	 * @see org.starhope.appius.via.ViaMunita#getViaAppiaServerPort()
	 */
	public int getViaAppiaServerPort () {
		return remotePort;
	}

	/**
	 * @see org.starhope.appius.via.ViaMunita#getViaPeerClass()
	 */
	public Class <AbstractZone> getViaPeerClass () {
		return AbstractZone.class;
	}

	/**
	 * This is an overriding method.
	 * 
	 * @see org.starhope.appius.types.AbstractZone#getZoneData_JSON(AbstractUser)
	 */
	public JSONObject getZoneData_JSON (final AbstractUser user)
	throws JSONException {
		return (JSONObject) Via.rpc (this, "getZoneData_JSON", user);
	}

	/**
	 * @see org.starhope.appius.types.AbstractZone#getZoneList_JSON(org.starhope.appius.user.AbstractUser)
	 */
	public JSONObject getZoneList_JSON (final AbstractUser u) {
		return (JSONObject) Via.rpc (this, "getZoneList_JSON", u);
	}

	/**
	 * This is an overriding method.
	 * 
	 * @see org.starhope.appius.types.AbstractZone#handleSpeak(int,
	 *      AbstractUser, String)
	 */
	public void handleSpeak (final int roomNumber,
			final AbstractUser user, final String speech) {
		Via.rpc (this, "handleSpeak", new Object [] {
				Integer.valueOf (roomNumber), user, speech });

	}

	/**
	 * This is an overriding method.
	 * 
	 * @see org.starhope.appius.types.AbstractZone#init()
	 */
	public void init () {
		Via.rpc (this, "handleSpeak", new Object [] {});
	}

	/**
	 * This is an overriding method.
	 * 
	 * @see org.starhope.appius.types.AbstractZone#remove(AbstractUser)
	 */
	public void remove (final AbstractUser user) {
		Via.rpc (this, "remote", new Object [] { user });

	}

	/**
	 * @see org.starhope.appius.types.AbstractZone#retire()
	 */
	public void retire () {
		Via.rpc (this, "retire");
	}

	/**
	 * @param o WRITEME
	 * @see org.starhope.appius.util.CastsToJSON#set(org.json.JSONObject)
	 */
	public void set (final JSONObject o) {
		Via.rpc (this, "set", o);
	}

	/**
	 * This is an overriding method.
	 * 
	 * @see org.starhope.appius.types.AbstractZone#setAutoJoinRoom(int)
	 */
	public void setAutoJoinRoom (final int id) {
		Via.rpc (this, "setAutoJoinRoom", new Object [] { Integer
				.valueOf (id) });
	}

	/**
	 * @see org.starhope.appius.types.AbstractZone#setBadge(java.lang.String,
	 *      org.starhope.appius.game.AbstractRoom)
	 */
	public void setBadge (final String string, final AbstractRoom room) {
		Via.rpc (this, "setBadge", string, room);
	}

	/**
	 * This is an overriding method.
	 * 
	 * @see org.starhope.appius.types.AbstractZone#spawnNewZone()
	 */
	public String spawnNewZone () {
		return (String) Via.rpc (this, "spawnNewZone");
	}

	/**
	 * @see org.starhope.appius.types.AbstractZone#spawnZone(java.lang.String)
	 */
	public void spawnZone (final String newZone) {
		Via.rpc (this, "spawnZone", newZone);
	}

	/**
	 * This is an overriding method.
	 * 
	 * @see org.starhope.appius.types.AbstractZone#tellEaves(AbstractUser,
	 *      AbstractRoom, String, String)
	 */
	public void tellEaves (final AbstractUser user,
			final AbstractRoom room, final String verb,
			final String note) {
		Via.rpc (this, "tellEaves", user, room, verb, note);
	}

	/**
	 * @return WRITEME
	 * @see org.starhope.appius.util.CastsToJSON#toJSON()
	 */
	public JSONObject toJSON () {
		return (JSONObject) Via.rpc (this, "toJSON");
	}

	/**
	 * This is an overriding method.
	 * 
	 * @see org.starhope.appius.types.AbstractZone#trace(java.lang.String)
	 */
	public void trace (final String string) {
		Via.rpc (this, "trace", string);
	}
}
