using System;
using System.Drawing;
using System.Runtime.InteropServices;
using Microsoft.Ink;

namespace MathSpeakWrite
{
	/// <summary>
	/// Contains all of the functions of the CIT handwriting class and a couple of helpers
	/// </summary>
	public class CITHandwriting
	{	

		/// <summary>
		/// Returns the length of a C string
		/// </summary>
		/// <param name="aCstr"></param>
		/// <returns></returns>
		public static int CStringLength(char []aCstr)
		{
			int i;

			for(i=0; i < aCstr.Length; i++)
				if(aCstr[i] == '\0')
					return i;
			return i;
		}
		
		/// <summary>
		/// Load's a recognizer from the given path
		/// </summary>
		/// <param name="datapath"></param>
		public static void setupRecognition(string datapath)
		{
			LoadAsRecognizer(datapath.ToCharArray());
		}

		/// <summary>
		/// Given some strokes, recognizes the ink and returns an array of alts
		/// </summary>
		/// <param name="daStrokes"></param>
		/// <param name="g"></param>
		/// <param name="ic"></param>
		/// <returns></returns>
		public static string[] RecognizeFromInk(Strokes daStrokes, Graphics g, InkCollector ic)
		{
			char []buf = new char[128];
			int[] xs; int[] ys;
			String []alts = new String[10];

			xs = xCoordsFromStrokes(daStrokes,g, ic);
			ys = yCoordsFromStrokes(daStrokes,g, ic);
			
			LoadProfWithRec(xs, ys, xs.Length-1);
			for(int i = 0; i < 10; i++)
			{
				if(0==ProfNameOfChoice(i, buf))
				{
					String bufVal = new String(buf, 0, CStringLength(buf));
					alts[i] = bufVal;
				}
			}
			return alts;
		}

		/// <summary>
		/// Gets the x Coordinates of some strokes and returns them in an int array
		/// </summary>
		/// <param name="daStrokes"></param>
		/// <param name="g"></param>
		/// <param name="ic"></param>
		/// <returns></returns>
		public static int[] xCoordsFromStrokes(Strokes daStrokes, Graphics g, InkCollector ic)
		{
			int[] returnme;
			int i, j, totalpoints=0, presindex=0;
			Stroke presStroke;
			Point[] presPoints;
			
			for(i=0; i < daStrokes.Count; i++)
				totalpoints += daStrokes[i].GetPoints().Length + 1;

			returnme = new int[totalpoints];
 
			for(i=0; i < daStrokes.Count; i++)
			{
				presStroke = daStrokes[i];
				presPoints = presStroke.GetPoints();
				ic.Renderer.InkSpaceToPixel(g, ref presPoints);
				for(j=0; j < presPoints.Length; j+=2)
				{
					returnme[presindex] = presPoints[j].X; //May need to change this constant
					presindex++;
				}
				returnme[presindex] = 0;
				presindex ++;
			}

			return returnme;
		}
		
		/// <summary>
		/// Gets the y coordinates of some strokes and returns them in an int array
		/// </summary>
		/// <param name="daStrokes"></param>
		/// <param name="g"></param>
		/// <param name="ic"></param>
		/// <returns></returns>
		public static int[] yCoordsFromStrokes(Strokes daStrokes, Graphics g, InkCollector ic)
		{
			int[] returnme;
			int i, j, totalpoints=0, presindex=0;
			Stroke presStroke;
			Point[] presPoints;
			
			for(i=0; i < daStrokes.Count; i++)
				totalpoints += daStrokes[i].GetPoints().Length + 1;

			returnme = new int[totalpoints];
 
			for(i=0; i < daStrokes.Count; i++)
			{
				presStroke = daStrokes[i];
				presPoints = presStroke.GetPoints();
				ic.Renderer.InkSpaceToPixel(g, ref presPoints);
				for(j=0; j < presPoints.Length; j+=2)
				{
					returnme[presindex] = presPoints[j].Y; //May need to change this constant
					presindex++;
				}
				returnme[presindex] = 0;
				presindex ++;
			}

			return returnme;
		}
		
		/// <summary>
		/// Add the strokes collection to the training data in the DLL.
		/// </summary>
		/// <param name="daStrokes"></param>
		/// <param name="g"></param>
		/// <param name="ic"></param>
		/// <returns></returns>
		public static bool addToTrainingFromStrokes(Strokes daStrokes, Graphics g, InkCollector ic)
		{
			int[] xs = xCoordsFromStrokes(daStrokes, g, ic);

			if(xs.Length < 1)
				return false;

			AddToTraining(xs, yCoordsFromStrokes(daStrokes,g ,ic), xs.Length);
			return true;
		}

		//From DLL
		[DllImport("WinCitDll.dll")]
		public static extern int TestSquare(int input);
		[DllImport("WinCitDll.dll")]
		public static extern float ProbOfChoice(int choicenum, [In] int[] xs, [In] int[] ys, int arrsize, [In] char[] path);
		[DllImport("WinCitDll.dll")]
		public static extern int NameOfChoice(int choicenum, [In] int[] xs, [In] int[] ys, int arrsize, [Out] char[] buf, [In] char[] path);
		[DllImport("WinCitDll.dll")]
		public static extern float ProbOfBest([In] int []xs, [In] int[] ys, int arrsize, [In] char[] path);
		[DllImport("WinCitDll.dll")]
		public static extern int NameOfBest([In] int[] xs, [In] int[] ys, int arrsize, [Out] char[] buf, [In] char []path);
		[DllImport("WinCitDll.dll")]
		public static extern int LoadAsProfile([In] int[] xs, [In] int[] ys, int arrsize, char []path);
		[DllImport("WinCitDll.dll")]
		public static extern float ProfProbOfChoice(int choicenum);
		[DllImport("WinCitDll.dll")]
		public static extern int ProfNameOfChoice(int choicenum, [Out] char []buf);
		[DllImport("WinCitDll.dll")]
		public static extern void AddToTraining([In] int []xs, [In] int []ys, int arrsize);
		[DllImport("WinCitDll.dll")]
		public static extern void ClearTraining();
		[DllImport("WinCitDll.dll")]
		public static extern void LoadAsRecognizer([In] char []path);
		[DllImport("WinCitDll.dll")]
		public static extern void LoadProfWithRec([In] int []xs, [In] int []ys, int arrsize);
		[DllImport("WinCitDll.dll")]
		public static extern int WriteTraining([In] char[] name, [In] char[] path);
	}
}
