package com.panache.comm
{	import com.panache.debug.MediaServicesAdDebug;

import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.SecurityErrorEvent;
import flash.events.StatusEvent;
import flash.events.TimerEvent;
import flash.net.LocalConnection;
import flash.utils.Timer;
	
	
	
	public class PanacheToolkitAssetLocalConnectionCommunicationServices extends EventDispatcher
	{		
		
		// CONSTANTS
		/**
		 * The PanacheCommunicationServices.CONNECTION_SUCCESS constant defines the value of the 
		 * <code>type</code> property of the event object 
		 * for a <code>connectionSuccess</code> event.
		 * 
		 * @eventType connectionSuccess
		 * */
		public static const CONNECTION_SUCCESS:String 		= "connectionSuccess";
		
		private static const VERSION_MAJOR:uint				= 5;
		private static const VERSION_MINOR:uint				= 0;
		private static const VERSION_RELEASE:uint			= 1;
		private static const VERSION_STRING:String			= VERSION_MAJOR + "." + VERSION_MINOR + "." + VERSION_RELEASE + " LITE";
		private static const DEBUG_SOURCE:String			= "PanacheToolkitAssetCommunicationServices";	
		
		
		private var mReceivingConnection:LocalConnection;	// connection for receiving
		private var mSendingConnection:LocalConnection;		// connection for sending
		private var mReceivingConnecitonName:String;		// id for the receiving connection
		private var mSendingConnectionName:String;			// id for the sending connection
		private var mClient:Object;							// the client for the receiving connection
		private var mHandShake:Boolean = false;				// flag that determines whether a handshake between the local connections has taken place
		private var mHsTimer:Timer;							// timer that attempts to send a message to another swf until successful or a timeout		
		private var mAllowTraces:Boolean;					// a flag to disable/enable traces
		private var mSourceAdId:String;						//keep track of the adId that instantiated us
//////////////////////////////////////////////////////////////////////////////////////////
// -------------------------------- Public Methods ---------------------------------------	

		/**
		 * Constructor.
		 * @param client the client property to be used for the receiving local connection
		 * @param allowTraces enables or disables the traces during notification passing
		 * */
		public function PanacheToolkitAssetLocalConnectionCommunicationServices(client:Object, allowTraces:Boolean = false, sourceAdId:String = "")
		{			
			//trace("PanacheToolkitAssetCommunicationServices version: " + VERSION_STRING);
			MediaServicesAdDebug.reportVersion(DEBUG_SOURCE, VERSION_STRING);
			mClient = client;
			mAllowTraces = allowTraces;
			mSourceAdId = sourceAdId;
		}
		
		/**
		 * Creates a local connection to be used for sending data to another swf.
		 * This function ensures the connection was made by sending a message to another swf every 200ms until
		 * it gets a success response or times out after 15 seconds.
		 * 
		 * @param connectionID a unique id to be used when creating a local connection
		 * */
		public function setUpConnectionForSending(connectionID:String):void
		{
			mSendingConnection = new LocalConnection();
     		mSendingConnection.addEventListener(StatusEvent.STATUS, onStatus);
     		mSendingConnection.addEventListener(SecurityErrorEvent.SECURITY_ERROR, handleSecurityError);
 			mSendingConnection.allowDomain("*");
			mSendingConnectionName = connectionID; 

			// create a handshake timer
			mHsTimer = new Timer(200, 75);
			mHsTimer.addEventListener(TimerEvent.TIMER, handleHandshakeTimer);
			mHsTimer.addEventListener(TimerEvent.TIMER_COMPLETE, handleHandshakeTimerComplete);
			mHsTimer.start();
			
			MediaServicesAdDebug.reportTrace("Start a handshake timer. Duration before timeout is 15 seconds", DEBUG_SOURCE, "setUpConnectionForSending");
		}
		
		/**
		 * Creates a local connection to be used for receiving data to another swf.
		 * 
		 * @param connectionID a unique id to be used when creating a local connection
		 * */
		public function setUpConnectionForReceiving(connectionID:String):void
		{
			mReceivingConnection = new LocalConnection();
			mReceivingConnecitonName = connectionID;
			openConnectionForReceiving();
		}
		

		
		/**
		 * Closes the local connections.
		 * 
		 * */
		public function closeConnections():void
		{
			try 
			{
				MediaServicesAdDebug.reportTrace("Panache communications have been closed. Ad unit and asset will no longer be able to communicate.", 
						DEBUG_SOURCE, "closeConnections");
				// if the ad unit was terminated while the local connection was attempting to be established, stop the timer
				
				if(mHsTimer != null)
				{
					mHsTimer.stop();
					mHsTimer = null;
				}
				
				// close the local connection
				if( mReceivingConnecitonName != null )
			    {
					mReceivingConnection.close();
			    }
            } 
            catch (error:ArgumentError) 
            {
                MediaServicesAdDebug.reportTrace("WARNING:  Unable to close the connection because it is not open", DEBUG_SOURCE, "closeConnections");
            }
		}
		
		/**
		 * Sends a notification to a connected swf.
		 * The connected swf must have a function named "handleNotify" that receives an object as a parameter
		 * 
		 * @example The following code shows how a receiving swf can get the notification.
		 * <pre>
		 * public function handleNotify(aPn:Object):void
		 * {
			    switch(aPn.notificationName)
			    {
				    case PanacheToolkitAssetCommunicationServicesNotification.AD_UNIT_OPEN_RESIDUAL_STATE:
					    break;
				    case PanacheToolkitAssetCommunicationServicesNotification.AD_UNIT_OPEN_INIT_STATE:
					    break;
				    case PanacheToolkitAssetCommunicationServicesNotification.AD_UNIT_OPEN_MAX_STATE:
					    break;				
				    .
				    .
				    .
				}
			}
		 * </pre>
		 * 
		 * @param notificationName The a name of the notification to send
		 * @param data An object containing any necessary data to pass to a connected swf
		 * */
		public function notify(notificationName:String, data:Object = null, targetAdID:String = "*"):void
		{
			//don't trace handshake except at "detail" debug level
			var debugLevel:String = MediaServicesAdDebug.DEBUG_LEVEL_DETAIL;
			if(notificationName != "HandShake" )
				debugLevel = MediaServicesAdDebug.DEBUG_LEVEL_ON;
				
			var msg:String = "Send to: " + mSendingConnectionName;
			msg += " notification name=" + notificationName;
			msg += " target ad id name: " + targetAdID;
			MediaServicesAdDebug.reportTrace(msg, DEBUG_SOURCE, "notify");
			
			try
			{			
				var pn:PanacheToolkitAssetCommunicationServicesNotification = new PanacheToolkitAssetCommunicationServicesNotification(notificationName, data, targetAdID);
				mSendingConnection.send(mSendingConnectionName, "handleNotify", pn);
			}
			catch (ex:Error)
			{
				MediaServicesAdDebug.reportErrorTrace("Unable to send notify=" + notificationName, ex, DEBUG_SOURCE, "notify");	
			}
		}
		

		

		
// ------------------------------ END Public Methods --------------------------------------
///////////////////////////////////////////////////////////////////////////////////////////

		// openConnectionForReceiving -- sets up the connection for receiving
		private function openConnectionForReceiving():void
		{
			var success:Boolean = true;
			
			try 
			{
				mReceivingConnection.allowDomain("*");
         		mReceivingConnection.connect(mReceivingConnecitonName);
         		mReceivingConnection.client = mClient;
         		
            } 
            catch (error:ArgumentError) 
            {
            	success = false;
                var msg:String = "Can't connect...the connection name is already being used by another SWF";
                MediaServicesAdDebug.reportErrorTrace(msg, error, DEBUG_SOURCE, "openConnectionForReceiving");
            }
   
		}
		
		// onStatus -- callback of the sending connection. Exectued after a send method was called on a local connection
		private function onStatus(event:StatusEvent):void 
		{
            switch (event.level) 
            {
                case "status":
                	if(!mHandShake)
                	{
                		mHandShake = true;
                		
                		// stop the timer
						mHsTimer.stop();
						mHsTimer = null;
						
                		dispatchEvent(new Event(CONNECTION_SUCCESS));
                		
      		     		//mConnection02.removeEventListener(StatusEvent.STATUS, onStatus);
                		// quit out of the function to avoid the trace when the handshake timer succeeded.
						return;
                	}
                	else
                	{
	                   		MediaServicesAdDebug.reportTrace("send handshake", DEBUG_SOURCE, "onStatus", MediaServicesAdDebug.DEBUG_LEVEL_DETAIL);
                	}
	                MediaServicesAdDebug.reportTrace("LocalConnection.send() succeeded", DEBUG_SOURCE, "onStatus");
                    break;
                case "error":
                	// suppress traces for the flooding of the handshake calls
                	if(mHandShake)
	                    MediaServicesAdDebug.reportErrorTrace("connection " + mSendingConnectionName + ". LocalConnection.send() failed",
	                    		null, DEBUG_SOURCE, "onStatus");
                    break;
            }
        }
		
		// handleSecurityError -- exectued if there is a security error
		private function handleSecurityError(event:SecurityErrorEvent):void 
		{
			MediaServicesAdDebug.reportErrorTrace("Local Connection Security Error: " + event.text, null, DEBUG_SOURCE, "handleSecurityError");
		}
		
		// handleHandshakeTimer -- callback of handshake timer. sends a purposely undocumented handshake notification to a connected swf
		private function handleHandshakeTimer(event:TimerEvent):void
		{
			notify("HandShake", "", mSourceAdId);
		}		
		
		// handleHandshakeTimerComplete -- callback of handshake timer end. Traces whether a connection was made successfully or not.
		private function handleHandshakeTimerComplete(event:TimerEvent):void
		{
			MediaServicesAdDebug.reportTrace("Handshake timer expired. Success: " + mHandShake, DEBUG_SOURCE, "handleHandshakeTimerComplete");
		}	
		
		public function get SendingConnection():*
		{
			return mSendingConnection;
		}
		
		public function get ReceivingConnection():*
		{
			return mReceivingConnection;
		}
		
		//we could just not include this, but I have them in here for readability/future expansion
		override public function addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void
		{
			super.addEventListener(type,listener,useCapture,priority,useWeakReference);
		}
		
		//we could just not include this, but I have them in here for readability/future expansion
		override public function removeEventListener(type:String, listener:Function, useCapture:Boolean = false):void
		{
			super.removeEventListener(type,listener,useCapture);
		}
		
	}
}