using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;

namespace NistUtilities
{
    public abstract class NistAdapter
    {
        protected Bitmap Bitmap;
        public abstract Bitmap To28X28();

        protected NistAdapter(Bitmap sourceBitmap)
        {
            Bitmap = sourceBitmap;
        }

        public float[] To28X28Floats()
        {
            using (var bitmap = To28X28())
            {
                var ret = new List<float>();
                var bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
                    ImageLockMode.ReadOnly, bitmap.PixelFormat);
                var maxI = bitmapData.Stride;
                var ptr = bitmapData.Scan0;
                var buffer = new byte[bitmapData.Stride * bitmap.Height];
                Marshal.Copy(ptr, buffer, 0, buffer.Length);
                bitmap.UnlockBits(bitmapData);
                for (var i = 0; i < maxI; i += 4)
                {
                    for (var row = 0; row < bitmap.Height; ++row)
                    {
                        var index = row * bitmapData.Stride + i;
                        var b = buffer[index];
                        ret.Add((byte)(255 - b));
                    }
                }
                return ret.ToArray();
            }
        }


        protected Bitmap FindRegionOfInterest()
        {
            int white = Color.White.ToArgb();
            int w = Bitmap.Width, h = Bitmap.Height;
            var bitmapData = Bitmap.LockBits(new Rectangle(0, 0, w, h),
                ImageLockMode.ReadOnly, Bitmap.PixelFormat);
            var ptr = bitmapData.Scan0;
            var buffer = new byte[bitmapData.Stride * h];
            Marshal.Copy(ptr, buffer, 0, buffer.Length);
            Bitmap.UnlockBits(bitmapData);
            int x2 = 0, y2 = 0, x1 = w, y1 = h;
            for (var y = 0; y < h; y++)
            {
                for (var x = 0; x < w; x++)
                {
                    var px = Bitmap.GetPixel(x, y); 
                    if (px.ToArgb() == white) continue;
                    if (y < y1)
                    {
                        y1 = y;
                    }
                    if (x < x1)
                    {
                        x1 = x;
                        break;
                    }

                }
            }
            for (var y = h - 1; y > y1; y--)
            {
                for (var x = w - 1; x > x1; x--)
                {
                    var px = Bitmap.GetPixel(x, y);
                    if (px.ToArgb() == white)
                    {
                        continue;
                    }
                    if ((y + 1) > y2)
                    {
                        y2 = y + 1;
                    }
                    if ((x + 1) > x2)
                    {
                        x2 = x + 1;
                        break;
                    }
                }
            }
            var rectangle = Rectangle.FromLTRB(x1, y1, x2, y2);
            if (rectangle.Width <= 0 || rectangle.Height <= 0)
            {
                return Bitmap.Clone(new Rectangle(0, 0, w, h), Bitmap.PixelFormat);
            }
            return Bitmap.Clone(rectangle, Bitmap.PixelFormat);
        }

        protected static PointF FindCenterOfMass(Bitmap bitmap)
        {
            var cumX = 0f;
            var cumY = 0f;
            var numberOfPoints = 0;
            for (var x = 0; x < bitmap.Width; ++x)
                for (var y = 0; y < bitmap.Height; ++y)
                {
                    var pixel = bitmap.GetPixel(x, y);
                    var gray = 255 - (pixel.R + pixel.G + pixel.B) / 3;
                    if (gray <= 0) continue;
                    cumX += x; 
                    cumY += y; 
                    ++numberOfPoints;
                }
            var avgX = cumX / numberOfPoints;
            var avgY = cumY / numberOfPoints;
            return new PointF(avgX, avgY);
        }
    }
}

