﻿using UnityEngine;
using System.Collections;

public class MainController : MonoBehaviour
{
	private CsoundUnity csound;

	private int currentBeat=0;
	//master tempo value
	public float masterTempo=60.0f;
	public enum TempoDivision 
	{
		Double_Whole = 0,
		Whole = 1 , 
		Half = 2,
		Quarter = 3,
		Quarter_Triplet = 4,
		Eighth = 5,
		Eighth_Triplet = 6, 
		Sixteenth = 7
	};
	//additional routing - Velocity is always on but these are for other parameters
	// public enum IntensityRouting
	// {
	// 	Off = 0,
	// 	Transposition = 1,
	// 	Panning = 2,
	// 	SeqLength = 3,
	// 	SeqBeatDivision = 4,
	// };
	//additional routing destination
	// public enum LayerNumber
	// {
	// 	Layer0 = 0,
	// 	Layer1 = 1,
	// 	Layer2 = 2,
	// 	Layer3 = 3,
	// 	Layer4 = 4,
	// 	Layer5 = 5,
	// 	Layer6 = 6,
	// 	Layer7 = 7
	// };
	//beat division values for divisions
	private float[] beatDivisions = {0.125f,0.25f,0.5f,1.0f,1.5f,2.0f,3.0f,4.0f};
	//public IntensityRouting intensityRouting;
	//public MainController layerCtrl;
	//public LayerNumber layerToControl;
	public TempoDivision layerDivision;
	//individual tempo value - must be greater than 0
	//Csound metro tempo 
	private float tempo = 1.0f;
	//csound instrument (0-7)
	public int layerInst;
	public int seqLength;
	//duration value per layer - can be changed via intensity from another layer
	public float duration;
	public int[] noteRowList = new int[8];
	public int noteOffset;
	private int transpose;
	

	//intensity is a monophonic, per position parameter - defaults to 1-127 range
	//will need to be mapped to tempo, seq length, duration, due to lower ranges
	public int[] posIntensity = new int[8];

	public int panValue;


	// Use this for initialization
	void Start () 
	{
		//get master tempo from main script

		//Csound tempo calculation at start
		//set tempo to whatever the dropdown enum value is
		UpdateTempo((int)layerDivision);
		Debug.Log("Tempo selection is:"+(int)layerDivision);
		//set layer to Control
		//UpdateLayerControl((int)layerToControl);
		csound = GetComponent<CsoundUnity>();
		//csound.setChannel("tempo", tempo);  
		csound.setChannel("seqLength", seqLength);
		csound.setChannel("inst",layerInst);
		csound.setChannel("duration",duration);
		csound.setChannel("noteOffset",noteOffset);

		for (int count=0; count < 8; ++count)
		{
		int note = noteRowList[count];
			csound.setChannel("noteRowList",note);
		}
	}

	
	// Update is called once per frame
	void Update () 
	{
		//adjust tempo on the fly with up and down keys
		if(Input.GetKeyDown("up"))
		{
			++layerDivision;
			if((int)layerDivision > 7)
				layerDivision = TempoDivision.Sixteenth;
			UpdateTempo((int)layerDivision);
		}
		else if(Input.GetKeyDown("down"))
		{
			--layerDivision;
			if((int)layerDivision < 0)
				layerDivision = TempoDivision.Double_Whole;
			UpdateTempo((int)layerDivision);
		}
		//adjust seq length on the fly with left and right


		if(currentBeat == csound.getChannel("beat"))
		{
			ResizeCubesInRow(currentBeat);
			currentBeat = (currentBeat!=seqLength-1 ? currentBeat+1 : 0);				
		}
		if(Input.GetKeyUp("r"))
		{
			BroadcastMessage("Randomize");
			StartCoroutine(EnableCubesInOrder());
		}
	}

	//for now this should be called only after seq has stopped
	//but it might be interesting to see if layer control could be called
	//on the fly 
	public void UpdateLayerControl(int layerNum)
	{
		//layerCtrl = GameObject.Find("/Layer"+layerNum).GetComponent<MainController>();

	}

	// public void UpdateIntensity(int intensityValue)
	// {
	// 	//always send velocity unless?
	// 	//set control to intensity value by default
	// 	int controlValue=intensityValue;
	// 	switch(intensityRouting)
	// 	{
	// 		case IntensityRouting.Off:
	// 		break;
	// 		case IntensityRouting.Transposition:
	// 		//subtract 64 divide by 16 (leaves range of -16 to +16 values)
	// 		controlValue = intensityValue - 64 / 4;
	// 		layerCtrl.UpdateTransposition(controlValue); 
	// 		break;
	// 		case IntensityRouting.Panning:
	// 		layerCtrl.UpdatePanning(controlValue);
	// 		break;
	// 		case IntensityRouting.SeqLength:
	// 		controlValue = intensityValue / 4;
	// 		layerCtrl.UpdateSequenceLength(controlValue);
	// 		break;
	// 		case IntensityRouting.SeqBeatDivision:
	// 		controlValue = intensityValue / 16;
	// 		layerCtrl.UpdateTempo(controlValue);
	// 		break;
	// 	}
		
	// }

	//Transposition can be called on the fly
	public void UpdateTransposition(int transposition)
	{
		transpose = transposition;

	}

	//Panning can be called on the fly
	public void UpdatePanning(int panning)
	{
		csound.setChannel("panning", panning);
	}

	public void UpdateSequenceLength(int seqlength)
	{
		csound.setChannel("seqLength",seqlength);
	}

	//tempo/beat div can be called on the fly
	public void UpdateTempo(int value)
	{
		float divisor = beatDivisions[value];
		tempo = masterTempo / 60.0f * divisor;
		Debug.Log("LayerTempo is:"+tempo);
		csound.setChannel("tempo", tempo);

	}


	void ResizeCubesInRow(int index)
	{
		for( int i = 0 ; i < 8; i++)
		{
			string objectName = "Row"+i;
			if(transform.Find(objectName))
				transform.Find(objectName).GetComponent<RowController>().ResizeCube(index);
		}
	}

	public void EnableCubeToPlaySound(int row, int index, bool state)
	{	
		//Debug.Log("Cell Instrument is:"+instrument);	
		row = row +1;
		string channel = "rowCubeIndex"+row;
		csound.setChannel(channel, index);
		channel = "rowCubeNote"+row;
		//get note plus modifier
		csound.setChannel(channel,noteRowList[index]+transpose);
		channel = "rowCubeState"+row;
		csound.setChannel(channel, posIntensity[index]);

		Debug.Log("Playing"+row+","+index+","+state);
	}

	//R keyup calls Randomize function which visually enables cube
	//then this function starts the Coroutine, which then goes through
	//all cubes in order, checks if they are enabled and sends messages to Csound
	IEnumerator EnableCubesInOrder()
	{
		for (int countRow =0; countRow < 8; ++countRow)
		{
			//get row objects
			string currentRow = "Row"+countRow.ToString();
			Transform currentRowObj = transform.Find(currentRow);
			for (int countIndex =0; countIndex < 8; ++countIndex)
			{
			//get index objects in row - easy since these are in child order
				CubeController cube = currentRowObj.GetChild(countIndex).GetComponent<CubeController>();
				Debug.Log("cube is:"+currentRowObj.name+"-"+cube.transform.name);
				if(cube.state == true)
				{
				//if cube is active call the function that sends its data to Csound
				cube.EnableCubeCsound();
				}
				
			//adjustable wait time
			yield return new WaitForSeconds(0.01f);
			}
		}
		
		
	}
}
