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

namespace MyScreenCap.Ctrl {

    /// <summary>
    /// MedianCut
    /// </summary>
    public static class MedianCut {

        /// <summary>
        /// カラーパレットの取得
        /// </summary>
        /// <param name="img">元の画像</param>
        /// <param name="nColors">色数</param>
        /// <returns>色とピクセルのPointのList</returns>
        public static Dictionary<Color, List<Point>> SetColorPalette(Image image, ColorPalette palette) {

            // カラーパレットの作成

            // imageをbitmapに複製
            Bitmap bitmap = new Bitmap(
                image.Width,
                image.Height,
                PixelFormat.Format32bppArgb);
            {
                Graphics g = Graphics.FromImage(bitmap);

                g.PageUnit = GraphicsUnit.Pixel;

                g.DrawImage(image, 0, 0, image.Width, image.Height);

                g.Dispose();
            }

            // bitmapからcolorを抽出
            Dictionary<Color, List<Point>> colorDic = new Dictionary<Color, List<Point>> { };
            for (int x = 0; x < bitmap.Width; x++) {
                for (int y = 0; y < bitmap.Height; y++) {
                    Color pixcelColor;
                    pixcelColor = bitmap.GetPixel(x, y);
                    if (colorDic.ContainsKey(pixcelColor)) {
                        colorDic[pixcelColor].Add(new Point(x, y));
                    } else {
                        colorDic.Add(pixcelColor, new List<Point> { new Point(x, y) });
                    }
                }
            }

            // 指定された色の数だけ色空間を分割
            List<MedianCutColor> colorList = new List<MedianCutColor> { };
            foreach (KeyValuePair<Color, List<Point>> keyValue in colorDic) {
                colorList.Add(new MedianCutColor(keyValue.Key, keyValue.Value.Count));
            }
            List<MedianCutBox> medianCutBoxList = new List<MedianCutBox> { };
            medianCutBoxList.Add(new MedianCutBox(colorList));
            for (int i = 0; i < palette.Entries.Length - 1; i++) {
                if (medianCutBoxList[i].ColorList.Count > 1) {
                    MedianCutBox box1;
                    MedianCutBox box2;
                    medianCutBoxList[i].CutBox(out box1, out box2);
                    medianCutBoxList[i] = box1;
                    medianCutBoxList.Add(box2);
                    BringToLast(medianCutBoxList);
                } else {
                    // これ以上分割が出来なかくなったら終了
                    break;
                }
            }

            // ColorPaletteに各MedianCutBoxの色を設定
            for (int i = 0; i < medianCutBoxList.Count; i++) {
                MedianCutBox box = medianCutBoxList[i];
                Color color = box.Color;
                palette.Entries[i] = color;
            }

            return colorDic;
        }

        /// <summary>
        /// 含まれる色が最も多く、色の差が大きいMedianCutBoxをListの最後尾へ移動
        /// </summary>
        /// <param name="medianCutBoxList"></param>
        private static void BringToLast(List<MedianCutBox> medianCutBoxList) {

            int maxCnt = 0;
            int maxCntTmp;
            int index = 0;
            for (int i = 0; i < medianCutBoxList.Count; i++) {
                maxCntTmp = medianCutBoxList[i].ColorList.Count;
                if ((maxCnt < maxCntTmp) ||
                    (maxCnt == maxCntTmp && medianCutBoxList[index].MaxLength < medianCutBoxList[i].MaxLength)) {
                    index = i;
                    maxCnt = maxCntTmp;
                }
            }
            if (medianCutBoxList.Count - 1 != index) {
                MedianCutBox medianCutBox = medianCutBoxList[medianCutBoxList.Count - 1];
                medianCutBoxList[medianCutBoxList.Count - 1] = medianCutBoxList[index];
                medianCutBoxList[index] = medianCutBox;
            }
        }
    }
}
