using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Threading;
using System.Windows.Forms;

namespace Demo
{
	public partial class FormDemo : Form
	{
		public FormDemo()
		{
			InitializeComponent();
		}

		private void buttonSelectPicture_Click(object sender, EventArgs e)
		{
			if (openFileDialog.ShowDialog() == DialogResult.OK)
			{
				selection.Width = 0;
				selection.Height = 0;
				progressBar.Value = 0;
				textBoxText.Clear();
				textBoxHtml.Clear();
				textBoxUnlv.Clear();
				pictureBoxRegions.Image = null;
				pictureBoxParagraphs.Image = null;
				pictureBoxTextLines.Image = null;
				pictureBoxWords.Image = null;
				pictureBoxComponents.Image = null;

				try
				{
					pictureBox.Image = Image.FromFile(openFileDialog.FileName);
					ocr.Picture = pictureBox.Image;
					pictureBox.Cursor = Cursors.Cross;
				}
				catch (Exception)
				{
					ocr.Picture = null;
					ocr.PictureFileName = openFileDialog.FileName;
					pictureBox.Cursor = Cursors.Default;
				}

				if (!ocr.Active)
				{
					ocr.DataPath = AppDomain.CurrentDomain.BaseDirectory;
					ocr.Active = true;
				}
				buttonRecognize.Enabled = true;
			}
		}

		private bool cancel;

		private void OcrInvoke()
		{
			try
			{
				if (!cancel)
				{
					progressBar.Value = 100;

					textBoxText.Text = ocr.Text.Replace("\xa", "\xd\xa");
					textBoxHtml.Text = ocr.HtmlText.Replace("\xa", "\xd\xa");
					textBoxUnlv.Text = ocr.UnlvText.Replace("\xa", "\xd\xa");

					using (var bitmap = new Bitmap(pictureBox.Image))
					{
						pictureBoxWords.Image = bitmap.Clone(new Rectangle(0, 0, bitmap.Width, bitmap.Height), PixelFormat.Format24bppRgb);
						if (ocr.Words != null)
							using (var g = Graphics.FromImage(pictureBoxWords.Image))
							{
								var pen = new Pen(Color.FromArgb(0x00, 0x7F, 0xFF));
								foreach (var rectangle in ocr.Words)
									g.DrawRectangle(pen, ocr.PictureLeft + rectangle.Left, ocr.PictureTop + rectangle.Top, rectangle.Width, rectangle.Height);
							}

						pictureBoxRegions.Image = bitmap.Clone(new Rectangle(0, 0, bitmap.Width, bitmap.Height), PixelFormat.Format24bppRgb);
						if (ocr.Regions != null)
							using (var g = Graphics.FromImage(pictureBoxRegions.Image))
							{
								var pen = new Pen(Color.FromArgb(0x7F, 0x00, 0xFF));
								foreach (var rectangle in ocr.Regions)
									g.DrawRectangle(pen, ocr.PictureLeft + rectangle.Left, ocr.PictureTop + rectangle.Top, rectangle.Width, rectangle.Height);
							}

						pictureBoxTextLines.Image = bitmap.Clone(new Rectangle(0, 0, bitmap.Width, bitmap.Height), PixelFormat.Format24bppRgb);
						if (ocr.TextLines != null)
							using (var g = Graphics.FromImage(pictureBoxTextLines.Image))
							{
								var pen = new Pen(Color.FromArgb(0x00, 0xFF, 0x7F));
								foreach (var rectangle in ocr.TextLines)
									g.DrawRectangle(pen, ocr.PictureLeft + rectangle.Left, ocr.PictureTop + rectangle.Top, rectangle.Width, rectangle.Height);
							}

						pictureBoxComponents.Image = bitmap.Clone(new Rectangle(0, 0, bitmap.Width, bitmap.Height), PixelFormat.Format24bppRgb);
						if (ocr.ConnectedComponents != null)
							using (var g = Graphics.FromImage(pictureBoxComponents.Image))
							{
								var pen = new Pen(Color.FromArgb(0xFF, 0x7F, 0x00));
								foreach (var rectangle in ocr.ConnectedComponents)
									g.DrawRectangle(pen, ocr.PictureLeft + rectangle.Left, ocr.PictureTop + rectangle.Top, rectangle.Width, rectangle.Height);
							}

						pictureBoxParagraphs.Image = bitmap.Clone(new Rectangle(0, 0, bitmap.Width, bitmap.Height), PixelFormat.Format24bppRgb);
						if (ocr.Paragraphs != null)
							using (var g = Graphics.FromImage(pictureBoxParagraphs.Image))
							{
								var pen = new Pen(Color.FromArgb(0x7F, 0xFF, 0x00));
								foreach (var paragraph in ocr.Paragraphs)
								{
									var rectangle = paragraph.Location;
									g.DrawRectangle(pen, rectangle.Left, rectangle.Top, rectangle.Width, rectangle.Height);
								}
							}
					}
				}
				else
					progressBar.Value = 0;
			}
			finally
			{
				buttonCancel.Visible = false;
				buttonSelectPicture.Enabled = true;
				Cursor.Current = Cursors.Default;
			}
		}

		delegate void OcrDelegate();

		private void Start()
		{
			ocr.Recognize();
			if (InvokeRequired)
			{
				var invoke = new OcrDelegate(OcrInvoke);
				this.Invoke(invoke, null);
			}
			else
				OcrInvoke();
		}

		private void buttonRecognize_Click(object sender, EventArgs e)
		{
			buttonSelectPicture.Enabled = false;
			Cursor.Current = Cursors.WaitCursor;
			cancel = false;
			buttonCancel.Visible = true;
			textBoxText.Clear();
			textBoxHtml.Clear();
			textBoxUnlv.Clear();
			pictureBoxRegions.Image = null;
			pictureBoxParagraphs.Image = null;
			pictureBoxTextLines.Image = null;
			pictureBoxWords.Image = null;
			pictureBoxComponents.Image = null;

			bool useSelection = selection.Width != 0 && selection.Height != 0;
			if (useSelection)
			{
				int left, top, right, bottom;
				PictureBoxToImage(selection.Left, selection.Top, out left, out top);
				PictureBoxToImage(selection.Right, selection.Bottom, out right, out bottom);
				ocr.PictureLeft = left;
				ocr.PictureTop = top;
				ocr.PictureWidth = right - ocr.PictureLeft;
				ocr.PictureHeight = bottom - ocr.PictureTop;
			}
			else
				selection.X = selection.Y = ocr.PictureLeft = ocr.PictureTop = ocr.PictureWidth = ocr.PictureHeight = 0;

			new Thread(Start).Start();
		}

		delegate void ProgressDelegate(int progress);

		void ProgressInvoke(int progress)
		{
			progressBar.Value = progress;
		}

		private void ocr_Progress(object sender, Winsoft.Ocr.ProgressEventArgs e)
		{
			if (progressBar.InvokeRequired)
			{
				var invoke = new ProgressDelegate(ProgressInvoke);
				this.Invoke(invoke, new object[] { e.Progress });
			}
			else
				ProgressInvoke(e.Progress);
			e.Cancel = cancel;
		}

		private void buttonCancel_Click(object sender, EventArgs e)
		{
			cancel = true;
		}

		private bool selecting;
		private Rectangle selection;

		private void pictureBox_Paint(object sender, PaintEventArgs e)
		{
			using (Pen pen = new Pen(Color.Red))
			{
				pen.DashStyle = DashStyle.Dash;
				e.Graphics.DrawRectangle(pen, selection);
			}
		}

		private void pictureBox_MouseDown(object sender, MouseEventArgs e)
		{
			if (pictureBox.Cursor == Cursors.Cross)
				if (e.Button == MouseButtons.Left)
				{
					selecting = true;
					selection.X = e.X;
					selection.Y = e.Y;
					selection.Width = 0;
					selection.Height = 0;
					pictureBox.Refresh();
				}
		}

		private void pictureBox_MouseMove(object sender, MouseEventArgs e)
		{
			if (selecting)
			{
				selection.Width = e.X - selection.X;
				selection.Height = e.Y - selection.Y;
				pictureBox.Refresh();
			}
		}

		private void pictureBox_MouseUp(object sender, MouseEventArgs e)
		{
			if (selecting)
			{
				selecting = false;
				selection.Width = e.X - selection.X;
				selection.Height = e.Y - selection.Y;
				pictureBox.Refresh();
			}
		}

		private void pictureBox_Resize(object sender, EventArgs e)
		{
			selection.Width = 0;
			selection.Height = 0;
			pictureBox.Refresh();
		}

		private void PictureBoxToImage(int x, int y, out int imageX, out int imageY)
		{
			var boxHeight = pictureBox.Height;
			var boxWidth = pictureBox.Width;
			var boxAspect = (double)boxWidth / boxHeight;

			var imageHeight = pictureBox.Image.Height;
			var imageWidth = pictureBox.Image.Width;
			var imageAspect = (double)imageWidth / imageHeight;

			if (boxAspect >= imageAspect)
			{
				// PictureBox is wider and shorter than image
				var zoom = (double)imageHeight / boxHeight;

				imageY = (int)(y * zoom); // zoom height

				var boxDX = x - (double)boxWidth / 2; // calc distance from PictureBox center
				var imageDX = boxDX * zoom; // zoom distance
				imageX = (int)(imageDX + (double)imageWidth / 2); // convert distance back to coordinate
			}
			else
			{
				// PictureBox is taller and thinner than image
				var zoom = (double)imageWidth / boxWidth;

				imageX = (int)(x * zoom); // zoom width

				var boxDY = y - (double)boxHeight / 2; // calc distance from PictureBox center
				var imageDY = boxDY * zoom; // zoom distance
				imageY = (int)(imageDY + (double)imageHeight / 2); // convert distance back to coordinate
			}
		}
	}
}