using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.IO;
using Microsoft.DirectX;
using Microsoft.DirectX.DirectDraw;
using WaveLib;

namespace HearingAidLab
{
	/// <summary>
	/// Summary description for CatLoud2.
	/// </summary>
	public class CatLoud2 : System.Windows.Forms.Form
	{
		private System.Windows.Forms.Button btnSkip;
		private System.Windows.Forms.TextBox txtMax;
		private System.Windows.Forms.TextBox txtMin;
		private System.Windows.Forms.TextBox txtLevel;
		private System.Windows.Forms.TextBox txtPrimary;
		private System.Windows.Forms.Label label4;
		private System.Windows.Forms.Label label2;
		private System.Windows.Forms.Panel panel1;
		private System.Windows.Forms.Label label3;
		private System.Windows.Forms.Label label1;
		private System.Windows.Forms.TextBox textBox1;
		private System.Windows.Forms.Label label5;
		private System.Windows.Forms.StatusBar statusBar1;
		private System.Windows.Forms.StatusBarPanel sbLeftCal;
		private System.Windows.Forms.StatusBarPanel sbRightCal;

		/// <summary>
		/// Required designer variable.
		/// </summary>
		private System.ComponentModel.Container components = null;

		public Form1 mainmenu;
		public System.Windows.Forms.Timer ResponseTimer;		//time before a 'no response'
		public System.Windows.Forms.Timer InterStimDelay;		//time between stims
		public FileInfo outfile;								//output file
		public StreamWriter output;								//output writer
		private ArrayList Stims = new ArrayList();				//list of CLDatas
		private int nCurrentStim = 0;							//number of the current stim
		private CLData CurrentStim = null;						//the current Stim
		private float nCurrentLevel = 70;							//current level
		private int nMin;										//Used when determining the min/max in phase 1
		private int nMax;										//Used when determining the min/max in phase 1
		private Random r;										//a randomizer
		private CatLoudUser dlg = new CatLoudUser();			//the buttons dlg
		public WaveLib.WavePlayer player = new WaveLib.WavePlayer();//audio
		private int nButtons = 11;								//the number of buttons
		private int nPhase = 0;									//what phase are we in,0, 1, 3, or 4
		//0 is waiting for that first response
		//1 is finding min/max
		//two is finding first four interped points
		//three is finding midpoints
		//four is double checking and getting more data

		public CatLoud2()
		{
			//
			// Required for Windows Form Designer support
			//
			InitializeComponent();

			this.Closing += new CancelEventHandler(CatLoud2_Closing);
		}

		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		protected override void Dispose( bool disposing )
		{
			if( disposing )
			{
				if(components != null)
				{
					components.Dispose();
				}
			}
			base.Dispose( disposing );
		}

		#region Windows Form Designer generated code
		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{
			System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(CatLoud2));
			this.btnSkip = new System.Windows.Forms.Button();
			this.txtMax = new System.Windows.Forms.TextBox();
			this.txtMin = new System.Windows.Forms.TextBox();
			this.txtLevel = new System.Windows.Forms.TextBox();
			this.txtPrimary = new System.Windows.Forms.TextBox();
			this.label4 = new System.Windows.Forms.Label();
			this.label2 = new System.Windows.Forms.Label();
			this.panel1 = new System.Windows.Forms.Panel();
			this.label3 = new System.Windows.Forms.Label();
			this.label1 = new System.Windows.Forms.Label();
			this.textBox1 = new System.Windows.Forms.TextBox();
			this.label5 = new System.Windows.Forms.Label();
			this.statusBar1 = new System.Windows.Forms.StatusBar();
			this.sbLeftCal = new System.Windows.Forms.StatusBarPanel();
			this.sbRightCal = new System.Windows.Forms.StatusBarPanel();
			((System.ComponentModel.ISupportInitialize)(this.sbLeftCal)).BeginInit();
			((System.ComponentModel.ISupportInitialize)(this.sbRightCal)).BeginInit();
			this.SuspendLayout();
			// 
			// btnSkip
			// 
			this.btnSkip.Location = new System.Drawing.Point(8, 135);
			this.btnSkip.Name = "btnSkip";
			this.btnSkip.TabIndex = 33;
			this.btnSkip.Text = "Skip to 2";
			// 
			// txtMax
			// 
			this.txtMax.Location = new System.Drawing.Point(168, 103);
			this.txtMax.Name = "txtMax";
			this.txtMax.ReadOnly = true;
			this.txtMax.Size = new System.Drawing.Size(240, 20);
			this.txtMax.TabIndex = 32;
			this.txtMax.Text = "";
			// 
			// txtMin
			// 
			this.txtMin.Location = new System.Drawing.Point(168, 79);
			this.txtMin.Name = "txtMin";
			this.txtMin.ReadOnly = true;
			this.txtMin.Size = new System.Drawing.Size(240, 20);
			this.txtMin.TabIndex = 30;
			this.txtMin.Text = "";
			// 
			// txtLevel
			// 
			this.txtLevel.Location = new System.Drawing.Point(168, 55);
			this.txtLevel.Name = "txtLevel";
			this.txtLevel.ReadOnly = true;
			this.txtLevel.Size = new System.Drawing.Size(240, 20);
			this.txtLevel.TabIndex = 27;
			this.txtLevel.Text = "";
			// 
			// txtPrimary
			// 
			this.txtPrimary.Location = new System.Drawing.Point(168, 31);
			this.txtPrimary.Name = "txtPrimary";
			this.txtPrimary.ReadOnly = true;
			this.txtPrimary.Size = new System.Drawing.Size(240, 20);
			this.txtPrimary.TabIndex = 26;
			this.txtPrimary.Text = "";
			// 
			// label4
			// 
			this.label4.Location = new System.Drawing.Point(8, 103);
			this.label4.Name = "label4";
			this.label4.Size = new System.Drawing.Size(160, 23);
			this.label4.TabIndex = 31;
			this.label4.Text = "Max Level:";
			this.label4.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
			// 
			// label2
			// 
			this.label2.Location = new System.Drawing.Point(8, 79);
			this.label2.Name = "label2";
			this.label2.Size = new System.Drawing.Size(160, 23);
			this.label2.TabIndex = 29;
			this.label2.Text = "Min Level:";
			this.label2.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
			// 
			// panel1
			// 
			this.panel1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
				| System.Windows.Forms.AnchorStyles.Left) 
				| System.Windows.Forms.AnchorStyles.Right)));
			this.panel1.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
			this.panel1.Location = new System.Drawing.Point(280, 135);
			this.panel1.Name = "panel1";
			this.panel1.Size = new System.Drawing.Size(504, 400);
			this.panel1.TabIndex = 28;
			// 
			// label3
			// 
			this.label3.Location = new System.Drawing.Point(8, 55);
			this.label3.Name = "label3";
			this.label3.Size = new System.Drawing.Size(160, 23);
			this.label3.TabIndex = 25;
			this.label3.Text = "Primary Stimulus Pres. Level:";
			this.label3.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
			// 
			// label1
			// 
			this.label1.Location = new System.Drawing.Point(8, 31);
			this.label1.Name = "label1";
			this.label1.Size = new System.Drawing.Size(160, 23);
			this.label1.TabIndex = 24;
			this.label1.Text = "Current Primary Stimulus:";
			this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
			// 
			// textBox1
			// 
			this.textBox1.Location = new System.Drawing.Point(168, 8);
			this.textBox1.Name = "textBox1";
			this.textBox1.ReadOnly = true;
			this.textBox1.Size = new System.Drawing.Size(240, 20);
			this.textBox1.TabIndex = 35;
			this.textBox1.Text = "";
			// 
			// label5
			// 
			this.label5.Location = new System.Drawing.Point(8, 8);
			this.label5.Name = "label5";
			this.label5.Size = new System.Drawing.Size(160, 23);
			this.label5.TabIndex = 34;
			this.label5.Text = "Current Function:";
			this.label5.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
			// 
			// statusBar1
			// 
			this.statusBar1.Location = new System.Drawing.Point(0, 544);
			this.statusBar1.Name = "statusBar1";
			this.statusBar1.Panels.AddRange(new System.Windows.Forms.StatusBarPanel[] {
																						  this.sbLeftCal,
																						  this.sbRightCal});
			this.statusBar1.ShowPanels = true;
			this.statusBar1.Size = new System.Drawing.Size(792, 22);
			this.statusBar1.TabIndex = 36;
			this.statusBar1.Text = "statusBar1";
			// 
			// sbLeftCal
			// 
			this.sbLeftCal.AutoSize = System.Windows.Forms.StatusBarPanelAutoSize.Contents;
			this.sbLeftCal.Text = "statusBarPanel1";
			this.sbLeftCal.Width = 97;
			// 
			// sbRightCal
			// 
			this.sbRightCal.AutoSize = System.Windows.Forms.StatusBarPanelAutoSize.Contents;
			this.sbRightCal.Text = "statusBarPanel1";
			this.sbRightCal.Width = 97;
			// 
			// CatLoud2
			// 
			this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
			this.ClientSize = new System.Drawing.Size(792, 566);
			this.Controls.Add(this.statusBar1);
			this.Controls.Add(this.textBox1);
			this.Controls.Add(this.label5);
			this.Controls.Add(this.btnSkip);
			this.Controls.Add(this.txtMax);
			this.Controls.Add(this.txtMin);
			this.Controls.Add(this.txtLevel);
			this.Controls.Add(this.txtPrimary);
			this.Controls.Add(this.label4);
			this.Controls.Add(this.label2);
			this.Controls.Add(this.panel1);
			this.Controls.Add(this.label3);
			this.Controls.Add(this.label1);
			this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
			this.Name = "CatLoud2";
			this.Text = "Categorical Loudness";
			((System.ComponentModel.ISupportInitialize)(this.sbLeftCal)).EndInit();
			((System.ComponentModel.ISupportInitialize)(this.sbRightCal)).EndInit();
			this.ResumeLayout(false);

		}
		#endregion

		private void CatLoud2_Closing(object sender, CancelEventArgs e)
		{
			player.Close();
			if(dlg!=null)
				dlg.Close();
			GC.Collect();
			mainmenu.Show();
		}
		public void Init()
		{
			r = new Random(DateTime.Now.Millisecond);

			ResponseTimer = new Timer();
			ResponseTimer.Interval = mainmenu.def.nTimer;
			ResponseTimer.Tick += new EventHandler(ResponseTimer_Tick);
			
			InterStimDelay = new Timer();
			InterStimDelay.Interval = (int) (mainmenu.def.nDelay+r.NextDouble()*mainmenu.def.nJitter);
			InterStimDelay.Tick += new EventHandler(InterStimDelay_Tick);

			sbLeftCal.Text = mainmenu.GetLCal();
			sbRightCal.Text = mainmenu.GetRCal();
            
			InitStims();
			InitOutput();
			InitUser();
			this.Show();
			DialogResult res = MessageBox.Show(this,"Click 'OK' when you are ready to begin, or 'Cancel' to abort!","Ready?",MessageBoxButtons.OKCancel,MessageBoxIcon.Information);
			if(res == DialogResult.OK)
				Start();
			else
				this.Close();
		}
		private void InitStims()
		{
			try
			{
				CLData dat;
				foreach(Stim a in mainmenu.def.PrimaryStims)
				{
					dat = new CLData();
					dat.s = new Stim();
					if(mainmenu.def.bFrequencyShaping==false)
					{
						dat.s = a.Clone();
						dat.s.strEar = a.strEar;
						dat.s.nFreq = a.nFreq;
						dat.s.buffer = new WaveBuffer();
						mainmenu.CreateStim(ref dat.s);
					}
					else
					{
						FileInfo f = new FileInfo(mainmenu.def.strStimDirectory+dat.s.strFile);
						int V2 = mainmenu.GetV2(a.nOrigin,1000,"both");
						WaveBuffer bt = SigPro.FreqShape(f,mainmenu.def.LAtten,mainmenu.def.LFreqs,mainmenu.def.RAtten,mainmenu.def.RFreqs,V2);
						dat.s.buffer.SetMS(bt.ms, "both");
					}
					dat.s.buffer.AmplificationType = dat.s.AmpType;
					Stims.Add(dat);
				}
				if(mainmenu.def.bRandom==true)
				{
					//randomize Stims
					SortedList temp = new SortedList();
					foreach(CLData d in Stims)
					{
						temp.Add(r.Next(1000000),d);
					}
					Stims.Clear();
					foreach(DictionaryEntry de in temp)
					{
						Stims.Add(de.Value);
					}
				}
			}
			catch(Exception err)
			{ 
				Form1.ErrorMsg(err.Message);
				return;
			}
		}

		private void InitOutput()
		{
			output = new StreamWriter(outfile.ToString(),true);
			output.WriteLine("%CATEGORICAL LOUDNESS RESULTS");
			output.WriteLine("%test revised 7/07");
			output.WriteLine(string.Empty);
			output.WriteLine("%SUBJECT DATA");
			output.WriteLine("%"+mainmenu.txtName.Text);
			output.WriteLine("%"+mainmenu.txtBirth.Text);
			output.WriteLine("%"+mainmenu.cmbGender.Text);
			output.WriteLine("%"+mainmenu.txtGroup.Text);
			output.WriteLine("%"+mainmenu.txtId.Text);
			output.WriteLine(string.Empty);
			output.WriteLine("%Definition File: "+mainmenu.def.strInitFile);
			output.WriteLine("%StimuliDirectory: "+mainmenu.def.strStimDirectory);
			output.WriteLine("%"+DateTime.Now.ToShortDateString());
			output.WriteLine("%"+DateTime.Now.ToShortTimeString());
			output.WriteLine(string.Empty);
			output.WriteLine("Calibration: "+mainmenu.GetCal());
			output.WriteLine(string.Empty);
			if(mainmenu.txtBirth.Text.Length>0)
			{
				try
				{
					DateTime dtBirth = DateTime.Parse(mainmenu.txtBirth.Text);
					
					TimeSpan sp = DateTime.Now.Subtract(dtBirth);
					double age = sp.Days/365.25;
					int yrs = (int) age;
					int mos = (int) ((age-yrs)*12);
					output.WriteLine("%"+yrs.ToString() + ";" + mos.ToString());
				}
				catch(Exception){}
			}
			output.WriteLine(string.Empty);

			output.WriteLine("%"+"STIMULI");
			
			foreach(Stim s in mainmenu.def.PrimaryStims)
			{
				output.WriteLine("%"+s.strText);
			}
			output.WriteLine(string.Empty);
			output.WriteLine("---------------------------------------------------------");
			output.WriteLine(string.Empty);
			output.Flush();
			output.Close();
		}
		private void InitUser()
		{
			dlg.Show();
#if !DEBUG
			if(mainmenu.OptSingleScreen.Checked == false)
				dlg.Location = new Point(1220,-4);
#endif
			dlg.CreateButtons(nButtons);
			dlg.ButtonEvt += new HearingAidLab.CatLoudUser.ButtonEventHandler(dlg_ButtonEvt);
			
		}



		private void Start()
		{
			//Start
			if(GetNextStim()==true)
				PresentStim();
			ResponseTimer.Start();
		}
		private bool GetNextStim()
		{
			try
			{
				if(nCurrentStim>=Stims.Count)
					return false;
				CurrentStim = (CLData) Stims[nCurrentStim];
				nCurrentLevel = CurrentStim.s.nOrigin;
				if(CurrentStim.s.strType=="wave")
					txtPrimary.Text = CurrentStim.s.strFile;
				else
					txtPrimary.Text = CurrentStim.s.nFreq.ToString() + "  " + CurrentStim.s.strType;
			}
			catch(Exception err)
			{
				Form1.ErrorMsg(err.Message);
				return false;
			}
			output = new StreamWriter(outfile.ToString(),true);
			output.WriteLine("%PHASE 1 - DETERMINE MIN/MAX");
			output.WriteLine("Stimulus: {0}",this.txtPrimary.Text);
			output.WriteLine(string.Empty);
			output.WriteLine("Stimulus, Level(dB), Loudness Assigned");
			output.Flush();
			output.Close();
			return true;
		}
		private void PresentStim()
		{
			dlg.LightListen();
			//Set Level
			txtLevel.Text = nCurrentLevel.ToString();
			int V2 = GetPrimaryLevel();
			player.Signals[0] = CurrentStim.s.buffer;
			player.Signals[0].SetLevel((int) V2);
			player.Signals[0].Play();
			//dlg.Show();
			player.Play();
			//Play it
			dlg.LightRespond();
		}
		private int GetPrimaryLevel()
		{
			int V2 = 0;
			if(CurrentStim.s.strType=="wave")
			{
				//set level
				double d = mainmenu.CalDb;
				if(nCurrentLevel>mainmenu.def.nMaxLevel)
					nCurrentLevel = mainmenu.def.nMaxLevel;
				double fLevel = nCurrentLevel - d;
				V2 = (int) (mainmenu.MaxAmplitude*(Math.Pow(10,fLevel/20)) );
				if(V2>mainmenu.MaxAmplitude)
					V2 = mainmenu.MaxAmplitude;
			}
			else if(CurrentStim.s.strType!="wave")
			{
				//only if it is not a wave
				V2 = mainmenu.GetV2(nCurrentLevel,CurrentStim.s.nFreq,CurrentStim.s.strEar);
			}
			return V2;
		}
		

		
		private void dlg_ButtonEvt(object sender, EventArgs e)
		{
		}
		private void ResponseTimer_Tick(object sender, EventArgs e)
		{

		}
		private void InterStimDelay_Tick(object sender, EventArgs e)
		{
			InterStimDelay.Stop();
			InterStimDelay.Enabled = false;
			//PresentStim();
		}

		
	}
}
