/*	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/nextDepth.as"
#include "gameFunctions/copyObject.as"
#include "gameFunctions/getImpliedValue.as"
#include "gameFunctions/callUnload.as"
#include "gameFunctions/makeStringObject.as"
	// nestedEval
	// evalPath
	// getImpliedValue
	// resolveContainer
	
// run()
define_swf = function( thisCommand_obj, skipSwfloader ){
	var prom = VOW.make();
	var nextEvent = once( prom.keep );		// calling nextEvent() calls prom.keep()
	
	
	function attemptStart( newClip ){
		if(!newClip)	return;
		// attempt to run start()
		var tries = 30;
		var startInterval;
		var tryStart = function(){
			// detect if any parent movieclips have been deleted  (so this code doesn't run endlessly)
			if(_this instanceof MovieClip == false)			clearInterval(startInterval);
			// detect start() within the placed MovieClip
			if(newClip.start === undefined){
				tries--;
				if(tries<=0)	clearInterval(startInterval);
			}else{
				newClip.start();
				clearInterval(startInterval);
			}
		}// tryStart()
		startInterval = setInterval(function(){
			tryStart();
		}, 1);
		tryStart();
	}// attemptStart()
	
	
	//trace("define swf command:  name: "+thisCommand_obj.data.linkage);
	if(thisCommand_obj.data.linkage)
	{// if:  linkage specified
		var target;
		
		// make functions available to inner functions
		thisCommand_obj.copyObject = copyObject;
		thisCommand_obj.makeStringObject = makeStringObject;
		thisCommand_obj.nestedEval = nestedEval;
		thisCommand_obj.evalPath = evalPath;
		thisCommand_obj.getImpliedValue = getImpliedValue;
		thisCommand_obj.resolveContainer = resolveContainer;
		// determine where this clip is being placed  (parse variables if [] are used)
		var target_str = nestedEval( thisCommand_obj.data.target, "RAM", "_this");
		target = evalPath( target_str, "RAM", "_this");
		
		
		// generate instance name if none is supplied		(read variables if [] are used)
		var newName = nestedEval( thisCommand_obj.data.name, "RAM", "_this");
		var nameIndex = 0;
		if(newName==""  ||  newName==undefined)
		{// if:  no instance name is supplied
			do{
				var newName = "swf_"+nameIndex;
				nameIndex++;
			}while(target[newName]);
		}// if:  no instance name is supplied
		
		if(TRACE_SCRIPT)
			trace(">>  Place swf:  "+thisCommand_obj.data.linkage+"   named: "+newName+"   waitForEnd: "+thisCommand_obj.data.waitForEnd);
		
		
		// figure out depth
		var newDepth = (thisCommand_obj.data.depth==-1) ? nextDepth(target) : nestedEval( thisCommand_obj.data.depth, "RAM", "_this");
		
		// store this SWF command for save-game loading
		var storedObj = {};
		copyObject( thisCommand_obj.data, storedObj );
		storedObj.name = newName;
		storedObj.depth = newDepth;
		if(!skipSwfloader){
			ROOT.swfLoader.add( storedObj, _this );		// accesses ROOT.swfLoader  (not to be confused with the local "swfLoader" used below)
		}
		
		
		
		// create local loader object
		var swfLoader = new MovieClipLoader();			// This is NOT the same thing as ROOT.swfLoader
		swfLoader.root = ROOT;
		swfLoader.commandData = thisCommand_obj.data.data;
		swfLoader.nextEvent = nextEvent;
		swfLoader.waitForEnd = thisCommand_obj.data.waitForEnd;
		swfLoader.levelId = "common";
		if( isInsideLevel( target ) )
			swfLoader.levelId = ROOT.game_mc.uid;
		
		
		
		// remove existing clip with same name
		callUnload( target[newName] );
		target[newName].removeMovieClip();
		// remove existing clip with same depth
		var replaceClip = target.getInstanceAtDepth(newDepth);
		callUnload( replaceClip );
		replaceClip.removeMovieClip();
		
		
		
		// (parse variables if [] are used)
		var linkage = thisCommand_obj.data.linkage;
		linkage = nestedEval( linkage, "RAM", "_this");
		
		
		
		// movieclip linkage
		var externalFile = false;
		target.attachMovie( linkage, newName, newDepth);
		if(	target[newName] == target  ||
				target[newName] == undefined)
		{// if:  no movieClip loaded
			// bitmap linkage
			target.createEmptyMovieClip(newName, newDepth);
			var new_pic = flash.display.BitmapData.loadBitmap( linkage );
			target[newName].attachBitmap(new_pic, 0);
			if(	target[newName]._width == undefined  ||
					target[newName]._width == 0)
			{// if:  no bitmap loaded
				// external file
				var externalFile = true;
			}// if:  no bitmap loaded
			else
			{// if:  internal bitmap loaded
				thisCommand_obj.data.waitForEnd = false;
			}// if:  internal bitmap loaded
		}// if:  no movieClip loaded
		
		
		
		
		
		swfLoader.passData = function( newClip, commandData )
		{
			//#include "gameFunctions/makeStringObject.as"
			// grant access to the sprite whose script is placing the SWF
			newClip.parentSprite = _this;
			// pass the settings to the loaded SWF
			for(var nam in commandData){// for each variable
				var newValue = thisCommand_obj.nestedEval( commandData[nam], "RAM", "_this" );
				newValue = thisCommand_obj.makeStringObject( newValue, "RAM", "_this" );
				newClip[nam] = getImpliedValue( newValue );		// "false" => false
				// newClip[nam] = newValue;		// textboxes should be able to display "false"
			}// for each variable in commandData
			
			// allow loaded SWFs to manually resume the script
			newClip.nextEvent = nextEvent;
			
			newClip.onClose = function(){
				//ROOT.swfLoader.remove( thisCommand_obj.data );
				ROOT.swfLoader.remove( storedObj );
			}// onClose()
		}// passData()
		
		
		swfLoader.detectLastFrame = function( newClip, nextEvent )
		{
			var loopTimes = 0;
			var detectLastFrame = {
				parent:newClip,
				nextEvent:nextEvent,
				swfData:thisCommand_obj.data,
				loop:function( thisObj )		// repeatedly check for last frame
				{
					loopTimes++;
					
					// if:  swf is still being placed,  skip this particular check for last-frame
					if(!thisObj && loopTimes==1)		return;
					
					var isDone = false;
					if(	thisObj.parent._currentframe === undefined )			isDone = true;		// movieClip was removed by something else
					if(	thisObj.parent._currentframe == thisObj.parent._totalframes )			isDone = true;
					if(	loopTimes > 1  &&  thisObj.parent._currentframe == undefined )		isDone = true;
					
					// if:  swf still hasn't been placed after multiple frames,  then give up checking for last frame
					if(!thisObj > loopTimes)		isDone = true;
					
					if(	isDone )
					{// if:  last frame
						ROOT.swfLoader.remove( thisObj.swfData );
						// stop checking for last frame
						clearInterval( thisObj.intervalId );
						// restore root
						_global.ROOT = swfLoader.root;
						// start next event
						var sameLevel = (swfLoader.levelId === ROOT.game_mc.uid);
						// All SWF's placed inside of COMMON are in the same level, because level loading won't remove them
						if( swfLoader.levelId === "common" )		sameLevel = true;
						if(sameLevel){
							thisObj.nextEvent();
						}// if:  sameLevel
					}// 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"  =>  "thisObj" of loop( thisObj )
					this.loop();
				}// start()
			}// detectLastFrame obj
			newClip.detectLastFrame = detectLastFrame;
			newClip.detectLastFrame.start();		// start checking for the last frame
		}// detectLastFrame()
		
		
		
		if(externalFile)
		{// external file is being loaded
			
			// waitForEnd = true:		wait for last frame,  then resume script
			// waitForEnd = false:	wait for clip to exist,  then resume script
			// load error: 					resume script
			/*	
			// waitForEnd = false:	wait for clip to exist,  then resume script
			// if:  not waiting for the last frame,  then instead wait for the movieClip to exist
			if( swfLoader.waitForEnd === false ){
				swfLoader.onLoadComplete = function(){
					nextEvent();
				}// the clip now exists,  but hasn't yet run its frame-1 code
			}// if:  not waiting for the last frame,  then instead wait for the movieClip to exist
			*/
			swfLoader.onLoadInit = function( newClip )
			{
				// 2nd time,  send variables to the loaded clip  (2nd time, in case the SWF didn't notice them the first time)
				swfLoader.passData( newClip, this.commandData );
				// waitForEnd = true:		wait for last frame,  then resume script
				if(swfLoader.waitForEnd){
					swfLoader.detectLastFrame( newClip, this.nextEvent );
				}
				delete swfLoader;
				// announce that the parameters are available
				// ... after waiting a moment
				attemptStart( newClip );
			}// file loaded & is running()
			
			// load error: 					resume script
			swfLoader.onLoadError = function( newClip ){
				if(newClip)		this.unloadClip( newClip );		// remove empty movieClip
				newClip.removeMovieClip();		// make sure it's gone
				delete swfLoader;
				// fail  =>  resume script
				nextEvent();
			}// error()
			
			swfLoader.onLoadComplete = function( newClip, status ){
				// 1st time,  send variables to the loaded clip
				swfLoader.passData( newClip, this.commandData );
				// if not waitForEnd  =>  resume as soon as it finishes loading
				if( swfLoader.waitForEnd === false )		return nextEvent();
				
				// loaded clip immediately removed itself  (check one frame later whether it still exists)
				if( !newClip )					return nextEvent();
				if( status !== 0 )			return nextEvent();
				if( status === 404 )		return nextEvent();
				setTimeout(function(){
					if( newClip._name === undefined )		nextEvent();
				}, 33);
			}// onLoadComplete()
			
			swfLoader.loadClip( linkage, target[newName] );
		}// external file is being loaded
		else
		{// internal file is being loaded
			swfLoader.passData( target[newName], swfLoader.commandData );
			if(swfLoader.waitForEnd)
				swfLoader.detectLastFrame( target[newName], nextEvent );
			delete swfLoader;
			attemptStart( target[newName] );
		}// internal file is being loaded
		
		
		// if:   not already waiting for the last frame
		if(	thisCommand_obj.data.waitForEnd == false){
			// if:  internal file
			if( externalFile === false ){
				// instantly done,  (because the clip instantly exists)
				// nextEvent();
				return VOW.make().keep();
			}// if:  internal file
		}// if:   not already waiting for the last frame
		
		
		// if:   parent doesn't exist,  so placing this movieClip is impossible
		if(target === undefined){
			trace("* SCRIPT MISTAKE:  Failed to put SWF into container:  "+target_str);
			// instantly done  (because the clip cannot exist, and there's nothing else to wait for)
			// nextEvent();
			return VOW.make().keep();
		}// if:   parent doesn't exist,  so placing this movieClip is impossible
	
	
	}// if:  linkage specified












	else












	{// if:  no linkage given
		var target;
		// remove the target swf's command from storage
		if(!preserveSwfloader)
			ROOT.swfLoader.remove( thisCommand_obj.data );
		if(TRACE_SCRIPT)
			trace("removeSwf named: "+thisCommand_obj.data.name+"  from: "+thisCommand_obj.data.target);
		
		var targetName = nestedEval(thisCommand_obj.data.name, "RAM", "_this");
		if(targetName==""  ||  targetName==undefined)
		{// if:  missing variable name
			// ignore this command & continue the script
			// thisCommand_obj.nextEvent();
			return VOW.make().keep();
		}// if:  missing variable name
		else
		{// if:  has variable name
			// if "auto" command has just started, wait a bit before potentially removing this sprite  (via flags)	(this prevents crashing the game)
			var autoDelay = 1;
			var endTime = getTimer();
			var elapsedTime = endTime - startTime;
			if(TRACE_SCRIPT)
				trace("\t elapsedTime: "+elapsedTime);
			if(isNaN(elapsedTime)  ||  elapsedTime>autoDelay)
			{// if:  time has passed since "auto" script started		(prevent game crash)
				// figure out the target container
				var defaultContainer = "OVERLAY";
				target_str = nestedEval(thisCommand_obj.data.target, "RAM", "_this");
				var startAt = target_str.indexOf(".");
				if(startAt==-1)
				{// if:  path has NO objects
					var container = defaultContainer;
					var containerIsGlobal = false;
					for(var nam in _global){
						if(nam == target_str){
							containerIsGlobal = true;
							break;		// stop searching
						}// if:  Path is a global object
					}// for:  each global object
					var theRest = target_str;
					target = (containerIsGlobal) ? eval(theRest) : eval(container+"."+theRest);
					if(target_str=="this")
						target = _this;
				}// if:  path has NO objects
				else
				{// if:  path has objects
					var containerName = target_str.substr(0, startAt);
					var container = nestedEval(containerName, "RAM", "_this");
					var theRest = target_str.substr( startAt+1 );
					target = eval(container+"."+theRest);
				}// if:  path has objects
				
				
				// if it's a sprite, remove it from update list  (so variables don't restore it)
				if(target == SPRITES  &&  target[targetName].remove)
				{// if:  targeting a sprite
					target[targetName].remove();
				}// if:  targeting a sprite
				else
				{// if:  targeting a regular movieClip
					// remove the specified movieClip		(WARNING:  onUnload() might get called more than once!!! )
	//					target[targetName].unload();
	//					target[targetName].onUnload();
					callUnload( target[targetName] );
					target[targetName].removeMovieClip();
					//target[targetName]._name = null;
				}// if:  targeting a regular movieClip
				
				
				// wait for promise
				nextEvent();
				
				
			}// if:  time has passed since "auto" script started		(prevent game crash)
			else
			{// if:  NO time has passed since the "auto" script began
				
				
				// wait for promise
				if(TRACE_SCRIPT)
					trace("\t too early, wait for 1 millisecond");
				setTimeout( function(){
					var inner_prom = define_swf( thisCommand_obj, skipSwfloader );
					inner_prom.then = nextEvent;
				}, autoDelay );
				
				
			}// if:  NO time has passed since the "auto" script began
		}// if:  has variable name
	}// if:  no linkage given
	
	
	// wait for promise
	return prom;
	
	
	// recursively search all parent movieClips,  look for a parent that is a temporary layer listed in ROOT.tempContainers
	function isInsideLevel( mc ){
		var parent = mc._parent;
		if( !parent._name )															return false;
		if( ROOT.tempContainers[ parent._name ] )				return true;
		if( parent === ROOT )														return false;
		if( parent === _root )													return false;
		if( parent === _level0 )												return false;
		return isInsideLevel( parent );
	}// isInsideLevel()
	
}// define_swf()