using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media.Media3D;
using Emgu;
using Emgu.CV;
using Emgu.CV.Structure;

namespace WpfApp1.Tools
{
    struct RleObj
    {
        public int[] size;  //[height, width]
        public string counts;
    }

    struct RLE
    {
        public int h;
        public int w;
        public int m;
        public uint[] cnts;
    }

    class RLEs
    {
        public RLE[] R;
        public int n;

        public RLEs(int n = 0)
        {
            MaskTools.rlesInit(ref R, n);
            this.n = n;
        }
    }

    class Masks
    {
        public byte[] mask;
        public int h;
        public int w;
        public int n;

        public Masks(int h, int w, int n)
        {
            this.mask = new byte[h * w * n];
            this.h = h;
            this.w = w;
            this.n = n;
        }

        public Image<Gray, byte> gray_image()
        {
            if (this.n != 1)
            {
                throw new Exception("CocoTools: unsupport mask channel: " + this.n.ToString());
            }
            //转置模拟列优先存储
            Mat mat = new Mat(this.w, this.h, Emgu.CV.CvEnum.DepthType.Cv8U, this.n);
            mat.SetTo(this.mask);
            Mat transposedMat = new Mat();
            CvInvoke.Transpose(mat, transposedMat);
            return transposedMat.ToImage<Gray, byte>();
        }
    }

    internal class CocoTools
    {
        private static RleObj[] toString(RLEs Rs)
        {
            int n = Rs.n;
            RleObj[] objs = new RleObj[n];
            for (int i = 0; i < n; i++)
            {
                string s = MaskTools.rleToString(Rs.R[i]);
                objs[i] = new RleObj { size = new int[] { Rs.R[i].h, Rs.R[i].w }, counts = s };
            }
            return objs;
        }

        //仅接受1个RLE
        private static RLEs frString(RleObj rleObj)
        {
            RLEs Rs = new RLEs(1);
            MaskTools.rleFrString(ref Rs.R[0], rleObj.counts, rleObj.size[0], rleObj.size[1]);
            return Rs;
        }

        public static Image<Gray, byte> decode(RleObj rleObj)
        {
            RLEs Rs = frString(rleObj);
            int h = Rs.R[0].h;
            int w = Rs.R[0].w;
            int n = Rs.n;
            Masks masks = new Masks(h, w, n);
            MaskTools.rleDecode(Rs.R, masks.mask, n);
            return masks.gray_image();
        }

        public static RleObj encode(Image<Gray, byte> image)
        {
            int h = image.Height;
            int w = image.Width;
            int n = 1;
            RLEs Rs = new RLEs(n);
            MaskTools.rleEncode(ref Rs.R, image.Bytes, h, w, n);
            RleObj[] rleObjs = toString(Rs);
            return rleObjs[0];
        }
    }
}
