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

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

namespace Utage
{
	public class Adx2Group : MonoBehaviour
	{
		internal SoundManager SoundManager { get { return SoundManagerSystem.SoundManager; } }
		internal Adx2LeSoundManagerSystem SoundManagerSystem { get; private set; }

		internal Dictionary<string, Adx2Player> PlayerList { get { return playerList; } }
		Dictionary<string, Adx2Player> playerList = new Dictionary<string, Adx2Player>();

		public string GroupName { get { return gameObject.name; } }

		//グループ内で複数のオーディオを鳴らすか
		public bool MultiPlay
		{
			get { return multiPlay; }
			set { multiPlay = value; }
		}
		[SerializeField]
		bool multiPlay;

		//プレイヤーが終了したら自動削除するか
		public bool AutoDestoryPlayer
		{
			get { return autoDestoryPlayer; }
			set { autoDestoryPlayer = value; }
		}
		[SerializeField]
		bool autoDestoryPlayer;

		//マスターボリューム
		public float MasterVolume { get { return masterVolume; } set { masterVolume = value; } }
		[Range(0, 1), SerializeField]
		float masterVolume = 1;

		//ダッキングの影響を与えるグループ
		public List<Adx2Group> DuckGroups { get { return duckGroups; } }
		[SerializeField]
		List<Adx2Group> duckGroups = new List<Adx2Group>();

		float DuckVolume { get; set; }
		float duckVelocity = 1;

		internal void Init(Adx2LeSoundManagerSystem soundManagerSystem)
		{
			SoundManagerSystem = soundManagerSystem;
			DuckVolume = 1;
			duckVelocity = 1;
		}

		internal float GetVolume(string tag)
		{
			float masterVolume = 1;
			if (!SoundManagerSystem.Adx2LeForUtage.IgnoreConfigMasterVolume)
			{
				masterVolume = this.MasterVolume * SoundManager.MasterVolume;
				foreach (var taggedVolume in SoundManager.TaggedMasterVolumes)
				{
					if (taggedVolume.Tag == tag)
					{
						masterVolume *= taggedVolume.Volume;
					}
				}
			}
			float duckVolume = 1;
			if(!SoundManagerSystem.Adx2LeForUtage.IgnoreDuckVolume)
			{
				duckVolume = DuckVolume;
			}
			return masterVolume * duckVolume;
		}

		void Update()
		{
			//以下、ダッキング処理
			if (Mathf.Approximately(1.0f, SoundManager.DuckVolume))
			{
				//ダッキングのボリュームが1なので常に影響受けない
				DuckVolume = 1;
				return;
			}

			//ダッキングの影響をうけるグループがない
			if (DuckGroups.Count <= 0)
			{
				DuckVolume = 1;
				return;
			}

			bool isPlaying = DuckGroups.Exists(x => x.IsPlaying());
			float dukkingTo = (isPlaying) ? SoundManager.DuckVolume : 1;
			if (Mathf.Abs(dukkingTo - DuckVolume) < 0.001f)
			{
				//ダッキングの目標値に近づいた
				DuckVolume = dukkingTo;
				duckVelocity = 0;
			}
			else
			{

				DuckVolume = Mathf.SmoothDamp(DuckVolume, dukkingTo, ref duckVelocity, SoundManager.DuckFadeTime);
			}
		}


		internal void Remove(string label)
		{
			PlayerList.Remove(label);
		}

		public bool IsLoading
		{
			get
			{
				return false;
			}
		}

		Adx2Player GetPlayer(string label)
		{
			Adx2Player player;
			if (PlayerList.TryGetValue(label, out player))
			{
				return player;
			}
			return null;
		}

		Adx2Player GetPlayerOrCreateIfMissing(string label)
		{
			Adx2Player player = GetPlayer(label);
			if (player == null)
			{
				player = this.transform.AddChildGameObjectComponent<Adx2Player>(label);
				player.Init(label, this);
				PlayerList.Add(label, player);
			}
			return player;
		}

		Adx2Player GetOnlyOnePlayer(string label, float fadeOutTime)
		{
			Adx2Player player = GetPlayerOrCreateIfMissing(label);
			if (PlayerList.Count > 1)
			{
				foreach (var keyValue in PlayerList)
				{
					if (keyValue.Value != player)
					{
						keyValue.Value.Stop(fadeOutTime);
					}
				}
			}
			return player;
		}

		internal bool IsPlaying()
		{
			foreach (var keyValue in PlayerList)
			{
				if (keyValue.Value.IsPlaying()) return true;
			}
			return false;
		}

		internal bool IsPlaying(string label)
		{
			Adx2Player player = GetPlayer(label);
			if (player == null) return false;
			return player.IsPlaying();
		}

		internal bool IsPlayingLoop(string label)
		{
			Adx2Player player = GetPlayer(label);
			if (player == null) return false;
			return player.IsPlayingLoop();
		}

		internal void Play(string label, SoundData data, float fadeInTime, float fadeOutTime)
		{
			Adx2Player player = (MultiPlay) ? GetPlayerOrCreateIfMissing(label) : GetOnlyOnePlayer(label, fadeOutTime);
			player.Play(data, fadeInTime, fadeOutTime);
		}

		internal void Stop(string label, float fadeTime)
		{
			Adx2Player player = GetPlayer(label);
			if (player == null) return;
			player.Stop(fadeTime);
		}
		internal void StopAll(float fadeTime)
		{
			foreach (var keyValue in PlayerList)
			{
				keyValue.Value.Stop(fadeTime);
			}
		}

		internal void StopAllIgnoreLoop(float fadeTime)
		{
			foreach (var keyValue in PlayerList)
			{
				if (keyValue.Value.IsPlayingLoop()) continue;
				keyValue.Value.Stop(fadeTime);
			}
		}

		internal float GetSamplesVolume(string label)
		{
			Adx2Player player = GetPlayer(label);
			if (player == null) return 0;
			return player.GetSamplesVolume();
		}

		const int Version = 0;
		//セーブデータ用のバイナリ書き込み
		internal void Write(BinaryWriter writer)
		{
			writer.Write(Version);
			writer.Write(PlayerList.Count);
			foreach (var keyValue in PlayerList)
			{
				writer.Write(keyValue.Key);
				writer.WriteBuffer(keyValue.Value.Write);
			}
		}

		//セーブデータ用のバイナリ読み込み
		internal void Read(BinaryReader reader)
		{
			int version = reader.ReadInt32();
			if (version <= Version)
			{
				int playerCount = reader.ReadInt32();
				for (int i = 0; i < playerCount; ++i)
				{
					string label = reader.ReadString();
					Adx2Player player = GetPlayerOrCreateIfMissing(label);
					reader.ReadBuffer(player.Read);
				}
			}
			else
			{
				Debug.LogError(LanguageErrorMsg.LocalizeTextFormat(ErrorMsg.UnknownVersion, version));
			}
		}
	}
}
