import Utils from "./utils";
import FillArea from "./fillarea";
import { AreaMap, ColorInfo, ColorMap, ColorSumItem } from "./interfaces";
import { mergeByColorMap } from "./color-merge";

const TAG = 'AutoColorMap';

export default class AutoColorMap {
  page: HTMLImageElement;
  map: HTMLImageElement;
  colored: HTMLImageElement;

  areaMap: AreaMap;
  colorMap: ColorMap;
  colorSum: ColorSumItem[];
  mapData: ImageData;
  mapPixels: Uint32Array;
  pageData: ImageData;
  pagePixels: Uint32Array;
  coloredData: ImageData;
  coloredPixels: Uint32Array;

  constructor(page: HTMLImageElement, map: HTMLImageElement, colored: HTMLImageElement) {
    this.page = page;
    this.map = map;
    this.colored = colored;

    this.mapData = Utils.getImageData(this.map);
    this.mapPixels = new Uint32Array(this.mapData.data.buffer);
    this.pageData = Utils.getImageData(this.page);
    this.pagePixels = new Uint32Array(this.pageData.data.buffer);
    this.coloredData = Utils.getImageData(this.colored);
    this.coloredPixels = new Uint32Array(this.coloredData.data.buffer);

    //makesure colored no alpha
    let pixels = new Uint8Array(this.coloredPixels.buffer);
    for (var i = 0; i < this.coloredPixels.length; i++) {
      pixels[i * 4 + 3] = 0xff;
    }

    //cut the map with page.
    for (var i = 0; i < this.mapPixels.length; i++) {
      if (this.pagePixels[i] != 0) this.mapPixels[i] = 0;
    }

    this.createAreaMap();
    console.log(TAG, 'areaMap=', this.areaMap);

    this.process();
    this.colorSum = this.getColorSum();
    
    // //颜色数超过100 自动合并颜色
    // if(this.colorSum.length >= 100) {
    //   this.colorMap = mergeByColorMap(this.colorMap);
    //   this.colorSum = this.getColorSum();
    // }
  }

  process() {
    let areas: FillArea[] = Object.values(this.areaMap);
    this.colorMap = {};
    for (var i = 0; i < areas.length; i++) {
      this.colorMap[areas[i].color] = this.getColorFromColored(areas[i]);
    }
  }

  /**
   * create work blob from the color map.
   * @returns 
   */
  public getWorkBlob() : Promise<Blob> {
    let canvas: HTMLCanvasElement = Utils.createCanvas(this.width, this.height);
    let ctx: CanvasRenderingContext2D = canvas.getContext('2d');
    let imgData: ImageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
    let pixels = new Uint32Array(imgData.data.buffer);
    for (var i = 0; i < pixels.length; i++) {
      if (this.colorMap[this.mapPixels[i]]) {
        pixels[i] = this.colorMap[this.mapPixels[i]].color;
      }
    }
    ctx.putImageData(imgData, 0, 0);
    ctx.drawImage(this.page, 0, 0);
    return new Promise((done, reject) => {
      canvas.toBlob((blob: Blob) => { done(blob); }, 'image/png');
    })
  }


  /**
   * 统计这个区域的所有像素的颜色，选出最具代表的颜色
   * @param area 
   * @returns 
   */
  getColorFromColored(area: FillArea): ColorInfo {
    let ai, aw, i, x, y;
    let sum = {};
    aw = area.width();
    let count = area.width() * area.height();
    for (ai = 0; ai < count; ai++) {
      x = area.left + ai % aw;
      y = area.top + Math.floor(ai / aw);
      i = y * this.width + x;
      if (this.mapPixels[i] == area.color) {
        let color = this.coloredPixels[i];
        if (!sum[color]) sum[color] = 1;
        else sum[color] = sum[color] + 1;
      }
    }
    let maxColor: string;
    let maxCount = 0;
    Object.keys(sum).forEach((color: string) => {
      if (sum[color] > maxCount) {
        maxCount = sum[color];
        maxColor = color;
      }
    });
    //console.log('sum:', sum);
    let colorInt = parseInt(maxColor);
    let colorCss = Utils.getColorFromInteger(colorInt);

    return {
      color: colorInt,
      cssColor: colorCss,
    };
  }


  get width() { return this.page.width }
  get height() { return this.page.height }

  /**
   * Create area map from map pixels.
   */
  createAreaMap() {
    let width = this.width;
    let floodArr = this.mapPixels;
    let areaMap = {};
    let i, x, y, color;
    for (i = 0; i < floodArr.length; i++) {
      color = floodArr[i];
      if (color == 0) continue;
      x = i % width;
      y = Math.floor(i / width);
      if (areaMap[color]) {
        areaMap[color].addPoint(x, y);
      } else {
        areaMap[color] = new FillArea(color, x, y);
      }
    }
    this.areaMap = areaMap;
  }

  public static getColorMap(page: HTMLImageElement, map: HTMLImageElement, colored: HTMLImageElement): ColorMap {
    let acm = new AutoColorMap(page, map, colored);
    return acm.colorMap;
  }


  /**
   * 获取
   * @returns 
   */
  public getColorSum(): ColorSumItem[] {
    let sumHash = {};
    Object.keys(this.colorMap).forEach(_areaIndex => {
      let areaIndex = parseInt(_areaIndex);
      let { color, cssColor } = this.colorMap[areaIndex];
      if (sumHash[color]) {
        sumHash[color].total++;
        sumHash[color].areas.push(areaIndex);
      } else {
        sumHash[color] = {
          total: 1,
          cssColor,
          color,
          areas: [areaIndex]
        }
      }
    })
    return Object.keys(sumHash).map(key => {
      return sumHash[key];
    })
  }
}