﻿//----------------------------------------------
// UTAGE: Unity Text Adventure Game Engine
// Copyright 2014 Ryohei Tokimura
//----------------------------------------------

using System.Collections;
using System.Collections.Generic;
using System.IO;
using System;
using UnityEngine;

namespace Utage
{
	public class Adx2Audio : MonoBehaviour
	{
		Adx2Player Player { get; set; }
		Adx2LeForUtage Adx2LeForUtage
		{
			get
			{
				return Player.Group.SoundManagerSystem.Adx2LeForUtage;
			}
		}
		Adx2AssetFile Adx2File;

		//オーディオの情報
		internal SoundData Data { get; private set; }
		public CriAtomSource Source { get { return source ?? (source = this.gameObject.AddComponent<CriAtomSource>()); } }
		CriAtomSource source;

		bool isFadeOuting = false;
		bool waitDelay;
		float fadeValue = 1;

		class FadeInfo
		{
			public bool Enable { get; private set; }
			public float From { get; set; }
			public float To { get; private set; }
			public float Time { get; private set; }
			public float Duration { get; private set; }
			public float Value { get; private set; }

			public void Start(float from, float to, float duration)
			{
				Enable = true;
				Value = From = from;
				To = to;
				Duration = duration;
				Time = 0;
			}
			public bool Update()
			{
				if (!Enable) return false;

				Time += UnityEngine.Time.deltaTime;
				if (Time >= Duration)
				{
					Value = To;
					Enable = false;
				}
				else
				{
					Value = Mathf.Lerp(From, To, Time / Duration);
				}
				return true;
			}
		}

		FadeInfo fadeInfo = new FadeInfo();

		//セーブが有効かどうか
		internal bool EnableSave
		{
			get
			{
				return !isFadeOuting;
			}
		}

		//初期化
		internal void Init(Adx2Player player, SoundData soundData)
		{
			this.Player = player;
			this.Data = soundData;
			this.Adx2File = Data.File as Adx2AssetFile;
		}

		void OnDestroy()
		{
			Player.Remove(this);
		}

		public bool IsPlaying()
		{
			if (isFadeOuting) return false;
			if (Source.status == CriAtomSource.Status.Playing) return true;
			return false;
		}

		public bool IsPlaying(SoundData data)
		{
			return (IsEqualSoundData(data) && IsPlaying());
		}

		public bool IsPlayingLoop()
		{
			return IsPlaying() && Source.loop;
		}

		internal float GetSamplesVolume()
		{
			throw new NotImplementedException();
			//			return Source.time / 1000.0f * 44100f;
		}
/*
		public float pitch
		{
			get
			{
				return Mathf.Pow(2, Source.pitch / 1200.0f);
			}
			set
			{
				Source.pitch = 1200.0f * Mathf.Log(value) / Mathf.Log(2.0f);
			}
		}
*/
		//サウンドデータのチェック
		internal bool IsEqualSoundData(SoundData data)
		{
			Adx2AssetFile adx2File = data.File as Adx2AssetFile;
			if (adx2File == null || Adx2File == null)
			{
				return false;
			}
			return (adx2File.CueName == Adx2File.CueName) && (adx2File.CueSheet == Adx2File.CueSheet);
		}

		//鳴らす
		internal void Play(float fadeTime, float delay = 0)
		{
			if (this.Adx2File == null)
			{
				Debug.LogError("Not Support Audio Clip");
				Destroy(this.gameObject);
				return;
			}

			StartCoroutine(CoWaitDelay(fadeTime, delay));
		}

		IEnumerator CoWaitDelay(float fadeTime, float delay)
		{
			isFadeOuting = false;
			Adx2AssetFile adx2File = Data.File as Adx2AssetFile;
			if (Adx2LeForUtage.DebugLog) Debug.Log(string.Format("Play {0} FadeIn{1}", Source.cueName, fadeTime));
			Source.volume = 0;
			Source.loop = Data.IsLoop;
			Source.cueSheet = adx2File.CueSheet;
			Source.cueName = adx2File.CueName;
			if (delay > 0)
			{
				waitDelay = true;
				yield return new WaitForSeconds(delay);
				waitDelay = false;
			}
			Source.Play();
			if (!Adx2LeForUtage.EnableFadeOnData && fadeTime > 0)
			{
				fadeInfo.Start(0, Data.Volume, fadeTime);
			}
			else
			{
				Source.volume = Data.Volume;
			}
		}

		internal void FadeOut(float fadeTime = 0)
		{
			if (IsPlaying())
			{
				if (!Adx2LeForUtage.EnableFadeOnData && fadeTime > 0)
				{
					isFadeOuting = true;
					fadeInfo.Start(Source.volume, 0, fadeTime);
				}
				else
				{
					if (Adx2LeForUtage.DebugLog) Debug.Log(string.Format("Stop {0}", Source.cueName));
					Source.Stop();
				}
			}
			else
			{
				GameObject.Destroy(this.gameObject);
			}
		}


		void Update()
		{
			if (fadeInfo.Update())
			{
				fadeValue = fadeInfo.Value;
			}
			else
			{
				if (isFadeOuting)
				{
					if (Adx2LeForUtage.DebugLog) Debug.Log(string.Format("Stop {0}", Source.cueName));
					Source.Stop();
					GameObject.Destroy(this.gameObject);
				}
				else
				{
					fadeValue = 1;
				}
			}

			if (!waitDelay)
			{
				switch (Source.status)
				{
					case CriAtomSource.Status.Error:
					case CriAtomSource.Status.PlayEnd:
					case CriAtomSource.Status.Stop:
						GameObject.Destroy(this.gameObject);
						break;
				}
			}
		}

		void LateUpdate()
		{
			//ボリュームの更新
			if (Source==null) return;

			Source.volume = GetVolume();
		}

		//ボリューム計算
		float GetVolume()
		{
			float volume = fadeValue * Data.Volume * Player.Group.GetVolume(Data.Tag);
			return volume;
		}
	}
}
