// ============================================================
// Project            :  GlassTower
// File               :  .\game\gameScripts\SoundSystem.cs
// Copyright          :  
// Author             :  Michael.Mineev
// Created on         :  6 декабря 2010 г. 16:59
//
// Editor             :  TorqueDev v. 1.2.3430.42233
//
// Description        :  
//                    :  
//                    :  
// ============================================================
function CreateSoundSystem()
{
	return new ScriptObject() { class="SoundSystem";};	
}

function Handle::onAdd(%this)
{
	%this.val=0;
}

function CreateHandle(%handle)
{
	%obj=new ScriptObject(){class="Handle";};
	%obj.val=%handle;
	return %obj;
}

function Sound::onAdd(%this)
{
	%this.name="";
	%this.obj="";
	%this.singleton=false;
	%this.handles=new ScriptGroup();
}

function Sound::SetProfile(%this, %profile)
{
	%this.obj=%profile;
}

function Sound::SetName(%this, %name)
{
	%this.name=%name;
}

function Sound::GetChannell(%this)
{
	return %this.obj.description.type;
}

function Sound::Create(%this,  %block, %name, %singleton)
{
	echo("Creating sound");
	%this.SetProfile(%block);
	%this.SetName(%name);
	%this.singleton=%singleton;
}

function Sound::CreateFromFile(%this, %soundName, %soundFileName, %soundIsLooping, %soundIs3D, %soundIsStreaming, %soundIsPreload, %isMusic, %isSingletone)
{
	new AudioDescription(%soundName@"Description")
	{
   		isLooping= %soundIsLooping;
   		is3D     = %soundIs3D;
   		isStreaming=%soundIsStreaming;
   		preload = %soundIsPreload;
   		type     = %isMusic ? $MusicAudioType:$effectsAudioType;
	};

	%sProf = new AudioProfile(%soundName@"Profile")
	{
		filename = %soundFileName;
		description = %soundName@"Description";
	};
	%this.obj=%soundName@"Profile";
	%this.name=%soundName;
	%this.singleton=%isSingletone;	
}

function Sound::Play(%this)
{
	if(%this.singleton && (%this.IsAnyPlaying() || %this.IsAnyPaused()))
		return "";
	%handle=CreateHandle(alxPlay(%this.obj));
	if(%handle.val != 0)
	{
		%this.handles.add(%handle);
	}
	else
	{
		if(sceneWindow2D.soundSystem.GetMusicVolume()==0)
		{
			sceneWindow2D.soundSystem.SetMusicVolume(0.1);
			%handle=%this.Play();
			sceneWindow2D.soundSystem.MuteMusic();
		}
		else			
			error("Failed to play " @ %this.name);
	}
	
	return %handle;
}

function Sound::Pause(%this, %handle)
{
	if(%this.handles.ismember(%handle))
	{
		alxPause(%handle.val);
	}
}

function Sound::PauseAll(%this)
{
	for(%i=0;%i<%this.handles.getCount();%i++)
		alxPause(%this.handles.getObject(%i).val);
}

function Sound::UnPause(%this, %handle)
{
	if(%this.handles.ismember(%handle))
	{
		alxUnPause(%handle.val);
	}
}

function Sound::UnPauseAll(%this)
{
	for(%i=0;%i<%this.handles.getCount();%i++)
		alxUnPause(%this.handles.getObject(%i).val);
}

function Sound::Stop(%this, %handle)
{
	if(%this.handles.ismember(%handle))
	{
		alxStop(%handle.val);
		%this.handles.remove(%handle);
	}
}

function Sound::StopAll(%this)
{
	for(%i=0;%i<%this.handles.getCount();%i++)
		alxStop(%this.handles.getObject(%i).val);
	%this.handles.clear();
}

function Sound::IsAnyPlaying(%this)
{
	%i=0;
	while(%i<%this.handles.getCount())
		if(!alxIsValidHandle(%this.handles.getObject(%i).val))
			%this.handles.remove(%this.handles.getObject(%i));
		else
			%i++;
			
	for(%i=0;%i<%this.handles.getCount();%i++)
		if(alxIsPlaying(%this.handles.getObject(%i).val))
			return true;
			
	return false;
}

function Sound::IsPlaying(%this, %handle)
{
	if(%this.handles.ismember(%handle))
	{
		return alxIsPlaying(%handle.val);
	}
			
	return false;
}

function Sound::IsPaused(%this, %handle)
{
	if(%this.handles.ismember(%handle))
	{
		return alxIsPaused(%handle.val);
	}
			
	return false;
}

function Sound::IsAnyPaused(%this)
{
	for(%i=0;%i<%this.handles.getCount();%i++)
		if(alxIsPaused(%this.handles.getObject(%i).val))
			return true;
			
	return false;
}

function Sound::GetDuration(%this)
{
	for(%i=0;%i<%this.handles.getCount();%i++)
	{
		%dur=alxGetStreamDuration(%this.handles.getObject(%i).val);
		if(%dur!=-1)
			return %dur;
	}
	
	return -1;
}

function Sound::GetSoundPosition(%this)
{
	for(%i=0;%i<%this.handles.getCount();%i++)
	{
		%pos=alxGetStreamPosition(%this.handles.getObject(%i).val);
		if(%pos!=-1)
			return %pos;
	}
	
	return -1;
}

function Sound::SetSoundPosition(%this, %position)
{
	for(%i=0;%i<%this.handles.getCount();%i++)
	{
		return alxSeekToStreamPosition(%this.handles.getObject(%i).val, %position);
	}
	
	return false;
}

function SoundGroup::onAdd(%this)
{
	%this.name="";
	%this.sounds=new ScriptGroup();
	%this.cancelLoop=false;
	%this.loopEvent=-1;
}

function SoundGroup::AddSound(%this, %sound)
{
	if(!%this.sounds.isMember(%sound))
		%this.sounds.add(%sound);
}

function SoundGroup::GetSoundByName(%this, %name)
{
	for(%i=0;%i<%this.sounds.getCount();%i++)
	{
		if(%this.sounds.getObject(%i).name $= %name)
			return %this.sounds.getObject(%i);
	}
			
	return "";
}

function SoundGroup::AddSound(%this, %block, %name, %singleton)
{
	if(!isObject(%this.GetSoundByName(%name)))
	{
		%sound=new ScriptObject(){class="Sound";};
		echo("Trying to create sound");
		%sound.Create(%block, %name, %singleton);
		%this.sounds.add(%sound);
	}
}

function SoundGroup::AddSoundFromFile(%this, %soundName, %soundFileName, %soundIsLooping, %soundIs3D, %soundIsStreaming, %soundIsPreload, %isMusic, %isSingletone)
{
	if(!isObject(%this.GetSoundByName(%soundName)))
	{
		%sound=new ScriptObject(){class="Sound";};
		%sound.CreateFromFile(%soundName, %soundFileName, %soundIsLooping, %soundIs3D, %soundIsStreaming, %soundIsPreload, %isMusic, %isSingletone);
		%this.sounds.add(%sound);
	}
}

function SoundGroup::PlayRandomSound(%this)
{
	%n= getRandom(0,%this.sounds.getCount()-1);
	echo("Playing " @ %n @ " sound");
	if(%n>=0)
		return %this.sounds.getObject(%n) SPC %this.sounds.getObject(%n).Play();
	return "";
}

function SoundGroup::GetRandomSound(%this)
{
	%found = false;
	%count = %this.sounds.getCount();
	%n = getRandom(0, %count - 1);
	
	for (%i = 0; %i < %count; %i++)
	{
		if (%this.wasPlayed[%n])
		{
			%n++;
			if (%n >= %count) %n = 0;
		}
		else
		{
			%this.wasPlayed[%n] = true;
			%found = true;
			break;
		}
	}
	
	if (%found == false)
	{
		for (%i = 0; %i < %count; %i++)
			%this.wasPlayed[%i] = false;
			
		%n = getRandom(0, %count - 1);
		%this.wasPlayed[%n] = true;
	}
	
	echo("Playing " @ %n @ " sound");
	return %this.sounds.getObject(%n);	
}

function SoundGroup::UnPauseAll(%this)
{
	for(%i=0;%i<%this.sounds.getCount();%i++)
		%this.sounds.getObject(%i).UnPauseAll();
}

function SoundGroup::PauseAll(%this)
{
	for(%i=0;%i<%this.sounds.getCount();%i++)
		%this.sounds.getObject(%i).PauseAll();
}

function SoundGroup::StopAll(%this)
{
	for(%i=0;%i<%this.sounds.getCount();%i++)
		%this.sounds.getObject(%i).StopAll();
}

function SoundGroup::IsAnyPlaying(%this)
{
	for(%i=0;%i<%this.sounds.getCount();%i++)
	{
		if(%this.sounds.getObject(%i).IsAnyPlaying())
			return true;
	}
			
	return false;
}
	

function SoundGroup::ScheduleRandomLoopAll(%this)
{
	%dur=%this.PlayRandomSound().GetDuration();
	echo("Duration " @ %dur);
	%this.loopEvent=%this.schedule(%dur*1000+100,"ScheduleRandomLoopAll");
}

function SoundGroup::CancelLoop(%this, %stopImmediate)
{
	if(%stopImmediate)
		%this.StopAll();
		
	if(isEventPending(%this.loopEvent))
	{
		cancel(%this.loopEvent);
		%this.loopEvent=-1;
	}
}

function SoundSystem::onAdd(%this)
{
	%this.groups=new ScriptGroup();	
	%this.endFadeEval="";
	%this.clearEval=false;
	
	%this.stoping=true;
	%this.starting=false;
	
	%this.musicFadeEvent=-1;
	%this.effectsFadeEvent=-1;
	%this.tweener = CreateTweener();
}

function SoundSystem::onRemove(%this)
{
	%this.tweener.delete();
}

function SoundSystem::AddGroup(%this, %name)
{
	%group=new ScriptObject(){class="SoundGroup";};
	%group.name=%name;
	echo("group name: " @ %group.name);
	%this.groups.add(%group);
	return %group;
}

function SoundSystem::GetGroupByName(%this, %name)
{
	for(%i=0;%i<%this.groups.getCount();%i++)
	{
		if(%this.groups.getObject(%i).name $= %name)
			return %this.groups.getObject(%i);
	}
			
	return "";
}

function SoundSystem::PlayRandomSoundInGroup(%this, %groupName)
{
	echo("Playing random sound in group " @ %groupName);
	%group=%this.GetGroupByName(%groupName);
	if(isObject(%group))
	{
		return %group.PlayRandomSound();
	}
}

function SoundSystem::PlaySoundInGroup(%this, %groupName, %soundName)
{
	echo("Playing sound " @ %soundName @ " in group " @ %groupName);
	%group=%this.GetGroupByName(%groupName);
	if(isObject(%group))
	{
		%sound=%group.GetSoundByName(%soundName);
		if(isObject(%sound))
			return %sound SPC %sound.Play();
	}
}

function SoundSystem::StopAllInGroup(%this, %groupName)
{
	%group=%this.GetGroupByName(%groupName);
	if(isObject(%group))
	{
		return %group.StopAll();
	}
}

function SoundSystem::PauseAll(%this)
{
	for(%i=0;%i<%this.groups.getCount();%i++)
	{
		%this.groups.getObject(%i).PauseAll();
	}
}

function SoundSystem::UnPauseAll(%this)
{
	for(%i=0;%i<%this.groups.getCount();%i++)
	{
		%this.groups.getObject(%i).UnPauseAll();
	}
}

function SoundSystem::StopAll(%this)
{
	for(%i=0;%i<%this.groups.getCount();%i++)
	{
		%this.groups.getObject(%i).StopAll();
	}
}

function SoundSystem::GetMusicVolume(%this)
{
	return $pref::Audio::channelVolume[$MusicAudioType];
}

function SoundSystem::GetEffectsVolume(%this)
{
	return $pref::Audio::channelVolume[$EffectsAudioType];
}

function SoundSystem::SetMusicVolume(%this, %volume)
{
	%ret=alxSetChannelVolume($MusicAudioType, %volume);
   	$pref::Audio::channelVolume[$MusicAudioType]=%volume;	
	return %ret;
}

function SoundSystem::SetEffectsVolume(%this, %volume)
{
	%ret=alxSetChannelVolume($EffectsAudioType, %volume);
	$pref::Audio::channelVolume[$EffectsAudioType]=%volume;	
	return %ret;
}

function SoundSystem::MuteMusic(%this)
{
	echo("MuteMusic");
	if(isObject(%this.musicFadeEvent))
	{
		%this.tweener.removeTween(%this.musicFadeEvent);
		%this.OnTweenered();
	}
	return %this.SetMusicVolume(0);
}

function SoundSystem::MuteEffects(%this)
{
	echo("MuteEffects");
	if(isObject(%this.effectsFadeEvent))
	{
		%this.tweener.removeTween(%this.effectsFadeEvent);
		%this.OnTweenered();
	}
	return %this.SetEffectsVolume(0);
}

function SoundSystem::FadeMusicVolume(%this, %time, %from, %to)
{
	echo("Fading music from " @ %from @ " to " @ %to);
	if($Game::musicEnabled && $GameWindowFocused)
	{
		%this.musicFadeEvent=%this.tweener.TweenValue(%this,%from,%to,%time,"SetMusicVolume",true);
	}
	else
		%this.OnTweenered();
}

function SoundSystem::FadeEffectsVolume(%this, %time, %from, %to)
{
	if($Game::soundEnabled && $GameWindowFocused)
	{
		%this.effectsFadeEvent=%this.tweener.TweenValue(%this,%from,%to,%time,"SetEffectsVolume",true);
	}
	else
		%this.OnTweenered();
}

function SoundSystem::StopGroupAndFade(%this, %group, %time, %music, %effects)
{
	%this.endFadeEval="%this.StopAllInGroup(" @ %group @ ");";
	if(%music)
		%this.FadeMusicVolume(%time,$Game::musicVolume,0);
	if(%effects)
		%this.FadeEffectsVolume(%time,$Game::soundVolume,0);
}

function SoundSystem::PlayRandomSoundInGroupAndFade(%this, %group, %time, %music, %effects)
{
	%sound=getWord(%this.PlayRandomSoundInGroup(%group),0);
	echo("PlayRandomSoundInGroupAndFade, Duration: " @ (%sound.GetDuration()*1000));
	if(%music)
	{
		%this.FadeMusicVolume(%time,0, $Game::musicVolume);
		if(!%sound.obj.description.isLooping)
			%this.PRSID=%this.schedule(%sound.GetDuration()*1000-%time,"PRSFading", %time, $MusicAudioType);
	}
	if(%effects)
	{
		%this.FadeEffectsVolume(%time, 0, $Game::soundVolume);
		if(!%sound.obj.description.isLooping)
			%this.PRSID=%this.schedule(%sound.GetDuration()*1000-%time,"PRSFading", %time, $effectsAudioType);
	}
}

function SoundSystem::PRSFading(%this, %time, %channel)
{
	echo("PRSFading " @ getRealTime()); 
	%this.stoping=true;
	%this.starting=false;
	%this.endFadeEval="%this.stoping=true; %this.starting=false; %this.clearEval=true; %this.PRSID=-1;";
	
	switch(%channel)
	{
	case $MusicAudioType:
		%this.FadeMusicVolume(%time,$Game::musicVolume, 0);
	case $effectsAudioType:
		%this.FadeEffectsVolume(%time, $Game::soundVolume, 0);
	}
}

function SoundSystem::PlaySoundInGroupAndFade(%this, %groupName, %soundName, %time)
{
	%mute=false;
	%grp=%this.GetGroupByName(%groupName);
	if(isObject(%grp))
	{
		%sound=%grp.GetSoundByName(%soundName);
		if(!isObject(%sound)) %mute=true;
	}
	else
		%mute=true;
		
	if(%mute)
	{
		%this.FadeMusicVolume(%time,0, $Game::musicVolume);
		return;
	}
	
	%this.PlaySoundInGroup(%groupName,%soundName);
	switch(%sound.GetChannell())
	{
	case $MusicAudioType:
		%this.FadeMusicVolume(%time,0, $Game::musicVolume);
	case $effectsAudioType:
		%this.FadeEffectsVolume(%time, 0, $Game::soundVolume);
	}
	if(!%sound.obj.description.isLooping)
	{
		%this.PRSID=%this.schedule(%sound.GetDuration()*1000-%time,"PRSFading", %time, %sound.GetChannell());
	}
}

function SoundSystem::StopAllOnChannell(%this, %channell)
{
	echo("Stoping all on chanell " @ %channell);
	for(%i=0;%i<%this.groups.getCount();%i++)
	{
		if(%this.groups.getObject(%i).IsAnyPlaying())
			for(%j=0;%j<%this.groups.getObject(%i).sounds.getCount();%j++)
				if(%this.groups.getObject(%i).sounds.getObject(%j).GetChannell()==%channell)
					%this.groups.getObject(%i).sounds.getObject(%j).StopAll();
	}
}

function SoundSystem::ChangeTrack(%this, %groupName, %soundName, %fadeTime)
{
	if( %this.PRSID != -1)
	{
		cancel(%this.PRSID);
		%this.PRSID=-1;
	}
	
	%this.endFadeEval="%this.StopAllOnChannell(" @ $MusicAudioType @ "); %this.stoping=false; %this.starting=true; %this.endFadeEval=\"%this.starting=false; %this.clearEval=true;\"; %this.PlaySoundInGroupAndFade(\"" @ %groupName @ "\",\"" @ %soundName @ "\"," @ %fadeTime @ ");";
	echo("ChangeTrack eval: " @ %this.endFadeEval);
	if(!%this.stoping)
	{
		%this.stoping=true;
		%this.FadeMusicVolume(%fadeTime,$Game::musicVolume, 0);
	}
	else
		if(%this.starting)
		{
			%this.endFadeEval="%this.stoping=false; %this.starting=false; %this.ChangeTrack(\"" @ %groupName @ "\",\"" @ %soundName @ "\"," @ %fadeTime @ ");";
		}
		else
		{
			if(%this.stoping && !%this.starting)
			{
				%this.starting=true;
				%this.endFadeEval="%this.stoping=false; %this.starting=false; %this.clearEval=true;";
				if(%this.PRSID!=-1)
					%this.StopAllOnChannell($MusicAudioType);
				%this.PlaySoundInGroupAndFade(%groupName,%soundName,%fadeTime);
			}
		}
		
}

function SoundSystem::ChangeRandomTrack(%this, %groupName, %fadeTime)
{
	%grp=%this.GetGroupByName(%groupName);
	%sound=%grp.GetRandomSound();
	%this.ChangeTrack(%groupName, %sound.Name, %fadeTime);
	return %sound;
}

function SoundSystem::PlayGroupRandom(%this, %groupName, %fadeTime)
{
	if(%groupName $= %this.groupPlayerGroup)return;
	if(%this.groupPlayerId>=0)
	{
		cancel(%this.groupPlayerId);
	}
	%this.groupPlayerGroup = %groupName;
	%grp=%this.GetGroupByName(%groupName);
	%this.groupPlayerFadeTime = %fadeTime;
	if(%grp.IsAnyPlaying())return;
	%this.stopAll();
	%this.ChangeRandomTrack(%groupName, %fadeTime);
	%this.groupPlayerId=%this.schedule(1000, "checkGroupPlayer");
}
function SoundSystem::cancelGroupPlayer(%this)
{
	if(%this.groupPlayerId>=0)cancel(%this.groupPlayerId);
	%this.groupPlayerGroup = "";
}
function SoundSystem::checkGroupPlayer(%this)
{
	if(%this.groupPlayerId<0)return;
	%grp=%this.GetGroupByName(%this.groupPlayerGroup);
	if(!%grp.IsAnyPlaying())%this.ChangeRandomTrack(%this.groupPlayerGroup, %this.groupPlayerFadeTime);
		
	%this.groupPlayerId=%this.schedule(1000, "checkGroupPlayer");
}

function SoundSystem::onTweenered(%this)
{
	echo("Trying to eval: " @ %this.endFadeEval);
	eval(%this.endFadeEval);
	if(%this.clearEval)
	{
		%this.endFadeEval="";
		%this.clearEval=false;
	}
}

function SoundSystem::CreateSoundInGroup(%this, %groupName, %soundName, %soundFileName, %soundIsLooping, %soundIs3D, %soundIsStreaming, %soundIsPreload, %isMusic, %isSingletone)
{
	%group = %this.GetGroupByName(%groupName);
	if(!isObject(%group))%group=%this.AddGroup(%groupName);
	
	%group.AddSoundFromFile(%soundName, %soundFileName, %soundIsLooping, %soundIs3D, %soundIsStreaming, %soundIsPreload, %isMusic, %isSingletone);
}

function SoundSystem::Init(%this)
{
	echo("Initializing sound system");
	%group=%this.AddGroup("Menu");
	%group.AddSound(ambient5Loop,"background",true);
	%group.AddSound(menuButtonClick,"inGameMenuButtonClick",false);
	%group.AddSound(menuButtonEnter,"inGameMenuButtonEnter",false);
	/*%group.AddSound(scoreCounting,"statScoreCounter",false);
	%group.AddSound(totalScore,"statTotalScore",false);
	%group.AddSound(livesShowing,"statLivesShowing",false);
	%group.AddSound(stars1,"statStar1",false);
	%group.AddSound(stars2,"statStar2",false);
	%group.AddSound(stars3,"statStar3",false);
	%group.AddSound(splash,"logo",true);
	%group.AddSound(LevelFailed, "LevelFailed", false);
	%group.AddSound(LevelCompleted, "LevelCompleted", false);*/
	
	%group=%this.AddGroup("Background");
	%group.AddSound(ambient6,"ambient6",true);
	%group.AddSound(ambient7,"ambient7",true);
	
	/*%group=%this.AddGroup("WoodBlueSFX");
	%group.AddSound(woodBlueBlockCrash,"blueBlockCrash",false);
	
	%group=%this.AddGroup("WoodRedSFX");
	%group.AddSound(woodRedBlockCrash,"redBlockCrash",false);
	
	%group=%this.AddGroup("BonusSFX");
	%group.AddSound(redBlockCrash,"bonusBlockCrash",false);*/
	
	echo("Initializing sound system ... finished");
}
