using System;
using System.Drawing;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.Serialization;


using CategoryTheory;
using DiagramUI;
using FormulaEditor;
using BitmapConsumer;

namespace ImageTransformations
{

	[Serializable()]
	public class SourceBitmap : ICategoryObject, IBitmapProvider, ISerializable
	{

		#region Fields
		/// <summary>
		/// Bitmap
		/// </summary>
		private Bitmap bitmap;
		
		/// <summary>
		/// Associated object
		/// </summary>
		private object obj;


		/// <summary>
		/// Comments
		/// </summary>
		private ArrayList comments = new ArrayList();

		#endregion

		#region Constructors

		public SourceBitmap()
		{
		}

		public SourceBitmap(SerializationInfo info, StreamingContext context)
		{
			try
			{
				bitmap = (Bitmap) info.GetValue("Bitmap", typeof(Bitmap));
			}
			catch (Exception)
			{
			}
			comments = (ArrayList) info.GetValue("Comments", typeof(ArrayList));
		}


		#endregion

		#region ISerializable Members

		public void GetObjectData(SerializationInfo info, StreamingContext context)
		{
			info.AddValue("Bitmap", bitmap);
			info.AddValue("Comments", comments);
		}

		#endregion

		#region ICategoryObject Members

		public ICategory Category
		{
			get
			{
				return null;
			}
		}

		public ICategoryArrow Id
		{
			get
			{
				return null;
			}
		}

		#endregion

		#region IAssociatedObject Members

		public object Object
		{
			get
			{
				return obj;
			}
			set
			{
				obj = value;
			}
		}

		#endregion

		#region IBitmapProvider Members

		public Bitmap Bitmap
		{
			get
			{
				return bitmap;
			}
		}

		#endregion

		#region Specific Members
		
		/// <summary>
		/// Sets bitmap
		/// </summary>
		/// <param name="bitmap"></param>
		public void SetBitmap(Bitmap bitmap)
		{
			this.bitmap = bitmap;
		}

		#endregion
	}

	/// <summary>
	/// Transformer of colors
	/// </summary>
	[Serializable()]
	public class ColorTransformer : ICategoryObject, ISerializable, IBitmapProvider, IBitmapConsumer, IAlias
	{
		#region Fields

		private object obj;
		private string[] formulaStrings = new string[]{"", "", ""}; 
		private MathFormula[] formulas = new MathFormula[3]; 
		private ObjectFormulaTree[] trees = new ObjectFormulaTree[3];
		private ElementaryObjectArgument arg = new ElementaryObjectArgument();
		private Bitmap bitmap;
		private Hashtable aliases = new Hashtable();
		private ArrayList comments = new ArrayList();
		
		/// <summary>
		/// Provider
		/// </summary>
		private IBitmapProvider provider;

		#endregion

		#region Constructors

		public ColorTransformer()
		{
		}

		public ColorTransformer(SerializationInfo info, StreamingContext context)
		{
			formulaStrings = info.GetValue("Formulas", typeof(string[])) as string[];
			comments = (ArrayList) info.GetValue("Comments", typeof(ArrayList));
			init();
		}

		#endregion

		#region ISerializable Members

		public void GetObjectData(SerializationInfo info, StreamingContext context)
		{
			info.AddValue("Formulas", formulaStrings);
			info.AddValue("Comments", comments);
		}

		#endregion

		#region ICategoryObject Members

		public ICategory Category
		{
			get
			{
				// TODO:  Add ColorTransformer.Category getter implementation
				return null;
			}
		}

		public ICategoryArrow Id
		{
			get
			{
				// TODO:  Add ColorTransformer.Id getter implementation
				return null;
			}
		}

		#endregion

		#region IAssociatedObject Members

		public object Object
		{
			get
			{
				return obj;
			}
			set
			{
				obj = value;
			}
		}

		#endregion

		#region IBitmapProvider Members

		public Bitmap Bitmap
		{
			get
			{
				return bitmap;
			}
		}

		#endregion

		#region IBitmapConsumer Members

		public void Process()
		{
			if (provider == null)
			{
				return;
			}
			if (provider.Bitmap == null)
			{
				return;
			}
			Bitmap bmp = provider.Bitmap;
			if (bitmap == null)
			{
				bitmap = new Bitmap(bmp.Width, bmp.Height);
			}
			else if ((bitmap.Width != bmp.Width) | (bitmap.Height != bmp.Height))
			{
				bitmap = new Bitmap(bmp.Width, bmp.Height);
			}
			byte[] res = new byte[]{0xFF, 0, 0, 0};
			foreach (object o in aliases.Keys)
			{
				arg[o] = aliases[o];
			}
			for (int i = 0; i < bmp.Width; i++)
			{
				for (int j = 0; j < bmp.Height; j++)
				{
					Color c = bmp.GetPixel(i, j);
					double r = (double) c.R;
					double g = (double) c.B;
					double b = (double) c.G;
					try
					{
						arg['r'] = r;
					}
					catch (Exception)
					{
					}
					try
					{
						arg['g'] = g;
					}
					catch (Exception)
					{
					}
					try
					{
						arg['b'] = b;
					}
					catch (Exception)
					{
					}
					try
					{
						arg['x'] = (double) i;
					}
					catch (Exception)
					{
					}
					try
					{
						arg['y'] = (double) j;
					}
					catch (Exception)
					{
					}
					for (int k = 0; k < 3; k++)
					{
						double a = (double) trees[k].Result;
						if (a < 0)
						{
							a = 0;
						}
						if (a > 255)
						{
							a = 255;
						}
						res[k + 1] = (byte) a;
						Color col = Color.FromArgb(res[1], res[2], res[3]);
						bitmap.SetPixel(i, j, col);
					}
				}
			}
		}

		public IBitmapProvider Provider
		{
			get
			{
				return provider;
			}
			set
			{
				if (provider == null)
				{
					provider = value;
					return;
					//Process();
				}
				if (value != null)
				{
					throw new Exception("Provider already exists");
				}
				provider = null;
			}
		}

		#endregion

		#region IAlias Members

		public List<string> AliasNames
		{
			get
			{
                List<string> l = new List<string>();
				foreach (char c in aliases.Keys)
				{
					l.Add(c + "");
				}
				return l;
			}
		}

		public object this[string alias]
		{
			get
			{
				return aliases[alias[0]];
			}
			set
			{
				aliases[alias[0]] = value;
			}
		}

        public object GetType(int n)
        {
            Double a = 0;
            return a;
        }

		#endregion

		#region Specific Members

		public string[] Formulas
		{
			get
			{
				return formulaStrings;
			}
			set
			{
				if (value.Length != 3)
				{
					throw new Exception("You should use three formulas");
				}
				formulaStrings = value;
				init();
				setAliases();
			}
		}

		private void init()
		{
			arg.Clear(); 
			for (int i = 0; i < 3; i++)
			{
				MathFormula f = MathFormula.FromString(MathSymbolFactory.Sizes, formulaStrings[i]);
				formulas[i] = f;
				f = f.FullTransform;
				ObjectFormulaTree t = new ObjectFormulaTree(f);
				trees[i] = t;
				arg.Add(t);
			}
		}

		private void setAliases()
		{
			aliases.Clear();
			string s = arg.Variables;
			double a = 0;
			foreach (char c in s)
			{
				if ((c == 'r') | (c == 'g') | (c == 'b') | (c == 'x') | (c == 'y'))
				{
					continue;
				}
				aliases[c] = a;
			}
		}


		#endregion
	}

}
