/**
 * FlxKongregate
 * -- Part of the Flixel Power Tools set
 * 
 * v1.0 First release
 * 
 * @version 1.0 - August 1st 2011
 * @link http://www.photonstorm.com
 * @author Richard Davey / Photon Storm
*/

package org.flixel.plugin.photonstorm.API 
{
	import flash.display.DisplayObject;
	import flash.display.Loader;
	import flash.errors.IOError;
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.net.URLRequest;
	import flash.system.Security;
	
	import org.flixel.*;
	
	/**
	 *	Allows for easy access to the Kongregate API
	 * 
	 *	Todo: Add in the functions for Chat Integration - you can still use them via the FlxKongregate.api object.
	 */
	public class FlxKongregate 
	{
		/**
		 * The Kongregate API object. You can make calls directly to this once the API has connected.
		 */
		public static var api:*;
		
		/**
		 * true if the API has loaded otherwise false. Loaded is not the same thing as connected, it just means it's ready for the connection.
		 */
		public static var hasLoaded:Boolean = false;
		
		/**
		 * Is the game running locally in Shadow API mode (true) or from Kongregates servers (false)
		 */
		public static var isLocal:Boolean = false;
		
		private static var shadowAPI:String = "http://www.kongregate.com/flash/API_AS3_Local.swf";
		private static var apiLoader:Loader;
		private static var loadCallback:Function;
		
		public function FlxKongregate() 
		{
		}
		
		/**
		 * Loads the Kongregate API and if successful connects to the service.
		 * Note that your game must have access to Stage by this point.
		 * 
		 * @param	callback	This function is called if the API loads successfully. Do not call any API function until this has happened.
		 */
		public static function init(callback:Function):void
		{
			try
			{
				var parameters:Object = FlxG.stage.loaderInfo.parameters;
			}
			catch (e:Error)
			{
				throw new Error("FlxKongregate: No access to FlxG.stage - only call this once your game has access to the display list");
				return;
			}
			
			var apiPath:String;
			
			if (parameters.kongregate_api_path)
			{
				Security.allowDomain(parameters.kongregate_api_path);
				apiPath = parameters.kongregate_api_path;
			}
			else
			{
				Security.allowDomain(shadowAPI);
				apiPath = shadowAPI;
				isLocal = true;
			}
			
			loadCallback = callback;
			
			apiLoader = new Loader();
			apiLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, apiLoadComplete, false, 0, true);
			apiLoader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, apiLoadError, false, 0, true);
			apiLoader.load(new URLRequest(apiPath));
			
			FlxG.stage.addChild(apiLoader);
		}
		
		/**
		 * Remove the API from memory (when possible) and removes it from the display list also
		 */
		public static function disconnect():void
		{
			api = null;
			
			hasLoaded = false;
			
			FlxG.stage.removeChild(apiLoader);
		}
		
		private static function apiLoadComplete(event:Event):void
		{
			api = event.target.content;
			
			hasLoaded = true;

			Security.allowDomain(api.loaderInfo.url);

			if (loadCallback is Function)
			{
				loadCallback.call();
			}
			
		}
		
		private static function apiLoadError(error:IOError):void
		{
			trace("Error loading Kongregate API", error);
		}
		
		/**
		 * Use the addLoadListener function to register an event listener which will be triggered when content of the specified type is loaded by the user.
		 * These MUST be set-up *before* you call FlxKongregate.connect()
		 * See: http://www.kongregate.com/developer_center/docs/shared-content-api
		 * 
		 * @param	contentType		Type of content to listen for
		 * @param	callback		Function to call when content load request has been made
		 */
		public static function addLoadListener(contentType:String, callback:Function):void
		{
			api.sharedContent.addLoadListener(contentType, callback);
		}
		
		/**
		 * Register an event listener with the API. Useful for capturing guest to user login requests for example.
		 * See: http://www.kongregate.com/developer_center/docs/handling-guests
		 * 
		 * @param	contentType		The event to listen for (i.e. "login")
		 * @param	callback		Funcation to call when this event is received
		 */
		public static function addEventListener(contentType:String, callback:Function):void
		{
			api.services.addEventListener(contentType, callback);
		}
		
		/**
		 * Connect to the Kongregate API. This should be called only after the init callback reports a succesful load of the API
		 */
		public static function connect():void
		{
			if (hasLoaded)
			{
				api.services.connect();
			}
		}
		
		/**
		 * The isGuest function can be called to determine if the player is currently signed into Kongregate or not
		 */
		public static function get isGuest():Boolean
		{
			return api.services.isGuest();
		}
		
		/**
		 * You can use the getUsername() function to retrieve the username of the current player. It will begin with Guest if the user is not signed in.
		 */
		public static function get getUserName():String
		{
			return api.services.getUsername();
		}
		
		/**
		 * You can use the getUserId() function to retrieve the unique user id of the current player. It will return 0 if the user is not signed in.
		 */
		public static function get getUserId():Number
		{
			try
			{
				return api.services.getUserId();
			}
			catch (e:Error)
			{
				return 0;
			}
			
			return 0;
		}
		
		/**
		 * If you are using the Authentication API you can use the getGameAuthToken function to get the player's game authentication token.
		 */
		public static function get getGameAuthToken():String
		{
			return api.services.getGameAuthToken();
		}
		
		/**
		 * If the player is a guest, and you want to display the sign-in/registration UI to them you can use the showSignInBox function.
		 */
		public static function showSignInBox():void
		{
			if (api.services.isGuest())
			{
				api.services.showSignInBox();
			}
		}
		
		/**
		 * This call works the same way as showSigninBox, but it focuses the registration form rather than the sign-in form.
		 */
		public static function showRegistrationBox():void
		{
			if (api.services.isGuest())
			{
				api.services.showRegistrationBox();
			}
		}
		
		/**
		 * If a player is logged-in and you want to allow them to post a shout on their profile page, you may bring up the shout box, optionally populated with some initial content.
		 * 
		 * @param	message		The optional initial content
		 */
		public static function showShoutBox(message:String = ""):void
		{
			if (api.services.isGuest() == false)
			{
				api.services.showShoutBox(message);
			}
		}
		
		/**
		 * If you need to resize your game's enclosing container, you may do so with resizeGame call. The enclosing iframe will resize around your game.
		 * Games may not be resized smaller than their initial dimensions. This call requires special permission from Kongregate to use.
		 * 
		 * @param	width		New width (in pixels) of the container
		 * @param	height		New height (in pixels) of the container
		 */
		public static function resizeGame(width:int, height:int):void
		{
			api.services.resizeGame(width, height);
		}
		
		/**
		 * Submit a statistic to the Kongregate server. Make sure you have defined the stat before calling this.
		 * See the Kongregate API documentation for details.
		 * 
		 * @param	name		The name of the statistic
		 * @param	value		The value to submit (will be converted to an integer server-side)
		 */
		public static function submitStats(name:String, value:Number):void
		{
			api.stats.submit(name, value);
		}
		
		/**
		 * Bring up the "purchase items" dialog box by using the purchaseItems method on the microtransaction services object.
		 * Your game must be in the Kongregate Microtransactions beta to use this function.
		 * See: http://www.kongregate.com/developer_center/docs/microtransaction-client-api
		 * 
		 * @param	items		The array of item identifier strings or item/metadata objects.
		 * @param	callback	The callback function
		 */
		public static function purchaseItem(items:Array, callback:Function):void
		{
			api.mtx.purchaseItems(items, callback);
		}
		
		/**
		 * Request the inventory of any user.
		 * Your game must be in the Kongregate Microtransactions beta to use this function.
		 * See: http://www.kongregate.com/developer_center/docs/microtransaction-client-api
		 * 
		 * @param	username	The username to request inventory for, or null for the current player
		 * @param	callback	The callback function
		 */
		public static function requestUserItemList(username:String, callback:Function):void
		{
			api.mtx.requestUserItemList(username, callback);
		}
		
		/**
		 * Display the Kred purchasing Dialog.
		 * Your game must be in the Kongregate Microtransactions beta to use this function.
		 * See: http://www.kongregate.com/developer_center/docs/microtransaction-client-api
		 * 
		 * @param	purchaseMethod	 The purchase method to display. Should be "offers" or "mobile"
		 */
		public static function showKredPurchaseDialog(purchaseMethod:String):void
		{
			api.mtx.showKredPurchaseDialog(purchaseMethod);
		}
		
		/**
		 * The browse function causes a list of shared content to appear in the user's browser.
		 * This will allow them to view, rate, or load shared content for your game.
		 * See: http://www.kongregate.com/developer_center/docs/shared-content-api
		 * 
		 * @param	contentType		Type of content to browse
		 * @param	sortOrder		Optional constant specifying how to sort content (see API docs)
		 * @param	label			Optional, only browse content saved with the specified label
		 */
		public static function browseSharedContent(contentType:String, sortOrder:String=null, label:String=null):void
		{
			api.sharedContent.browse(contentType, sortOrder, label);
		}
		
		/**
		 * Use the save function to submit shared content on the Kongregate back-end.
		 * See: http://www.kongregate.com/developer_center/docs/shared-content-api
		 * 
		 * @param	type		Type of content the user wishes to save, 12 characters max.
		 * @param	content		Value of content to be saved. We strongly recommend keeping these values under 100K.
		 * @param	callback	Function to call when save has finished.
		 * @param	thumb		Optional but highly recommended! Send us a DisplayObject that we will snapshotted and used as a thumbnail for the content.
		 * @param	label		Optional, label for sub-classing the shared content.
		 */
		public static function saveSharedContent(type:String, content:String, callback:Function, thumb:DisplayObject = null, label:String = null):void
		{
			api.sharedContent.save(type, content, callback, thumb, label);
		}
		
		/**
		 * Export a DisplayObject to be converted to a user avatar. It is highly recommended that avatars be at least 40 x 40px.
		 * See: http://www.kongregate.com/developer_center/docs/avatar-api
		 * 
		 * @param	avatar		Can be null, but highly recommended that you send yourself. If null, we will snapshot the stage.
		 * @param	callback	Function to call when content load request has been made
		 */
		public static function submitAvatar(avatar:DisplayObject, callback:Function):void
		{
			api.images.submitAvatar(avatar, callback);
		}
	}

}