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

using CategoryTheory;
using DataPerformer;
using DiagramUI;

using BitmapConsumer;

namespace ImageTransformations
{
    [Serializable()]
    public class DataPicture : ISerializable, ICategoryObject, IPostSetArrow, IDataConsumer, IBitmapDrawing
    {

        #region Fields
        List<IMeasurements> measurementsData = new List<IMeasurements>();
        List<string> measures = new List<string>();
        private List<string> aliasNames = new List<string>();
        private bool proportional = false;
        private bool equals = false;
        private bool colored;
        private double max;
        private double min;

        private double[] amax = new double[3];

        private double[] amin = new double[3];

        private int[] col = new int[3];

        private DataPerformerOperations op = new DataPerformerOperations();

        object obj;

        object[] oin = new object[2];
        object[] oout = new object[1];
        object[] aoout = new object[3];

        #endregion

        #region Ctor

        public DataPicture()
        {
        }

        protected DataPicture(SerializationInfo info, StreamingContext context)
        {
            try
            {
                measures = info.GetValue("Measures", typeof(List<string>)) as List<string>;
                aliasNames = info.GetValue("AliasNames", typeof(List<string>)) as List<string>;
                proportional = (bool)info.GetValue("Proportional", typeof(bool));
                equals = (bool)info.GetValue("Equals", typeof(bool));
                colored = (bool)info.GetValue("Colored", typeof(bool));
            }
            catch (Exception)
            {
            }

        }

        #endregion

        #region ISerializable Members

        void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.AddValue("Measures", measures, typeof(List<string>));
            info.AddValue("AliasNames", aliasNames, typeof(List<string>));
            info.AddValue("Proportional", proportional, typeof(bool));
            info.AddValue("Equals", equals, typeof(bool));
            info.AddValue("Colored", colored, typeof(bool));
        }

        #endregion

        #region ICategoryObject Members

        ICategory ICategoryObject.Category
        {
            get { throw new Exception("The method or operation is not implemented."); }
        }

        ICategoryArrow ICategoryObject.Id
        {
            get { throw new Exception("The method or operation is not implemented."); }
        }

        #endregion

        #region IAssociatedObject Members

        object IAssociatedObject.Object
        {
            get
            {
                return obj;
            }
            set
            {
                obj = value;
            }
        }

        #endregion

        #region IPostSetArrow Members

        void IPostSetArrow.PostSetArrow()
        {
            op.Set(this, measures, aliasNames);
        }

        #endregion

        #region IDataConsumer Members

        void IDataConsumer.Add(IMeasurements measurements)
        {
            measurementsData.Add(measurements);
        }

        void IDataConsumer.Remove(IMeasurements measurements)
        {
            measurementsData.Remove(measurements);
        }

        void IDataConsumer.UpdateChildrenData()
        {
            DataPerformerOperations.UpdateChildernData(this);
        }

        int IDataConsumer.Count
        {
            get { return measurementsData.Count; }
        }

        IMeasurements IDataConsumer.this[int n]
        {
            get { return measurementsData[n]; }
        }

        void IDataConsumer.Reset()
        {
            DataPerformerOperations.Reset(this);
        }

        #endregion

 

        #region IBitmapDrawing Members

        void IBitmapDrawing.Draw(Bitmap bmp)
        {
            if (bmp == null)
            {
                return;
            }
            int w = bmp.Width;
            int h = bmp.Height;
            if (equals)
            {
                if (h > w)
                {
                    h = w;
                }
                else
                {
                    w = h;
                }
            }
            double dw = (double)w;
            double dh = (double)h;
            min = 0;
            max = 1;
            try
            {
                if (proportional)
                {
                    if (colored)
                    {
                        defineColorBounds(w, h);
                    }
                    else
                    {
                        defineBounds(w, h);
                    }
                }
                if (colored)
                {
                    paintColored(bmp, w, h);
                }
                else
                {
                    paintGrayScale(bmp, w, h);
                }
            }
            catch (Exception ex)
            {
            }
        }

        #endregion

        #region Specific Members

        public void Set(List<string> measures, List<string> aliases)
        {
            if (aliases.Count != 2)
            {
                throw new Exception("Ill");
            }
            if (measures.Count < 1)
            {
                throw new Exception("Ill");
            }
            if (colored & measures.Count < 3)
            {
                throw new Exception("Ill");
            }
            this.measures = measures;
            aliasNames = aliases;
            IPostSetArrow p = this;
            p.PostSetArrow();
        }

        public List<string> Aliases
        {
            get
            {
                return aliasNames;
            }
        }


        public List<string> Measures
        {
            get
            {
                return measures;
            }
        }

        public List<string> AllAliases
        {
            get
            {
               return DataPerformerOperations.GetAliases(this);
            }
        }

        public List<string> AllMeasures
        {
            get
            {
                Double a = 0;
                return DataPerformerOperations.GetAllMeasurements(this, a);
            }
        }

        public bool Proportional
        {
            get
            {
                return proportional;
            }
            set
            {
                proportional = value;
            }
        }
        
        public bool EqualSize
        {
            get
            {
                return equals;
            }
            set
            {
                equals = value;
            }
        }

        public bool Colored
        {
            get
            {
                return colored;
            }
            set
            {
                colored = value;
            }
        }


        private void defineBounds(int w, int h)
        {
            double dw = (double)w;
            double dh = (double)h;

            for (int i = 0; i < w; i++)
            {
                double di = (double)i / dw;
                oin[0] = di;
                for (int j = 0; j < h; j++)
                {
                    double dj = (double)j / dh;
                    oin[1] = dj;
                    op.Transform(oin, oout);
                    double x = (double)oout[0];
                    if (i == 0 & j == 0)
                    {
                        min = x;
                        max = x;
                        continue;
                    }
                    if (x > max)
                    {
                        max = x;
                        continue;
                    }
                    if (x < min)
                    {
                        min = x;
                        continue;
                    }
                }
            }

        }
        private void defineColorBounds(int w, int h)
        {
            double dw = (double)w;
            double dh = (double)h;

            for (int i = 0; i < w; i++)
            {
                double di = (double)i / dw;
                oin[0] = di;
                for (int j = 0; j < h; j++)
                {
                    double dj = (double)j / dh;
                    oin[1] = dj;
                    op.Transform(oin, aoout);
                    for (int k = 0; k < 3; k++)
                    {
                        double x = (double)aoout[k];
                        if (i == 0 & j == 0)
                        {
                            amin[k] = x;
                            amax[k] = x;
                            continue;
                        }
                        if (x > amax[k])
                        {
                            amax[k] = x;
                            continue;
                        }
                        if (x < amin[k])
                        {
                            amin[k] = x;
                            continue;
                        }
                    }
                }

            }
        }

        void paintGrayScale(Bitmap bmp, int w, int h)
        {
            double dw = (double)w;
            double dh = (double)h;
            for (int i = 0; i < w; i++)
            {
                double di = (double)i / dw;
                oin[0] = di;
                for (int j = 0; j < h; j++)
                {
                    double dj = (double)j / dh;
                    oin[1] = dj;
                    op.Transform(oin, oout);
                    double x = ((double)oout[0] - min) / (max - min);
                    int c = (int)(x * 255);
                    Color col = Color.FromArgb(255, c, c, c);
                    bmp.SetPixel(i, j, col);
                }
            }

        }
        
        void paintColored(Bitmap bmp, int w, int h)
        {
            double dw = (double)w;
            double dh = (double)h;
            for (int i = 0; i < w; i++)
            {
                double di = (double)i / dw;
                oin[0] = di;
                for (int j = 0; j < h; j++)
                {
                    double dj = (double)j / dh;
                    oin[1] = dj;
                    op.Transform(oin, aoout);
                    for (int k = 0; k < 3; k++)
                    {
                        double x = ((double)aoout[k] - min) / (max - min);
                        col[k] = (int)(x * 255);
                    }
                    Color color = Color.FromArgb(255, col[0], col[1], col[2]);
                    bmp.SetPixel(i, j, color);
                }
            }

        }

        #endregion
    }
}
