/*
	VERSION:		3.3
	3.3		Added "isFading" flag
	3.2		New songs interrupt fadeTo() tranitions  (make them immediatley jump to their final volume levels)
	
	DESCRIPTION:
		This is a movieClip-based music system.
		It simulates stereo using mono music clips stored in the library.
	
	MINIMAL USAGE:
		#include "makeStereoMusic.as"
		MUSIC = makeStereoMusic();
		MUSIC.play( linkageName );
		
	
	MAX USAGE:
		#include "makeStereoMusic.as"
		MUSIC = makeStereoMusic( target_mc:MovieClip, newName:String, [newDepth:Number] );
		MUSIC.play( linkageName );
		
		
	FUNCTIONS:
		play( "songName.mp3" );				// Plays the songName_intro tune, then switches to songName (which should loop)
		playLoop( "songName.mp3" );			// Skip any intro's and specifically play the main loo pof the song
		stopMusic();								// Stops the music and forgets the last song
		fadeTo( newVolume, seconds );		// Fades the song volume to a new level
		
	VARIABLES:
		songName								// file path of the last song sent to this system
		isPlaying								// whether the current song is playing or stopped
		
	PROPERTIES:
		volume								// scalar (percentage) that gets or sets the maximum playback volume of all music
		songVolume							// gets or sets the intensity of THIS song  (used for fades)
		
		Playback volume  =  songVolume * (volume/100)
		To change the volume of all music played, use "volume".
		To change the volume of only the current song, use "songVolume".
		All songs start playback with an "songVolume" of 100.
		
	EVENTS:
		onLoad()									// Called when a song or song intro successfully starts.
		onSoundComplete()					// Called when a song or song intro completes.  (the song doesn't neccesarily stop)
		onFadeComplete()					// Called when a fadeTo() completes.
		onID3()										// Called each time an ID3 tag is loaded.  (if there are two versions in a file, it gets called twice)
		onStop()									// Called when the music is explicitly stopped
		
	INTROS & LOOPS:
		You may add folders before the fileNames.
		Name your files / linkages like so:
			songName_intro.mp3			play("songName.mp3")				(The extension must be .mp3)
			songName.mp3					playLoop("songName.mp3")			(This is the looping version of the song.)
		When play() is used, it'll automatically attempt to load an intro for the song. If there's no intro, it'll play the loop.
	
	DEPENDANCIES:
		nextDepth.as
*/



makeStereoMusic = function( target_mc, newName, newDepth )
{
	// resolve optional parameters
	var target_mc = (target_mc != undefined) ? target_mc : this;
	var newName = (newName != undefined) ? newName : "musicSystem_mc";
	#include "nextDepth.as"
	var newDepth = (newDepth) ? newDepth : nextDepth(target_mc);
	
	// create containers
	var _this = target_mc.createEmptyMovieClip( newName, newDepth );
	_this.createEmptyMovieClip( "right_mc", 1 );			// container for rightSound's transforms
	_this.createEmptyMovieClip( "left_mc", 0 );			// container for leftSound's transforms
	_this.rightSound = new Sound( _this.right_mc );	// internal Sound object
	_this.leftSound = new Sound( _this.left_mc );		// internal Sound object
	
	// internal variables
	_this.songName = " ";										// Linkage name		(remember which sound is being played, for stop()  &  play()
	_this.loops = 999999;									// loops indefinitely
	_this.stereoDelay = 0.02;								// 20 milliseconds
	_this._volume = 1;										// multiplier:  1 = 100%
	_this._songVolume = 1;								// multiplier:  1 = 100%
	_this.isPlaying = false;
	// Mimic Sound events		(these can be externally defined)
	_this.onID3 = function(){}
	_this.onLoad = function(){}
	_this.onSoundComplete = function(){}
	_this.onFadeComplete = function(){}		// triggers when fadeTo() completes
	_this.isFading = false;								// the existence of _this.fade could also indicate whether a fade isoccurring,  but a flag like this is more descriptive and allows the underlying implementation to change
	
	
	
	
	
	
	// FUNCTIONS
	_this.playSong = function( songName, skipIntro )
	{
		if(_this.songName != songName)
		{
			// immediately complete the fade tween if it exists
			_this.fade.fforward();
			_this.fade.onMotionFinished();
			delete _this.fade;
			
			_this.rightSound.stop();
			_this.leftSound.stop();
			_this.rightSound.onSoundComplete = function(){}
			_this.rightSound = new Sound( _this.right_mc );
			_this.leftSound = new Sound( _this.left_mc );
			var nameLength = songName.lastIndexOf(".");
			var introName = songName.substr(0, nameLength) + "_intro" + ".mp3";		// songName.mp3  ->  songName_intro.mp3
			_this.songName = songName;
			_this.isPlaying = false;
			if(_this._songVolume==0)
				_this.songVolume = 100;
			
			// transition:  intro  ->  loop
			_this.gotoLoop = function()
			{
				// play normally
				var songName = _this.songName;
				_this.songName = "";					// spoof it so it'll play the same song again
				_this.playLoop( songName );		// play the regular (looping) version
				_this.applyVolume();
				// broadcast events
				_this.broadcastMessage( "onSoundComplete" );
				_this.onSoundComplete();
			}// gotoLoop()
			
			_this.rightSound.onSoundComplete = function()
			{
				_this.gotoLoop();
			}// onSoundComplete()
			
			if(skipIntro)
			{// if:  skip intro
				_this.gotoLoop();
			}// if:  skip intro
			else
			{// if:  play intro
				_this.rightSound.attachSound( introName );
				_this.leftSound.attachSound( introName );
				
				// If there is no intro,  immediately play the loop
				if(_this.leftSound.duration == undefined)		// if there is no intro
					_this.gotoLoop();		// immediately play looping version
			}// if:  play intro
		}// if: a new song is specified
		
		if( _this.isPlaying == false )
		{
			_this.rightSound.start( 0+_this.stereoDelay, 1 );		// start right sound, 20 milliseconds sooner
			_this.leftSound.start( 0, 1 );											// start left sound
			_this.setChannels();
			_this.applyVolume();
			_this.isPlaying = true;
		}// if:  not playing
	}// play()
	_this.play = _this.playSong;
	
	
	
	_this.playLoop = function( songName )
	{
		if(_this.songName != songName)
		{
			_this.rightSound.stop();
			_this.leftSound.stop();
			_this.rightSound.onSoundComplete = function(){}
			_this.rightSound = new Sound( _this.right_mc );
			_this.leftSound = new Sound( _this.left_mc );
			_this.rightSound.attachSound( songName );
			_this.leftSound.attachSound( songName );
			_this.songName = songName;
			_this.isPlaying = false;
			
			// Remove intro  ->  loop transition
			_this.rightSound.onSoundComplete = function()
			{// sound done()
				// broadcast events
				_this.broadcastMessage( "onSoundComplete" );
				_this.onSoundComplete();
			}// sound done()
		}// if: a new song is specified
		
		if( _this.isPlaying == false )
		{
			_this.rightSound.start( 0+_this.stereoDelay );		// start right sound, 20 milliseconds sooner
			_this.leftSound.start( 0 );		// start left sound
			_this.setChannels();
			_this.applyVolume();
			_this.isPlaying = true;
			// looping
			_this.rightSound.onSoundComplete = function()
			{// sound done()
				_this.rightSound.start( 0+_this.stereoDelay );
				_this.leftSound.start( 0 );
				// broadcast events
				_this.broadcastMessage( "onSoundComplete" );
				_this.onSoundComplete();
			}// sound done()
		}// if:  not playing
	}// playLoop()
	
	
	
	_this.stopMusic = function()
	{
		// remove fade tween if it exists
		_this.fade.stop();
		delete _this.fade;
		delete _this.fadeVol;
		// Stop the sound
		_this.rightSound.stop();			// probably redundant
		_this.leftSound.stop();				// probably stops ALL instances of this particular sound effect
		_this.isPlaying = false;
		_this.songName = "";					// Forget the last song. Next time, it'll play again from the beginning.
		_this.broadcastMessage( "onStop" );
	}// stop()
	
	
	
	_this.stop = _this.stopMusic;		// compatible with my simpler music system
	
	
	
	// getVolume()
	_this.getVolume = function()
	{
		return _this._volume *100;
	}// volume		(get)
	// setVolume()
	_this.setVolume = function( newVolume )
	{
		_this._volume = newVolume / 100;
		_this.applyVolume();
	}// volume		(set)
	_this.addProperty( "volume", _this.getVolume, _this.setVolume );
	
	
	
	_this.getSongVolume = function()
	{
		return _this._songVolume *100;
	}// volume		(get)
	_this.setSongVolume = function( newVolume )
	{
		_this._songVolume = newVolume / 100;
		_this.applyVolume();
	}// volume		(set)
	_this.addProperty( "songVolume", _this.getSongVolume, _this.setSongVolume );
	
	
	
	_this.getDuration = function()
	{
		return _this.leftSound.duration;
	}// duration	(get)
	_this.addProperty( "duration", _this.getDuration, null );
	
	
	
	_this.fadeTo = function( endVolume, seconds )
	{
		// tween volume from current to target
		var startVolume = _this._songVolume *100;
		delete _this.fade;		// cancel previous fade
		_this.isFading = true;
		_this.fadeVol = startVolume;
		_this.fade = new mx.transitions.Tween( _this, "fadeVol", null, startVolume, endVolume, seconds, true);
		
		// onChange
		_this.fade.onMotionChanged = function()
		{
			_this.setSongVolume( this.position );
		}// onMotionChanged()
		
		// onDone
		_this.fade.onMotionFinished = function()
		{
			_this.fade.stop();
			delete _this.fade;
			delete _this.fadeVol;
			if(_this._songVolume == 0)
				_this.stopMusic();
			
			// call events
			_this.broadcastMessage( "onFadeComplete" );
			_this.onFadeComplete();
			_this.isFading = false;
		}// onMotionFinished()
		
		if(!_this.isPlaying)
			_this.fade.onMotionFinished();
	}// fadeTo()
	
	
	
	// Set channels		(which speaker each sound object uses)
	_this.setChannels = function()
	{
		_this.rightSound.setPan( 100 );
		_this.leftSound.setPan( -100 );
	}// setChannels()
	
	
	
	// set volume
	_this.applyVolume = function()
	{
		_this.rightSound.setVolume( 100 *_this._volume *_this._songVolume );
		_this.leftSound.setVolume( 100 *_this._volume *_this._songVolume );
	}// applyVolume()
	
	
	
	// pass Sound events
	_this.passSoundEvents = function()
	{
		_this.leftSound.onID3 = function()
		{
			_this.broadcastMessage( "onID3" );
			_this.onID3();
		}
		_this.leftSound.onLoad = function( success )
		{
			_this.broadcastMessage( "onLoad" );
			_this.onLoad( success );
		}
		/*			// EVENTS ARE CALLED DURING BUILT-IN LOOPING
		_this.rightSound.onSoundComplete = function()
		{
			_this.broadcastMessage( "onSoundComplete" );
			_this.onSoundComplete();
		}
		*/
	}// passSoundEvents()
	
	
	
	
	
	
	// SETUP
	AsBroadcaster.initialize( this );
	// Set channels				(which speaker each sound object uses)
	_this.setChannels();
	// pass sound events		(allows addListener(), which is not available in normal Sound objects)
	_this.passSoundEvents();
	
	// return this sound system
	return _this;
}// makeStereoMusic()