using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Diagnostics;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters;
using System.Runtime.Serialization.Formatters.Binary;
using System.Drawing.Text;
using System.IO;
using Microsoft.Ink;
using SpeechLib;

namespace MathSpeakWrite
{
	enum CBMode
	{
		Edit, Insert
	}

	/// <summary>
	/// Summary description for Form1.
	/// </summary>
	public class CBMainWin : System.Windows.Forms.Form
	{

		
		private bool lastWasHex = false;
		private ColorBoxRDB lastCB;
		private RelDrawingBase selectedRDB;
		private RootRDB daRoot;
		private InkCollector myInkCollector = null;
		private CBMode gMode;
		private Timer daTimer;
		private int int_count;
		private bool wasDown=false;
		private AltsWindow aAW;
		private SymbolData SD_upper, SD_lower, SD_NumSym;
		public string upperPath = "AllUpper.txt", lowerPath = "AllLower.txt", nsPath ="AllNumSym.txt";
		public string iconPath = "SpeakWriteIcon.ico";
		public string startingDir;
		private ArrayList undoStates = new ArrayList();
		private ArrayList redoStates = new ArrayList();
		private static int MaxTOs = 3;

		public String dataPath ="data\\"; //Path to training data
		private static int TimerInt = 100;

		/// <summary>
		/// Required designer variable.
		/// </summary>
		private System.ComponentModel.Container components = null;
		private SpSharedRecoContext objRecoContext;
		private ISpeechRecoGrammar grammar;
		private System.Windows.Forms.Panel PpandC;
		private System.Windows.Forms.Button B_ClearScreen;
		private System.Windows.Forms.MainMenu mainMenu1;
		private System.Windows.Forms.MenuItem FileMenu;
		private System.Windows.Forms.MenuItem mi_Quit;
		private System.Windows.Forms.MenuItem mi_Fonts;
		private System.Windows.Forms.Button bEdit;
		private System.Windows.Forms.MenuItem mi_TextDescription;//Lastobj = last guy with text, clicked == clicked color box
		private System.Windows.Forms.Button b_Deselect;
		private System.Windows.Forms.MenuItem m_Handwriting;
		private System.Windows.Forms.MenuItem mi_CITEnable;
		private System.Windows.Forms.MenuItem mi_Enabled;
		private System.Windows.Forms.Button Undo;
		private System.Windows.Forms.MenuItem mi_TrainLaunchTraining;
		private System.Windows.Forms.Button Redo;
		private System.Windows.Forms.MenuItem mi_TexTranslation;
		private System.Windows.Forms.MenuItem miTexPDF;
		private System.Windows.Forms.MenuItem mimathML;
		private System.Windows.Forms.MenuItem miSpeech;
		private System.Windows.Forms.MenuItem miDebug;
		private System.Windows.Forms.MenuItem miSave;
		private System.Windows.Forms.MenuItem menuItem1;
		private System.Windows.Forms.MenuItem mi_contents;
		private System.Windows.Forms.MenuItem mi_RegTest;
		private System.Windows.Forms.MenuItem mi_pointMatchTest;
		private System.Windows.Forms.MenuItem miLoad; //Interrupt for timer every 100 ms
		


		/// <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()
		{
			this.PpandC = new System.Windows.Forms.Panel();
			this.B_ClearScreen = new System.Windows.Forms.Button();
			this.mainMenu1 = new System.Windows.Forms.MainMenu();
			this.FileMenu = new System.Windows.Forms.MenuItem();
			this.miLoad = new System.Windows.Forms.MenuItem();
			this.miSave = new System.Windows.Forms.MenuItem();
			this.miTexPDF = new System.Windows.Forms.MenuItem();
			this.mimathML = new System.Windows.Forms.MenuItem();
			this.mi_Quit = new System.Windows.Forms.MenuItem();
			this.m_Handwriting = new System.Windows.Forms.MenuItem();
			this.mi_CITEnable = new System.Windows.Forms.MenuItem();
			this.mi_TrainLaunchTraining = new System.Windows.Forms.MenuItem();
			this.miSpeech = new System.Windows.Forms.MenuItem();
			this.mi_Enabled = new System.Windows.Forms.MenuItem();
			this.miDebug = new System.Windows.Forms.MenuItem();
			this.mi_Fonts = new System.Windows.Forms.MenuItem();
			this.mi_TextDescription = new System.Windows.Forms.MenuItem();
			this.mi_TexTranslation = new System.Windows.Forms.MenuItem();
			this.mi_RegTest = new System.Windows.Forms.MenuItem();
			this.mi_pointMatchTest = new System.Windows.Forms.MenuItem();
			this.menuItem1 = new System.Windows.Forms.MenuItem();
			this.mi_contents = new System.Windows.Forms.MenuItem();
			this.bEdit = new System.Windows.Forms.Button();
			this.b_Deselect = new System.Windows.Forms.Button();
			this.Undo = new System.Windows.Forms.Button();
			this.Redo = new System.Windows.Forms.Button();
			this.SuspendLayout();
			// 
			// PpandC
			// 
			this.PpandC.AutoScroll = true;
			this.PpandC.AutoScrollMinSize = new System.Drawing.Size(800, 0);
			this.PpandC.BackColor = System.Drawing.Color.LightSteelBlue;
			this.PpandC.Location = new System.Drawing.Point(8, 8);
			this.PpandC.Name = "PpandC";
			this.PpandC.Size = new System.Drawing.Size(472, 384);
			this.PpandC.TabIndex = 0;
			this.PpandC.Paint += new System.Windows.Forms.PaintEventHandler(this.PpandC_Paint);
			// 
			// B_ClearScreen
			// 
			this.B_ClearScreen.Location = new System.Drawing.Point(8, 400);
			this.B_ClearScreen.Name = "B_ClearScreen";
			this.B_ClearScreen.Size = new System.Drawing.Size(88, 24);
			this.B_ClearScreen.TabIndex = 1;
			this.B_ClearScreen.Text = "Clear Screen";
			this.B_ClearScreen.Click += new System.EventHandler(this.bClearScreen_Click);
			// 
			// mainMenu1
			// 
			this.mainMenu1.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
																					  this.FileMenu,
																					  this.m_Handwriting,
																					  this.miSpeech,
																					  this.miDebug,
																					  this.menuItem1});
			// 
			// FileMenu
			// 
			this.FileMenu.Index = 0;
			this.FileMenu.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
																					 this.miLoad,
																					 this.miSave,
																					 this.miTexPDF,
																					 this.mimathML,
																					 this.mi_Quit});
			this.FileMenu.Text = "File";
			this.FileMenu.Click += new System.EventHandler(this.FileMenu_Click);
			// 
			// miLoad
			// 
			this.miLoad.Index = 0;
			this.miLoad.Text = "Load";
			this.miLoad.Click += new System.EventHandler(this.mi_Load_Click);
			// 
			// miSave
			// 
			this.miSave.Index = 1;
			this.miSave.Text = "Save";
			this.miSave.Click += new System.EventHandler(this.mi_Save_Click);
			// 
			// miTexPDF
			// 
			this.miTexPDF.Index = 2;
			this.miTexPDF.Text = "Save As Tex and PDF";
			this.miTexPDF.Click += new System.EventHandler(this.mi_TexPDF_Click);
			// 
			// mimathML
			// 
			this.mimathML.Index = 3;
			this.mimathML.Text = "Save As MathML";
			this.mimathML.Click += new System.EventHandler(this.mi_mathML_Click);
			// 
			// mi_Quit
			// 
			this.mi_Quit.Index = 4;
			this.mi_Quit.Text = "Quit";
			this.mi_Quit.Click += new System.EventHandler(this.mi_Quit_Click);
			// 
			// m_Handwriting
			// 
			this.m_Handwriting.Index = 1;
			this.m_Handwriting.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
																						  this.mi_CITEnable,
																						  this.mi_TrainLaunchTraining});
			this.m_Handwriting.Text = "Handwriting";
			// 
			// mi_CITEnable
			// 
			this.mi_CITEnable.Index = 0;
			this.mi_CITEnable.Text = "Enable Handwriting";
			this.mi_CITEnable.Click += new System.EventHandler(this.mi_CITEnable_Click);
			// 
			// mi_TrainLaunchTraining
			// 
			this.mi_TrainLaunchTraining.Index = 1;
			this.mi_TrainLaunchTraining.Text = "Train Handwriting";
			this.mi_TrainLaunchTraining.Click += new System.EventHandler(this.mi_TrainLaunchTraining_Click);
			// 
			// miSpeech
			// 
			this.miSpeech.Index = 2;
			this.miSpeech.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
																					 this.mi_Enabled});
			this.miSpeech.Text = "Speech";
			// 
			// mi_Enabled
			// 
			this.mi_Enabled.Checked = true;
			this.mi_Enabled.Index = 0;
			this.mi_Enabled.Text = "Enable Speech Recognition";
			this.mi_Enabled.Click += new System.EventHandler(this.mi_VoiceEnable_Click);
			// 
			// miDebug
			// 
			this.miDebug.Index = 3;
			this.miDebug.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
																					this.mi_Fonts,
																					this.mi_TextDescription,
																					this.mi_TexTranslation,
																					this.mi_RegTest,
																					this.mi_pointMatchTest});
			this.miDebug.Text = "Debugging";
			// 
			// mi_Fonts
			// 
			this.mi_Fonts.Index = 0;
			this.mi_Fonts.Text = "Installed Fonts";
			this.mi_Fonts.Click += new System.EventHandler(this.mi_Fonts_Click);
			// 
			// mi_TextDescription
			// 
			this.mi_TextDescription.Index = 1;
			this.mi_TextDescription.Text = "Text Description";
			this.mi_TextDescription.Click += new System.EventHandler(this.mi_TextDescription_Click);
			// 
			// mi_TexTranslation
			// 
			this.mi_TexTranslation.Index = 2;
			this.mi_TexTranslation.Text = "Tex Translation";
			this.mi_TexTranslation.Click += new System.EventHandler(this.mi_TexTranslation_Click);
			// 
			// mi_RegTest
			// 
			this.mi_RegTest.Index = 3;
			this.mi_RegTest.Text = "Regression Test";
			this.mi_RegTest.Click += new System.EventHandler(this.mi_RegTest_Click);
			// 
			// mi_pointMatchTest
			// 
			this.mi_pointMatchTest.Index = 4;
			this.mi_pointMatchTest.Text = "Point Match Reg Test";
			this.mi_pointMatchTest.Click += new System.EventHandler(this.miPointMatchTest_Click);
			// 
			// menuItem1
			// 
			this.menuItem1.Index = 4;
			this.menuItem1.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
																					  this.mi_contents});
			this.menuItem1.Text = "Help";
			// 
			// mi_contents
			// 
			this.mi_contents.Index = 0;
			this.mi_contents.Text = "Contents";
			this.mi_contents.Click += new System.EventHandler(this.mi_contents_Click);
			// 
			// bEdit
			// 
			this.bEdit.Location = new System.Drawing.Point(200, 400);
			this.bEdit.Name = "bEdit";
			this.bEdit.Size = new System.Drawing.Size(88, 24);
			this.bEdit.TabIndex = 5;
			this.bEdit.Text = "Edit";
			this.bEdit.Click += new System.EventHandler(this.b_Edit_Click);
			// 
			// b_Deselect
			// 
			this.b_Deselect.Location = new System.Drawing.Point(104, 400);
			this.b_Deselect.Name = "b_Deselect";
			this.b_Deselect.Size = new System.Drawing.Size(88, 24);
			this.b_Deselect.TabIndex = 6;
			this.b_Deselect.Text = "Deselect All";
			this.b_Deselect.Click += new System.EventHandler(this.b_Deselect_Click);
			// 
			// Undo
			// 
			this.Undo.Location = new System.Drawing.Point(296, 400);
			this.Undo.Name = "Undo";
			this.Undo.Size = new System.Drawing.Size(88, 24);
			this.Undo.TabIndex = 7;
			this.Undo.Text = "Undo";
			this.Undo.Click += new System.EventHandler(this.b_Undo_Click);
			// 
			// Redo
			// 
			this.Redo.Location = new System.Drawing.Point(392, 400);
			this.Redo.Name = "Redo";
			this.Redo.Size = new System.Drawing.Size(88, 24);
			this.Redo.TabIndex = 8;
			this.Redo.Text = "Redo";
			this.Redo.Click += new System.EventHandler(this.b_Redo_Click);
			// 
			// CBMainWin
			// 
			this.AutoScaleBaseSize = new System.Drawing.Size(6, 13);
			this.ClientSize = new System.Drawing.Size(492, 427);
			this.Controls.Add(this.Redo);
			this.Controls.Add(this.b_Deselect);
			this.Controls.Add(this.bEdit);
			this.Controls.Add(this.B_ClearScreen);
			this.Controls.Add(this.PpandC);
			this.Controls.Add(this.Undo);
			this.Font = new System.Drawing.Font("Bookman Old Style", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
			this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
			this.Menu = this.mainMenu1;
			this.Name = "CBMainWin";
			this.Text = "Math Speak & Write";
			this.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.K_Press);
			this.Load += new System.EventHandler(this.Form1_Load);
			this.ResumeLayout(false);

		}
		#endregion

		/// <summary>
		/// The main entry point for the application.
		/// </summary>
		[STAThread]
		static int Main(string []args) 
		{
			MessageBox.Show("args size = " + args.Length);
			Application.Run(new CBMainWin());

			return 0;
		}
				
		
		
		//Various Functions

		public CBMainWin()
		{
			
			// Required for Windows Form Designer support
			//
			InitializeComponent();
			System.Drawing.Icon ico = new System.Drawing.Icon(iconPath);
			this.Icon = ico ; 

			objRecoContext = new SpSharedRecoContext();
			objRecoContext.Recognition += new _ISpeechRecoContextEvents_RecognitionEventHandler(Reco_Event);

			grammar = objRecoContext.CreateGrammar(0);
			grammar.CmdLoadFromFile("hexSingleTokens.xml", SpeechLoadOption.SLOStatic);
			grammar.CmdSetRuleState("Start", SpeechRuleState.SGDSActive);

			RelDrawingBase.initPFC();
			lastCB =null;
			daRoot = new RootRDB(0, 200);
			gMode = CBMode.Insert;
			selectedRDB = daRoot.aRoot;
			lastCB = (ColorBoxRDB) selectedRDB;

			this.KeyPreview = true;
			selectedRDB.readTexArrays();
			selectedRDB.readMathMLArrays();
			
			this.redefineRelativePaths();
			SD_lower = new SymbolData();
			SD_upper = new SymbolData();
			SD_NumSym = new SymbolData();
			SD_Read();

			this.saveUndoFile();
		}
		
		private void AltsCallBack(string name, string code)
		{
			IFormatter myForm = new BinaryFormatter();
			ArrayList stateInfo = new ArrayList();
			stateInfo.Add(daRoot);
			stateInfo.Add(lastCB);
			stateInfo.Add(selectedRDB);
			MemoryStream aStream = new MemoryStream();
			myForm.Serialize(aStream, stateInfo);

			this.b_Undo_Click(this, null);

			this.textToScreen(code);
			undoStates.Add(aStream);
			this.Focus();
		}

		private void AltsSetup()
		{
			SymbolData [] arr =  new SymbolData[3];
			arr[0] = SD_upper; arr[1] = SD_lower; arr[2] = SD_NumSym;
			
			this.aAW = new AltsWindow(arr, new AltDel(this.AltsCallBack));

			aAW.SetDesktopLocation(this.Location.X + this.Size.Width,this.Location.Y);
			System.Drawing.Icon ico = new System.Drawing.Icon(iconPath);
			aAW.Icon = ico ; 
			this.aAW.Show();
			this.aAW.Focus();
			this.Focus();
		}
		protected void clickFunc(int x, int y)
		{
			Graphics g = PpandC.CreateGraphics();
			RelDrawingBase clickedOn;
			clickedOn = daRoot.intersectsWith(x-PpandC.AutoScrollPosition.X, y, g);

			//On click on this clear ink if it was on a CB
			if(clickedOn == null)
				return;
			else
			{
				//	this.mi_CITEnable_Click(sender, e);
				Console.WriteLine("On UP: Clearing Screen");
				this.mi_ClearInk_Click(null, null);
				Console.WriteLine("On Up: Screen Cleared");
				Console.WriteLine("Num Strokes = " + this.myInkCollector.Ink.Strokes.Count);
			}
			if(clickedOn.GetType() == typeof(ColorBoxRDB))
			{
				gMode = CBMode.Insert;
				lastCB = (ColorBoxRDB)clickedOn;
				//objRecoContext.State = SpeechRecoContextState.SRCS_Enabled;
			}
			else
			{
				gMode = CBMode.Insert;
				
				if(selectedRDB != null)
					selectedRDB.removeNeighborCBs();

				selectedRDB = clickedOn;
				selectedRDB.addNeighborCBs();
				lastCB = null;
			}
			PpandC.Refresh();
		}

		/// <summary>
		/// Adds the current state as a serialized stream to the undoStates ArrayList
		/// so that it can be loaded with a call to Undo_Click at a later time.
		/// </summary>
		private void saveUndoFile()
		{
			IFormatter myForm = new BinaryFormatter();
			ArrayList stateInfo = new ArrayList();
			stateInfo.Add(daRoot);
			stateInfo.Add(lastCB);
			stateInfo.Add(selectedRDB);
			
			MemoryStream aStream = new MemoryStream();
			myForm.Serialize(aStream, stateInfo);
			undoStates.Add(aStream);
		}

		/// <summary>
		/// Adds the current state as a serialized stream to the redoStates ArrayList
		/// so that it can be loaded with a call to Redo_Click at a later time.
		/// </summary>
		private void saveRedoFile()
		{
			IFormatter myForm = new BinaryFormatter();
			ArrayList stateInfo = new ArrayList();
			stateInfo.Add(daRoot);
			stateInfo.Add(lastCB);
			stateInfo.Add(selectedRDB);
			
			MemoryStream aStream = new MemoryStream();
			myForm.Serialize(aStream, stateInfo);
			redoStates.Add(aStream);
		}
		
		/// <summary>
		/// Reads in SymbolData
		/// </summary>
		private void SD_Read()
		{
			SD_lower.ReadData(lowerPath);
			SD_upper.ReadData(upperPath);
			SD_NumSym.ReadData(nsPath);
		}
		

		/// <summary>
		/// A function used to add the text string at the presently selected location on the screen
		/// (based on the selectedRDB and lastCB). 
		/// </summary>
		/// <param name="text"></param>
		private void textToScreen(string text)
		{
			Graphics g = PpandC.CreateGraphics();
			
			if(aAW != null)
				this.aAW.clearAlts();

			if(text == "@")
			{
				lastWasHex = true;
				return;
			}

			if(lastWasHex)
			{
				text = "@" + text;
				lastWasHex = false;
			}
			
			if((text.Length == 3 && (text[0] == '@' && (text[1] == 'a' || text[1] == 'A'))))
			{
				this.aAW.DoAltN((int) char.GetNumericValue(text[2]));
				return;
			}

			this.saveUndoFile();
			redoStates = new ArrayList();

			if(text == "\b" || text == "@E" || text == "@e")
			{
				this.b_Delete_Click(null,  null);
				return;
			}
			if((text == "@b" || text == "@B") && selectedRDB != null && selectedRDB.GetType() == typeof(SymbolRDB))
			{
				SymbolRDB sel = (SymbolRDB) selectedRDB;

				if (sel.isBold())
					sel.makeBold(g, false);
				else
					sel.makeBold(g, true);

				PpandC.Refresh();
				return;
			}
			else if((text == "@i" || text == "@I") && selectedRDB != null && selectedRDB.GetType() == typeof(SymbolRDB))
			{
				SymbolRDB sel = (SymbolRDB) selectedRDB;

				if (sel.isItalic())
					sel.makeItalic(g, false);
				else
					sel.makeItalic(g, true);

				PpandC.Refresh();
				return;
			}
			else if((text == "@u" || text == "@U") && selectedRDB != null && selectedRDB.GetType() == typeof(SymbolRDB))
			{
				SymbolRDB sel = (SymbolRDB) selectedRDB;

				if (sel.isUnderline())
					sel.makeUnderline(g, false);
				else
					sel.makeUnderline(g, true);

				PpandC.Refresh();
				return;
			}

			if(gMode == CBMode.Edit)
			{
				if(selectedRDB !=null && selectedRDB.GetType() != typeof(ColorBoxRDB))
				{
					RelDrawingBase newRDBs;
					selectedRDB.removeNeighborCBs();
					newRDBs = RelDrawingBase.addWithStr(text, new ColorBoxRDB(null, selectedRDB.parents), null, g);

					if(newRDBs != null)
					{
						selectedRDB.replaceSelfWith(newRDBs.listGetRoot().next, newRDBs);
						selectedRDB = newRDBs;
						selectedRDB.addNeighborCBs();
					}
					this.gMode = CBMode.Insert;
				}
			}
			else if (gMode == CBMode.Insert)
			{
				if(lastCB == null && selectedRDB !=null  &&selectedRDB.next != null && 
					selectedRDB.next.GetType() == typeof(ColorBoxRDB))
					lastCB = (ColorBoxRDB)selectedRDB.next;
				if(lastCB !=null)
				{
					RelDrawingBase old = selectedRDB;
					if(selectedRDB !=null && selectedRDB.GetType() != typeof(ColorBoxRDB))
						selectedRDB = RelDrawingBase.addWithStr(text, selectedRDB, lastCB, g);
					else
						selectedRDB = RelDrawingBase.addWithStr(text, null, lastCB, g);
					if(selectedRDB == null)
					{
						selectedRDB = old;
						return;
					}
					daRoot.aRoot = selectedRDB.listGetRoot();
					
					lastCB = null;
					if(old != null)
						old.removeNeighborCBs();
					selectedRDB.addNeighborCBs();
				}
			}
			PpandC.Refresh();
		}


		/// <summary>
		/// Used to make the relative paths to various files absolute
		/// </summary>
		public void redefineRelativePaths()
		{
			char[] excluders = {':'};

			if(upperPath.IndexOfAny(excluders)== -1)
			{
				string curdir = Directory.GetCurrentDirectory() + '\\';
				this.upperPath = curdir + upperPath;
				this.lowerPath = curdir + lowerPath;
				this.nsPath = curdir + nsPath;
				this.dataPath = curdir + dataPath;
				this.iconPath = curdir + iconPath;
				this.startingDir = Directory.GetCurrentDirectory();
			}
		}

		/*EVENT HANDLERS*/
		/// <summary>
		/// Deletes the present expression and creates a new empty expression
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void bClearScreen_Click(object sender, System.EventArgs e)
		{
			daRoot = new RootRDB(0, 200);
			selectedRDB = daRoot.aRoot;
			lastCB = (ColorBoxRDB) daRoot.aRoot;
			PpandC.Refresh();
		}

		/// <summary>
		/// Deletes the presently selected RDB
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void b_Delete_Click(object sender, System.EventArgs e)
		{
			//this.saveRedoFile();
			this.saveUndoFile();
			redoStates = new ArrayList();
			if(selectedRDB == daRoot.aRoot && selectedRDB.GetType() != typeof(ColorBoxRDB))
			{
				if(selectedRDB.next != null && selectedRDB.next.next == null)
				{
					daRoot.aRoot = selectedRDB.next;
					daRoot.aRoot.prev = null;
					selectedRDB = daRoot.aRoot;
					lastCB = (ColorBoxRDB) selectedRDB;
				}
				else
				{
					daRoot.aRoot.removeNeighborCBs();
					daRoot.aRoot = selectedRDB.next;
					daRoot.aRoot.prev = null;
					selectedRDB = daRoot.aRoot;
					selectedRDB.addNeighborCBs();
					lastCB = (ColorBoxRDB) selectedRDB.next;
				}
			}
			else if(selectedRDB != null)
			{
				RelDrawingBase old = selectedRDB;
				selectedRDB = old.prev;
				old.deleteSelf();
				if(selectedRDB != null)
					selectedRDB.addNeighborCBs();
			}
			PpandC.Refresh();
		}
		
		/// <summary>
		/// Deselects the presently selectedRDB (IE: turns all Colorboxes off and sets 
		/// the selectRDB and lastCB to null)
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void b_Deselect_Click(object sender, System.EventArgs e)
		{
			if(selectedRDB != null)
			{
				selectedRDB.removeNeighborCBs();
				selectedRDB = null;
				lastCB = null;
				PpandC.Refresh();
			}
		}

		/// <summary>
		/// Instructs the program to enter edit mode for the next input. The next entry
		/// will replace that in the selectedRDB
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void b_Edit_Click(object sender, System.EventArgs e)
		{
			if(selectedRDB != null && selectedRDB.GetType() != typeof(ColorBoxRDB))
			{
				this.gMode = CBMode.Edit;
				//		objRecoContext.State = SpeechRecoContextState.SRCS_Enabled;
			}
		}
	
		/// <summary>
		/// Loads the previously saved redo state from the redoStates ArrayList
		/// and saves the current state in the undo array.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void b_Redo_Click(object sender, System.EventArgs e)
		{
			IFormatter myForm = new BinaryFormatter();
			if (redoStates.Count < 1)
				return;
			saveUndoFile();
			MemoryStream aStream = (MemoryStream) redoStates[redoStates.Count - 1];

			aStream.Seek(0,0);
			ArrayList stateInfo = (ArrayList) myForm.Deserialize(aStream);
			
			daRoot = (RootRDB) stateInfo[0];
			lastCB = (ColorBoxRDB) stateInfo[1];
			selectedRDB = (RelDrawingBase) stateInfo[2];

			redoStates.RemoveAt(redoStates.Count - 1);
			PpandC.Refresh();
			if (this.aAW != null)
				this.aAW.clearAlts();
		
		}

		/// <summary>
		/// Loads the previosuly saved undo state from the undoStates ArrayList
		/// and saves the current state in the redo array.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void b_Undo_Click(object sender, System.EventArgs e)
		{
			IFormatter myForm = new BinaryFormatter();
			if (undoStates.Count < 1)
				return;
			saveRedoFile();
			MemoryStream aStream = (MemoryStream) undoStates[undoStates.Count - 1];

			aStream.Seek(0,0);
			ArrayList stateInfo = (ArrayList) myForm.Deserialize(aStream);
			
			daRoot = (RootRDB) stateInfo[0];
			lastCB = (ColorBoxRDB) stateInfo[1];
			selectedRDB = (RelDrawingBase) stateInfo[2];

			undoStates.RemoveAt(undoStates.Count - 1);
			PpandC.Refresh();
			if (this.aAW != null)
				this.aAW.clearAlts();
		}

		private void Form1_Load(object sender, System.EventArgs e)
		{
			PpandC.MouseUp += new MouseEventHandler(OnUp);

			this.myInkCollector = new InkCollector(PpandC.Handle);
			this.myInkCollector.Stroke += new InkCollectorStrokeEventHandler(I_strokeHandler);
			this.myInkCollector.MouseUp += new InkCollectorMouseUpEventHandler(this.I_mouseUpHandler);
			daTimer = new Timer();
			daTimer.Interval = TimerInt;
			daTimer.Tick += new EventHandler(this.T_TickEventHandler);
			CITHandwriting.setupRecognition(dataPath);

			//Enable Handwriting/Disable Speech
			mi_CITEnable_Click(sender, e);
			mi_VoiceEnable_Click(sender,e);
		}
		
		/// <summary>
		/// Our clickhandler
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void I_mouseUpHandler(object sender, CancelMouseEventArgs e)
		{
			this.clickFunc(e.X, e.Y);
		}

		/// <summary>
		/// After a stroke is complete, reset the timer function's timer
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void I_strokeHandler(object sender, InkCollectorStrokeEventArgs e)
		{
			int_count =0;
		}
		
		/// <summary>
		/// On a keystroke add its text
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void K_Press(object sender, System.Windows.Forms.KeyPressEventArgs e)
		{

			textToScreen(e.KeyChar.ToString());
		}

		/// <summary>
		/// Toogles CIT handwriting on and off
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void mi_CITEnable_Click(object sender, System.EventArgs e)
		{
			this.myInkCollector.Enabled = !this.myInkCollector.Enabled;
			this.mi_CITEnable.Checked = this.myInkCollector.Enabled;
			if(this.myInkCollector.Enabled)
			{				
				
				this.daTimer.Start();
				this.AltsSetup();
			}
			else
			{
				this.daTimer.Stop();
				this.aAW.Close();
				this.aAW = null;
			}
		}
		
		/// <summary>
		/// Clears all rendered ink from the screen
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void mi_ClearInk_Click(object sender, System.EventArgs e)
		{
			Console.WriteLine("ClearInk: Deleting Strokes");
			if(myInkCollector != null && myInkCollector.Ink.Strokes != null && myInkCollector.Ink.Strokes.Count > 0
				&& myInkCollector.CollectingInk == false)
				myInkCollector.Ink.DeleteStrokes();
			else
				Console.WriteLine("Was unable to Clear screen");

			Console.WriteLine("ClearInk: Strokes Deleted");
			PpandC.Invalidate();
			PpandC.Update();
		}

		/// <summary>
		/// Turns voice on and off
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void mi_VoiceEnable_Click(object sender, System.EventArgs e)
		{
			if(mi_Enabled.Checked == false)
				objRecoContext.State = SpeechRecoContextState.SRCS_Enabled;
			else
				objRecoContext.State = SpeechRecoContextState.SRCS_Disabled;
			mi_Enabled.Checked = !mi_Enabled.Checked;
		}

		/// <summary>
		/// Lists all fonts
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void mi_Fonts_Click(object sender, System.EventArgs e)
		{
			InstalledFontCollection aIF = new InstalledFontCollection();
			FontFamily[] allFonts = aIF.Families;
			String outstr="";
			int i;

			for(i=0; i < allFonts.Length; i++)
			{
				outstr += allFonts[i].Name + ", ";
			}
			MessageBox.Show(outstr);
		}

		/// <summary>
		/// Loads a previously saved file
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void mi_Load_Click(object sender, System.EventArgs e)
		{
			OpenFileDialog ofd = new OpenFileDialog();
			ofd.DefaultExt = "iMath";
			ofd.Filter = "Math Files (*.iMath) | *.iMath";

			if(ofd.ShowDialog() == DialogResult.OK)
			{
				IFormatter myForm = new BinaryFormatter();
				Stream aStream = new FileStream(ofd.FileName, FileMode.Open);
			
				ArrayList stateInfo = (ArrayList) myForm.Deserialize(aStream);
				daRoot = (RootRDB) stateInfo[0];
				lastCB = (ColorBoxRDB) stateInfo[1];
				selectedRDB = (RelDrawingBase) stateInfo[2];

				aStream.Close();
				PpandC.Refresh();
			}
		}

		/// <summary>
		/// Writes the MathMl version of the current Math Expression to 'mathMLTranslation.html'
		/// and opens the file for the user.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void mi_mathML_Click(object sender, System.EventArgs e)
		{
			SaveFileDialog sdf = new SaveFileDialog();
			sdf.DefaultExt = ".html";
			sdf.Filter = "HTML Files (*.html) | *.html";

			if(sdf.ShowDialog() == DialogResult.OK)
			{

				string result = this.daRoot.aRoot.listConvertToMathML();

				StreamWriter sw = new StreamWriter(sdf.FileName);
				sw.WriteLine("<HTML XMLNS:m=\"http://www.w3.org/1998/Math/MathML\">");
				sw.WriteLine("<HEAD><OBJECT ID=MathPlayer CLASSID=\"clsid:32F66A20-7614-11D4-BD11-00104BD3F987\">");
				sw.WriteLine("</OBJECT><?IMPORT NAMESPACE=\"m\" IMPLEMENTATION=\"#MathPlayer\" ?></HEAD>");
				sw.WriteLine("<BODY>");
				sw.WriteLine("<m:math>");
				sw.WriteLine(result);
				sw.WriteLine("</m:math>");
				sw.WriteLine("</BODY>");
				sw.WriteLine("</HTML>");
				sw.Flush();
				sw.Close();
				string direc = Directory.GetCurrentDirectory();
				//System.Diagnostics.Process.Start("Netscp");
				System.Diagnostics.Process.Start("iexplore", "file://" + sdf.FileName);
			}
		}
		

		/// <summary>
		/// Quits the program
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void mi_Quit_Click(object sender, System.EventArgs e)
		{
			this.Close();
		}

		/// <summary>
		/// Saves the present expression
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void mi_Save_Click(object sender, System.EventArgs e)
		{
			SaveFileDialog sfd = new SaveFileDialog();
			sfd.DefaultExt = "iMath";
			sfd.Filter = "Math Files (*.iMath)|*.iMath";

			if(sfd.ShowDialog(this) == DialogResult.OK)
			{
				IFormatter myForm = new BinaryFormatter();
				Stream aStream = new FileStream(sfd.FileName, FileMode.Create);
				ArrayList stateInfo = new ArrayList();
				stateInfo.Add(daRoot);
				stateInfo.Add(lastCB);
				stateInfo.Add(selectedRDB);

				myForm.Serialize(aStream, stateInfo);
				aStream.Close();
			}
			Directory.SetCurrentDirectory(this.startingDir);
		}
	
		/// <summary>
		/// Displays the text description of the present expression
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void mi_TextDescription_Click(object sender, System.EventArgs e)
		{
			MessageBox.Show(this.daRoot.aRoot.listDebugStr());
		}
		/// <summary>
		/// Calls TexTranslation_Click to write the Tex version of the current math 
		/// expression. This function then used 'pdflatex' to create a pdf and opens that pdf.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void mi_TexPDF_Click(object sender, System.EventArgs e)
		{
			SaveFileDialog sdf = new SaveFileDialog();
			
			if(sdf.ShowDialog(this) == DialogResult.OK)
			{
				char[] delimiters = {'.'};

				string daFN = (sdf.FileName.Split(delimiters))[0];

				string texFN = daFN + ".tex";
				string pdfFN = daFN + ".pdf";
				string logFN = daFN + ".log";
				string auxFN = daFN + ".aux";

				//mi_TexTranslation_Click(sender, e);
				string result = this.daRoot.aRoot.listConvertToTex();
				//MessageBox.Show(result, "TeX Translation");
			
				StreamWriter sw = new StreamWriter(texFN);
				
				sw.WriteLine("\\documentclass{article}");
				sw.WriteLine("\\usepackage {amssymb}");
				sw.WriteLine("\\begin{document}");
				sw.WriteLine("\\begin{math}");
				sw.WriteLine(result);
				sw.WriteLine("\\end{math}");
				sw.WriteLine("\\end{document}");
				sw.Flush();
				sw.Close();
				//call pdflatex on texTranslation.tex and open the pdf
				try
				{
					ProcessStartInfo psi = new ProcessStartInfo("pdflatex", "-interaction=batchmode \""+ texFN+"\"");
					psi.UseShellExecute = true;
					Process p=System.Diagnostics.Process.Start(psi);
					p.WaitForExit();
				}
				catch
				{
					MessageBox.Show("You need to install a latex translator");
				}

				try
				{
					File.Delete(logFN);
					File.Delete(auxFN);
				}
				catch
				{
					MessageBox.Show("Error deleting intermediate files");
				}

				try
				{
					System.Diagnostics.Process.Start(pdfFN);
				}
				catch
				{
					MessageBox.Show("Check the output of pdfLatex, pdf creation failed"); 
				}
				Directory.SetCurrentDirectory(this.startingDir);
			}
		}

		/// <summary>
		/// Writes the Tex version of the current Math Expression to 'texTranslation.tex'
		/// and displays a message box with the tex expression in string format.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void mi_TexTranslation_Click(object sender, System.EventArgs e)
		{
			string result = this.daRoot.aRoot.listConvertToTex();
			MessageBox.Show(result, "TeX Translation");
			
			StreamWriter sw = new StreamWriter("texTranslation.tex");
			sw.WriteLine("\\documentclass{article}");
			sw.WriteLine("\\begin{document}");
			sw.WriteLine("\\begin{math}");
			sw.WriteLine(result);
			sw.WriteLine("\\end{math}");
			sw.WriteLine("\\end{document}");
			sw.Flush();
			sw.Close();
			Directory.SetCurrentDirectory(this.startingDir);
		}

		/// <summary>
		/// Launches the Handwriting trainer
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void mi_TrainLaunchTraining_Click(object sender, System.EventArgs e)
		{
			TrainerMainWin tmw = new TrainerMainWin(SD_NumSym, SD_upper, SD_lower, dataPath, iconPath);
			tmw.ShowDialog();
		}
		/// <summary>
		/// A mouse up handler
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		protected void OnUp(object sender, MouseEventArgs e)
		{
			clickFunc(e.X, e.Y);	
		}

		/// <summary>
		/// Redraws the window
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void PpandC_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
		{
			PpandC.AutoScrollMinSize = new Size((int)daRoot.width(), 0);

			Graphics g = PpandC.CreateGraphics();
			g.Clear(Color.LightSteelBlue);
			//g.TranslateClip(PpandC.AutoScrollPosition.X, PpandC.AutoScrollPosition.Y);
			g.Transform = new Matrix(1,0,0,1,PpandC.AutoScrollPosition.X,PpandC.AutoScrollPosition.Y);
			daRoot.drawAll(g);	
		}
		
		/// <summary>
		/// Event handler for speech recognition events
		/// </summary>
		/// <param name="StreamNum"></param>
		/// <param name="StreamPos"></param>
		/// <param name="RecType"></param>
		/// <param name="res"></param>
		private void Reco_Event(int StreamNum, object StreamPos,
			SpeechRecognitionType RecType, ISpeechRecoResult res)
		{
			String text = res.PhraseInfo.GetText(0, -1, true);
			text = RelDrawingBase.convertTextToNumbers(text);
			this.textToScreen(text);
		}
		
		/// <summary>
		/// Our timer function. Gets called at fixed intervals. If collecting Ink, sees
		/// whether conditions are right for doing recognition. Also makes sure the Alts
		/// Window is minimized/maximized with the main window.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void T_TickEventHandler(object sender, System.EventArgs e)
		{
			if(this.aAW != null)
				this.aAW.WindowState = this.WindowState;
			if(this.myInkCollector.CollectingInk)
			{
				int_count = 0;
				Console.WriteLine("Still Collecting Ink, IC="+int_count);
			}
			else if(int_count >= MaxTOs && this.myInkCollector.Enabled && this.myInkCollector.Ink.Strokes.Count >= 1 && !wasDown)
			{
				Console.WriteLine("Tick Event Handler is Recognizing, ic = "+ int_count);
				string[] alts = CITHandwriting.RecognizeFromInk(this.myInkCollector.Ink.Strokes, PpandC.CreateGraphics(),
					this.myInkCollector);
				mi_ClearInk_Click(sender, e);
				int_count = 0;

				textToScreen(alts[0]);
				this.aAW.changeAlts(alts);
			}
			else if(this.myInkCollector.Ink.Strokes.Count != 0)
				int_count ++;
			else 
				int_count = 0;
		}
		
		/// <summary>
		/// Shows help
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void mi_contents_Click(object sender, System.EventArgs e)
		{
			System.Windows.Forms.Help.ShowHelp(this, "Math Speak And Write Help.chm");
		}

		private void FileMenu_Click(object sender, System.EventArgs e)
		{
		
		}

		private void mi_RegTest_Click(object sender, System.EventArgs e)
		{
			RegTest r = new RegTest(this.dataPath);
			r.testFiles();
		}

		private void miPointMatchTest_Click(object sender, System.EventArgs e)
		{
			HandwritingPointMatch hpm = new HandwritingPointMatch();

			hpm.loadSamplesFromDir(this.dataPath);
			//hpm.regTest(this.dataPath);
			hpm.RegTestRigor(this.dataPath);
		}

	}

	/// <summary>
	///This class is the start of a math expression. In addition to an RDB, it stores
	///initial draw coordinates 
	/// </summary>
	[Serializable]
	public class RootRDB
	{
		public float x, y;
		public RelDrawingBase aRoot;
		
		public RootRDB(float ax, float ay)
		{
			x = ax;
			y = ay;

			aRoot = new ColorBoxRDB(null, 0);
			((ColorBoxRDB)aRoot).drawSelf=true;
		}
		
		/// <summary>
		/// Returns the width of the entire expression
		/// </summary>
		/// <returns></returns>
		public float width()
		{
			return aRoot.listWidth();
		}
		
		/// <summary>
		/// Draws the entire expression
		/// </summary>
		/// <param name="g"></param>
		public void drawAll(Graphics g)
		{
			aRoot.listDraw(x,y,g);
		}

		/// <summary>
		/// Checks for click intersection
		/// </summary>
		/// <param name="click_x"></param>
		/// <param name="click_y"></param>
		/// <param name="g"></param>
		/// <returns></returns>
		public RelDrawingBase intersectsWith(float click_x, float click_y, Graphics g)
		{
			return aRoot.listRDBAtCoords(x, y, click_x, click_y, g);
		}
	}
}