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

//	Summary
//		* 게임의 진행 밸런스를 제어한다.
//		* 시간, 속도, ...

namespace Game
{
	/*
		Game balance
	 */
	public class GameBalance : MonoBehaviour
	{

		public GameObject[] m_BottomItemPrab;

		public Camera m_Camera;

		public int StageChangeInterval	= 5;
		public int SpeedStageChangeInterval	= 10;


		float _defaultGameSpeed	= 4f;
		float maxGameSpeed = 6f;
		float _currentGameSpeed;
		bool isFirstItem;
		Vector3 wasPosition;
		BottomType wasBottomType;

		public float defaultGameSpeed {
			get {
				return _defaultGameSpeed;
			}
		}

		public float currentGameSpeed {
			get {
				return _currentGameSpeed;
			}
		}

		// Use this for initialization
		public void Start ()
		{
			ResetData ();
		}

		/* 
			Game balance 데이터를 초기화한다.
	 	*/
		public void ResetData ()
		{
			Debug.Log ("GameBalance.ResetData()");

			_currentGameSpeed	= defaultGameSpeed;
			isFirstItem = true;
		}

		/* 
			Bottom item을 생성/얻어온다.

			@param time 게임 진행 시간

			@return BottomItem
	 	*/
		public BottomItem GetBottomItem (float time)
		{
			BottomType type = GetBottomType (time);

			int index = (int)type;
	
			GameObject obj = Instantiate (m_BottomItemPrab [index],
				                  new Vector3 (0, 0, 0),
				                  m_BottomItemPrab [index].transform.rotation) as GameObject;

			BottomItem item = obj.GetComponent<BottomItem> ();
			item.transform.position	= GetBottomItemPosition (time, item); 

			return item;
		}

		/* 
			현재의 Game Speed를 얻어온다.

			@param time 게임 진행 시간.

			@return Game Speed
		*/
		public float GetGameSpeed (float time)
		{
			int stage	= (int)(time / SpeedStageChangeInterval);

			float speed = defaultGameSpeed + (defaultGameSpeed * (0.1f * stage));

			if (speed > maxGameSpeed) {
				speed = maxGameSpeed;
			}

			_currentGameSpeed	= speed;

			return speed;
		}

		/* 
			게임 진행 시간에 따른 (stage) 비중있는 랜덤 값으로 BottomType을 얻어온다.

			@param time 게임 진행 시간

			@return Bottom Type
	 	*/
		BottomType GetBottomType (float time)
		{
			int stage = (int)(time / StageChangeInterval);
			int[] weights = GetBalanceStage (stage);

			int value = WeigtedRandom (weights);
			BottomType type	= (BottomType)value;

			wasBottomType	= type;

			return type;
		}

		/* 
			게임 진행 시간에 따른 (stage) 랜덤으로 위치 값을 얻어온다.

			@param time 게임 진행 시간

			@return 위치 값 (Vector3)
		*/
		Vector3 GetBottomItemPosition (float time, BottomItem item)
		{
			float baseLine	= m_Camera.orthographicSize + 1;
			// float baseLine = (float)(Camera.main.orthographicSize * 2.0 * Screen.width / Screen.height);
			float positionX	= 0f;
			float positionY	= 0f;

			Vector3 cameraPosition	= m_Camera.gameObject.transform.position;

			// 처음 생성 값인 경우에는 position x = 0 으로 가운데 위치.
			if (isFirstItem == true) {
				isFirstItem	= false;
				positionX	= 0f;
				positionY	= (float)(-baseLine);
			} else {
				float pos = (m_Camera.orthographicSize - item.transform.localScale.x) / 2;

				bool isDone	= false;

				while (isDone == false) {
					positionX	= (float)(Random.Range (-pos, pos));

					if (wasPosition.x == positionX) {
						continue;
					}

					isDone	= true;
				}

				positionY	= (float)(-baseLine + Random.Range (0, 2));
			}

			Vector3 position = new Vector3 (positionX, positionY, 0f);

			wasPosition	= position;

			return position;
		}

		/*  
			비중 랜덤.

			@param int[] 비중 list.

			@return 비중 랜덤에 의해 선택된 값.
		*/
		int WeigtedRandom (int[] weights)
		{
			int totalWeight = 0;
			foreach (int weight in weights) {
				totalWeight += weight;
			}

			int r = Random.Range (1, totalWeight);

			for (int i = 0; i < weights.Length; i++) {
				r -= weights [i];

				if (r < 1) {
					return i;
				}
			}

			return 0;
		}

		/* 
			Stage에 따른 BottomItem 비중

			@param stage 게임 시간에 따른 stage 값.

			@return int[] 비중 list.
	 	*/
		int [] GetBalanceStage (int stage)
		{
			switch (stage) {
			case 0:
				return new int [] { 100, 0, 0, 0, 0 };
			case 1:
				return new int [] { 90, 10, 0, 0, 0 };
			case 2:
				return new int [] { 80, 10, 10, 0, 0 };
			case 3:
				return new int [] { 70, 10, 10, 10, 0 };
			case 4:
				return new int [] { 60, 10, 10, 10, 10 };
			case 5:
				return new int [] { 50, 20, 10, 10, 10 };
			case 6:
				return new int [] { 40, 20, 20, 10, 10 };
			case 7:
				return new int [] { 30, 20, 20, 20, 10 };
			default:
				return new int [] { 20, 20, 20, 20, 20 };
			}
		}
	}
}
