using System;
using System.Drawing;
using System.Drawing.Imaging;
using ImageBlockz.Api;
using ImageBlockz.Core;
using System.Xml;

namespace ImageBlockz.Operations
{
    public class Gradient : AbstractOperation
    {
        // uložíme si do veřejného statického pole dle typu operace jméno operace s plnou cestou
        public static readonly string OperationName = typeof(Gradient).FullName;

        public Gradient()
            : base(OperationType.Filter)
        {

        }

        public Gradient(int factor, bool isRedChecked, bool isGreenChecked, bool isBlueChecked)
            : this()
        {
            Factor = factor;
            IsRedChecked = isRedChecked;
            IsGreenChecked = isGreenChecked;
            IsBlueChecked = isBlueChecked;
        }

        public float Factor
        {
            get;
            set;
        }

        public bool IsRedChecked
        {
            get;
            set;
        }

        public bool IsGreenChecked
        {
            get;
            set;
        }

        public bool IsBlueChecked
        {
            get;
            set;
        }

        public override Bitmap Do(Bitmap bmp)
        {
            PixelFormat format = PixelFormat.Format24bppRgb;

            Bitmap newimg = new Bitmap(bmp.Width, bmp.Height, format);

            BitmapWrapper wrapperIn = new BitmapWrapper(bmp);
            BitmapWrapper wrapperOut = new BitmapWrapper(newimg);

            wrapperIn.Lock();
            wrapperOut.Lock();

            for (int x = 0; x < bmp.Width; x++)
                for (int y = 0; y < bmp.Height; y++)
                {
                    Color color = wrapperIn.GetPixel(x, y);

                    color = ComputeColor(color, x, bmp.Width);

                    wrapperOut.SetPixel(color, x, y);
                }

            wrapperIn.Unlock();
            wrapperOut.Unlock();

            return newimg;
        }

        private int ComputeChannel(int value, float factor, int position, int bmpWidth)
        {
            int result = value + (int) ((double)position / bmpWidth * 255 * factor);
            result = Math.Min(result, 255);
            result = Math.Max(result, 0);

            return result;
        }

        private Color ComputeColor(Color color, int position, int bmpWidth)
        {
            int red = color.R;
            int green = color.G;
            int blue = color.B;

            if (IsRedChecked)
            {
                red = ComputeChannel(color.R, Factor, position, bmpWidth);
            }

            if (IsGreenChecked)
            {
                green = ComputeChannel(color.G, Factor, position, bmpWidth);
            }

            if (IsBlueChecked)
            {
                blue = ComputeChannel(color.B, Factor, position, bmpWidth);
            }

            return Color.FromArgb(red, green, blue);
        }

        public override XmlNode ToXml(XmlDocument xmlDoc)
        {
            XmlElement gradient = xmlDoc.CreateElement(OperationName);

            XmlElement red = XmlOperation.BoolToXml("red", IsRedChecked, xmlDoc);
            XmlElement green = XmlOperation.BoolToXml("green", IsGreenChecked, xmlDoc);
            XmlElement blue = XmlOperation.BoolToXml("blue", IsBlueChecked, xmlDoc);
            XmlElement factor = XmlOperation.FloatToXml("factor", Factor, xmlDoc);

            gradient.AppendChild(red);
            gradient.AppendChild(green);
            gradient.AppendChild(blue);
            gradient.AppendChild(factor);

            return gradient;
        }

        public override void FromXml(XmlNode node)
        {
            IsRedChecked = XmlOperation.BoolFromXml(node["red"]);
            IsGreenChecked = XmlOperation.BoolFromXml(node["green"]);
            IsBlueChecked = XmlOperation.BoolFromXml(node["blue"]);
            Factor = XmlOperation.FloatFromXml(node["factor"]);
        }

        public override string GetFormattedName()
        {
            return "Gradient";
        }


        public override string GetInfo()
        {
            return "Factor: " + Factor;
        }
    }
}
