/*	VERSION:	1.4

1.4			Changed wait for "animation" to first check whether the sprite "isAnimating" as a sanity-check for deciding whether to wait for it in the first place
1.3: 		Changed "animDone" event is handled using a local object instead attaching thisCommand_obj to the listener
1.2:		Added "promise" wait-mode
1.1:		Added to "wait" command:  'movieclip'  and  'script'

AVAILABLE DATA
	thisCommand_obj
		data						This command's data
		run()						This function
		nextEvent()			Function that triggers the next sibling command
		storeTimeout()	Function that stores this command's timeout ID   (used to stop the script)
			var waitId = setTimeout( parentScript.nextEvent, thisCommand_obj.data.value*1000 );
			thisCommand_obj.storeTimeout( waitId );
*/
#include "functions/once.as"
#include "gameFunctions/getPathValue.as"
#include "gameFunctions/nestedEval.as"
	// evalPath

// run()
define_wait = function( thisCommand_obj )
{
	
	
	var prom = VOW.make();										// create a promise
	var nextEvent = once( prom.keep );							// create a function called "nextEvent" that can only run once and calls the "keep" function
	// so calling nextEvent() will call prom.keep() exactly one time
	
	
	thisCommand_obj.getTimeout = function(){
		return this.scriptBase.timeoutID;
	}
	
	// "_this" is the rpgSprite that is running this code.  "_this._parent" is the movieClip that contains this sprite.  It will either be _global.SPRITES or _global.COMMON
	var thisSpriteContainer = (_this._parent.is_common) ? COMMON : SPRITES;
	var waitMode = thisCommand_obj.data.mode;
	if(TRACE_SCRIPT)
		trace("wait for: "+waitMode);
	
	if(waitMode=="time")
	{
		var waitId = setTimeout( nextEvent, thisCommand_obj.data.value*1000 );
		thisCommand_obj.storeTimeout( waitId );
	}// if:  time
	
	
	
	if(waitMode=="movement")
	{
		var spriteName = thisCommand_obj.data.value;
		spriteName = nestedEval( spriteName, "RAM", "_this" );
		// make a list of sprites to wait for
		thisCommand_obj.spritesLeft = [];
		if(spriteName == "ALL")
		{// if:  wait for all sprites to finish moving
			for(var nam in SPRITES)
			{// for:  every sprite
				var sprite = SPRITES[nam];		// only wait for sprites moving in the SPRITES layer. (even if this script is within COMMON)
				if(sprite.lastMove)
				{// if:  this sprite is moving
					var waitObject = {
						sprite:sprite,
						thisCommand_obj:thisCommand_obj
					}// waitObject
					thisCommand_obj.spritesLeft.push( waitObject );
				}// if:  this sprite is moving
			}// for:  every sprite
		}// if:  wait for all sprites to finish moving
		else
		{// if:  wait for a specific sprite
			if(spriteName == "this"){
				spriteName = _this._name;		// read the instance name of the rpgSprite that contains this script
				var thisSpriteContainer = (_this._parent.is_common) ? COMMON : SPRITES;		// "this" is the only case where a COMMON sprites can wait for its own movement
				var sprite = thisSpriteContainer[spriteName];
			}else{
				var sprite = SPRITES[spriteName];		// only wait for sprites moving in the SPRITES layer. (even if this script is within COMMON)
			}
			if(sprite.lastMove)
			{// if:  this sprite is moving
				var waitObject = {
					sprite:sprite,
					thisCommand_obj:thisCommand_obj
				}// waitObject
				thisCommand_obj.spritesLeft.push( waitObject );
			}// if:  this sprite is moving
		}// if:  wait for a specific sprite
		
		
		// wait for each sprite in the list
		if(thisCommand_obj.spritesLeft.length > 0)
		{// if:  there are sprites to wait for
			for(var nam in thisCommand_obj.spritesLeft)
			{// for:  each sprite in the list
				var waitObject = thisCommand_obj.spritesLeft[nam];
				var sprite = waitObject.sprite;
				react.once().to( "onMotionFinished" ).from( sprite.lastMove ).then = function(){
					// this.sprite.lastMove.removeListener( this );
					thisCommand_obj.spritesLeft.pop();
					if(thisCommand_obj.spritesLeft.length<=0)		// when there are no more sprites left to wait for
						setTimeout( nextEvent, 34 );
				}// onMotionFinished();
			}// for:  each sprite in the list
		}// if:  there are sprites to wait for
		else
		{// if:  there's nothing to wait for
			nextEvent();
		}// if:  there's nothing to wait for
	}// if:  movement
	
	
	
	if(waitMode=="animation")
	{
		var waitForAnimDone = function(){
			var react_to_animDone = react.once().to("animDone").from( animSpriteContainer[spriteName].image );
			var react_to_unload = react.once().to("unload").from( animSpriteContainer[spriteName].image );
			
			var animDone = function(){
				react_to_animDone.disable();
				react_to_unload.disable();
				if( _this._name !== undefined)		nextEvent();
			}// animDone / unload()
			
			react_to_animDone.then = animDone;
			react_to_unload.then = animDone;
		}// waitForAnimDone()
		
		
		var spriteName = thisCommand_obj.data.value;
		spriteName = nestedEval( spriteName, "RAM", "_this" );
		var animSpriteContainer;
		var sprite;
		if(spriteName === "this"){
			spriteName = _this._name;		// read the instance name of the rpgSprite that contains this script
			animSpriteContainer = (_this._parent.is_common) ? COMMON : SPRITES;		// "this" is the only case where a COMMON sprite can wait for its own animation
			sprite = animSpriteContainer[spriteName];
		}else{
			animSpriteContainer = SPRITES;
			sprite = SPRITES[spriteName];		// only wait for sprites animating in the SPRITES layer. (even if this script is within COMMON)
		}
		// if:  not already on the last frame
		var frame = animSpriteContainer[spriteName].image.getParam("frame");
		var frames = animSpriteContainer[spriteName].image.getParam("frames");
		// if(frame<frames  &&  animSpriteContainer[spriteName].image.getParam("isAnimating") )
		if( animSpriteContainer[spriteName].image.getParam("isAnimating") )
			waitForAnimDone();
		else
			nextEvent();
	}// if:  animation
	
	
	
	if(waitMode=="movieclip")
	{
		// resolve the movieclip path
		var path = thisCommand_obj.data.value;
		path = nestedEval( path, "RAM", "SPRITES."+_this._name );
		// path = nestedEval( path, "RAM", "_this" );
		if( path=="this" )
			path = "SPRITES."+_this._name;
		if( path.substr(0,5) == "this." ){
			var theRest = path.substr(5);
			path = "SPRITES."+_this._name +"." +theRest;
		}
		var newClip = getPathValue( path,  ("SPRITES." +_this._name)  );
		var isMovieclip = (typeof(newClip) == "movieclip");
		
		if(isMovieclip)
		{// if:  is a movieClip
			// inject wait code into the movieclip
			newClip.detectLastFrame = {
				levelId:ROOT.game_mc.uid,
				parent:newClip,
				loop:function( thisObj )		// repeatedly check for last frame
				{
					var sameLevel = (thisObj.levelId === ROOT.game_mc.uid);
					if(	thisObj.parent._currentframe === thisObj.parent._totalframes
					||	thisObj.parent._currentframe === undefined
					||	sameLevel === false){
						// stop checking for last frame
						if(thisObj.intervalId != null)		clearInterval( thisObj.intervalId );
						// remove this code from the target movieClip
						newClip.detectLastFrame = null;
						delete newClip.detectLastFrame;
						// start next event
						if(sameLevel)
							nextEvent();
						else
							prom.doBreak();
					}// if:  last frame
				},// loop()
				intervalId:null,
				start:function(){		// begin loop
					if(this.intervalId!=null)
						clearInterval( this.intervalId );
					this.intervalId = setInterval( this.loop, 34, this );
					this.loop( this );
				}// start()
			}// detectLastFrame obj
			newClip.detectLastFrame.start();		// start checking for the last frame
		}// if:  is a movieClip
		else
		{// if:  not a movieClip
			nextEvent();
		}// if:  not a movieClip
	}// if:  movieclip
	
	
	
	if(waitMode=="fadeMusic")
	{
		// ?  Not sure why this is needed
		thisCommand_obj.storeTimeout( 999 );
		
		if( MUSIC.isFading ){
			// if:  music is fading
			react.once().to( "onFadeComplete" ).from( MUSIC ).then = nextEvent;
		}else{
			// if:  there's no fade to wait for
			nextEvent();			// resume immediately
		}
	}// if:  fadeMusic
	
	
	
	if(waitMode=="sound")
	{
		var soundObj = ROOT.soundLoop[thisCommand_obj.data.value].sound;
		// continue when specified sound ends
		if( soundObj ){
			// sound exists  =>  wait for sound
			react.once().to("onSoundComplete").from( soundObj ).then = nextEvent;
		}else{
			// no sound to wait for  =>  resume
			nextEvent();
		}
	}// if:  sound
	
	
	
	if(waitMode=="script")
	{
		if( TRACE_SCRIPT )		trace("wait.as  waitMode: script");
		var spriteName = thisCommand_obj.data.value;
		if(spriteName=="this")		spriteName = _this._name;
		// resolve [] variables
		spriteName = nestedEval( spriteName, "RAM", "_this" );
		// get a direct refernce to the specified sprite
		var thisSpriteContainer = (_this._parent.is_common) ? COMMON : SPRITES;
		var sprite_mc = getPathValue( spriteName, thisSpriteContainer );
		var scriptName = nestedEval( thisCommand_obj.data.value2, "RAM", "_this" );
		if( TRACE_SCRIPT )		trace("  sprite_mc: "+sprite_mc);
		if( TRACE_SCRIPT )		trace("  scriptName: "+scriptName);
		if(sprite_mc && scriptName)
		{// if:  sprite exists
			
			var script_prom = sprite_mc.waitForScript[ scriptName ];
			if( TRACE_SCRIPT )		trace("  script_prom getStatus: "+script_prom.getStatus() );
			if( script_prom )
			{// if:  script has started  (even if its start is being delayed)
				if( TRACE_SCRIPT )		trace("  " + scriptName + " has been invoked,  waiting for script to finish");
				if( script_prom.getStatus() !== "pending" ){
					// script is already done,  so there's nothing to wait for
					nextEvent();
				}else{
					// wait for the specified script until it finishes / aborts
					script_prom.then( nextEvent, nextEvent );
				}
			}// if:  script exists
			else
			{
				if( TRACE_SCRIPT )		trace("  target script is not running,  ignoring,  resuming script");
				nextEvent();
			}

		}// if:  sprite exists
		else
		{// if:  no such sprite
			if( TRACE_SCRIPT )		trace("  target sprite doesn't exist,  ignoring,  resuming script");
			nextEvent();
		}// if:  no such sprite
		
		//nextEvent();
	}// if:  script
	
	
	
	if(waitMode=="promise")
	{
		// resolve the specified path to the promise variable
		var promiseObjPath = thisCommand_obj.data.value;
		var target_str = nestedEval( promiseObjPath, "RAM", "_this" );
		var divideAt = target_str.lastIndexOf(".");
		var varContainer = null;
		if(divideAt === -1)
		{// if:  not a variable path  (single variable)
			// assume this single variable exists within RAM
			varContainer = defaultContainer;
		}// if:  not a variable path  (single variable)
		else
		{// if:  is a variable path
			// determine the intended container
			var varContainerName = target_str.substr(0,divideAt);
			varContainer = evalPath( varContainerName, "RAM", "_this" );
		}// if:  is a variable path
		var varName = target_str.substr(divideAt+1);
		
		
		var promiseObj = varContainer[varName];
		
		
		// wait for promise, then trigger nextEvent()
		if( promiseObj.getStatus() === "kept"){
			nextEvent();
		}else if( promiseObj.is_promise ){
			promiseObj.then( nextEvent );
		}else{
			nextEvent();
		}
	}// if:  promise
	
	
	// wait for promise
	return prom;
		
	
}// define_wait()