using System.Collections.Generic;
using OpenCvSharp;

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

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

        public float[] To28X28Floats()
        {
            using (var bitmap = To28X28())
            {
                var ret = new List<float>();
                using (var bytes = new MatOfByte(bitmap))
                {
                    var indexer = bytes.GetIndexer();
                    for (var x = 0; x < bitmap.Width; ++x)
                    {
                        for (var y = 0; y < bitmap.Height; ++y)
                        {
                            var pixel = indexer[y, x];
                            ret.Add((byte)(byte.MaxValue - pixel));
                        }
                    }
                }
                return ret.ToArray();
            }
        }

        protected Mat FindRegionOfInterest()
        {
            const int white = byte.MaxValue;
            int w = Bitmap.Width, h = Bitmap.Height;
            int x2 = 0, y2 = 0, x1 = w - 1, y1 = h - 1;
            using (var bytes = new MatOfByte(Bitmap))
            {
                var indexer = bytes.GetIndexer();

                for (var y = 0; y < h; y++)
                {
                    for (var x = 0; x < w; x++)
                    {
                        var px = indexer[y, x];
                        if (px == 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 = indexer[y, x];
                        if (px == white) continue;

                        if ((y + 1) > y2)
                        {
                            y2 = y;
                        }

                        if ((x + 1) > x2)
                        {
                            x2 = x;
                            break;
                        }
                    }
                }
            }

            if (y2 <= y1 || x2 < x1)
            {
                return Bitmap;
            }
            var rectangle = Rect.FromLTRB(x1, y1, x2, y2);
            return Bitmap.SubMat(rectangle);
        }

        protected static Point2f FindCenterOfMass(Mat bitmap)
        {
            var cumX = 0f;
            var cumY = 0f;
            var numberOfPoints = 0;
            var indexer = bitmap.GetGenericIndexer<byte>();
            for (var x = 0; x < bitmap.Width; ++x)
                for (var y = 0; y < bitmap.Height; ++y)
                {
                    var pixel = indexer[y, x];
                    var gray = byte.MaxValue - pixel;
                    if (gray <= 0) continue;
                    cumX += x;
                    cumY += y;
                    ++numberOfPoints;
                }
            var avgX = cumX / numberOfPoints;
            var avgY = cumY / numberOfPoints;
            return new Point2f(avgX, avgY);
        }
    }
}

