
/**
 * Temp canvas for color parse.
 */
var tempCanvas = document.createElement('canvas');
tempCanvas.width = 1;
tempCanvas.height = 1;
var tempCtx = tempCanvas.getContext('2d');

export default class Utils {

  static setImageSmoothing(_ctx: CanvasRenderingContext2D, smoothing: boolean) {
    let ctx = _ctx as any;
    ctx.msImageSmoothingEnabled = smoothing;
    ctx.mozImageSmoothingEnabled = smoothing;
    ctx.webkitImageSmoothingEnabled = smoothing;
    ctx.msImageSmoothingEnabled = smoothing;
    ctx.imageSmoothingEnabled = smoothing;
  }

  static isFunction(functionToCheck) {
    return functionToCheck &&
      {}.toString.call(functionToCheck) === '[object Function]';
  }

  /**
   * Check if image loaded.
   */
  static isLoaded(img) {
    if (!img)
      return false;

    // During the onload event, IE correctly identifies any images that
    // weren’t downloaded as not complete. Others should too. Gecko-based
    // browsers act like NS4 in that they report this incorrectly.
    if (!img.complete) {
      return false;
    }

    // However, they do have two very useful properties: naturalWidth and
    // naturalHeight. These give the true size of the image. If it failed
    // to load, either of these should be zero.
    if (img.naturalWidth === 0) {
      return false;
    }

    // No other way of checking: assume it’s ok.
    return true;
  }

  /**
   * Promise load image.
   */
  static loadImage(url) {
    return new Promise(function (done, reject) {
      var image = new Image();
      image.onload = function () { done(image); };
      image.onerror = reject;
      image.src = url;
    });
  }

  /**
   * Promise load array of images
   */
  static loadImages(urls) {
    var ps = urls.map(function (url) { return Utils.loadImage(url); });
    return Promise.all(ps);
  }

  static createCanvas(width, height) {
    var canvas = document.createElement('canvas');
    canvas.width = width;
    canvas.height = height;
    return canvas;
  }

  static getImageData(image: HTMLImageElement): ImageData {
    let canvas = Utils.createCanvas(image.width, image.height);
    let ctx = canvas.getContext('2d');
    Utils.setImageSmoothing(ctx, false);
    ctx.drawImage(image, 0, 0);
    return ctx.getImageData(0, 0, image.width, image.height);
  }


  static convertToPngBlob(srcImg: HTMLImageElement): Promise<Blob> {
    let canvas = Utils.createCanvas(srcImg.width, srcImg.height);
    let ctx = canvas.getContext('2d');
    Utils.setImageSmoothing(ctx, false);
    ctx.drawImage(srcImg, 0, 0);
    return new Promise((done, reject) => {
      canvas.toBlob((blob: Blob) => done(blob));
    });
  }

  static convertToJpegBlob(srcImg: HTMLImageElement, quality: number = 0.8): Promise<Blob> {
    let canvas = Utils.createCanvas(srcImg.width, srcImg.height);
    let ctx = canvas.getContext('2d');
    Utils.setImageSmoothing(ctx, false);
    ctx.drawImage(srcImg, 0, 0);
    return new Promise((done, reject) => {
      canvas.toBlob((blob: Blob) => done(blob), 'image/jpeg', quality);
    });
  }

  /**
   * parse color, return rgba obj.
   */
  static getRgba(color) {
    tempCtx.fillStyle = color;
    tempCtx.fillRect(0, 0, 1, 1);
    let imgData = tempCtx.getImageData(0, 0, 1, 1);
    return {
      red: imgData.data[0], green: imgData.data[1], blue: imgData.data[2],
      alpha: imgData.data[3],
    }
  }

  static getColorInteger(color) {
    tempCtx.fillStyle = color;
    tempCtx.fillRect(0, 0, 1, 1);
    let imgData = tempCtx.getImageData(0, 0, 1, 1);
    let arr = new Uint32Array(imgData.data.buffer);
    return arr[0];
  }

  static getColorFromInteger(intColor) {
    //console.log('getColorFromInteger: ', intColor);
    let a = new Uint32Array(1)
    a[0] = intColor;
    let b = new Uint8Array(a.buffer);
    return `rgba(${b[0]},${b[1]},${b[2]},${b[3] / 255})`;
  }


  static toHsl(color) {
    tempCtx.fillStyle = color;
    tempCtx.fillRect(0, 0, 1, 1);
    let imgData = tempCtx.getImageData(0, 0, 1, 1);
  }

  /**
   * 将任意颜色转换成hex， 忽略透明度
   * @param colorStr 
   * @returns 
   */
  static colorToHex(colorStr): string {
    let arr: Uint32Array = new Uint32Array(1);
    arr[0] = this.getColorInteger(colorStr);
    let buf: Uint8Array = new Uint8Array(arr.buffer);
    let r = buf[0].toString(16).padStart(2, '0').toUpperCase();
    let g = buf[1].toString(16).padStart(2, '0').toUpperCase();
    let b = buf[2].toString(16).padStart(2, '0').toUpperCase();
    return `#${r}${g}${b}`;
  }

  static makeRgba(rgba) {
    return 'rgba(' + rgba.red + ',' + rgba.green + ',' + rgba.blue + ',' +
      rgba.alpha / 255 + ')';
  }

  static transparentColor(color) { return Utils.alphaColor(color, 0); }

  static alphaColor(color, alpha) {
    let rgba = Utils.getRgba(color);
    rgba.alpha = alpha * 255;
    return Utils.makeRgba(rgba);
  }

  static randomColor() {
    return Utils.makeRgba({
      red: Math.round(Math.random() * 255),
      green: Math.round(Math.random() * 255),
      blue: Math.round(Math.random() * 255),
      alpha: 255,
    });
  }

  // 计算两个颜色的距离
  static colorDistance(c1: number, c2: number): number {
    let a1 = (c1 >> 24) & 0xff;
    let b1 = (c1 >> 16) & 0xff;
    let g1 = (c1 >> 8) & 0xff;
    let r1 = c1 & 0xff;

    let a2 = (c2 >> 24) & 0xff;
    let b2 = (c2 >> 16) & 0xff;
    let g2 = (c2 >> 8) & 0xff;
    let r2 = c2 & 0xff;

    let rr = r1 - r2;
    let gg = g1 - g2;
    let bb = b1 - b2;

    let dist = Math.sqrt(rr * rr + gg * gg + bb * bb) / 255;

    if (dist < 0.01) {
      console.log(`${c1}, ${c2}, dist:${dist}`);
      console.log(r1, g1, b1, a1);
      console.log(r2, g2, b2, a2);
    }

    return dist;
  }

  /**
   * Draw rounded corners rect.
   */
  static roundedCornersRect(ctx, left, top, width, height, radius) {
    // console.log('Utils@roundedCornersRect() ', left, top, width, height,
    // radius);
    let right = left + width;
    let bottom = top + height;
    ctx.beginPath();
    ctx.moveTo(left + radius, top);
    ctx.lineTo(right - radius, top);
    ctx.arcTo(right, top, right, top + radius, radius);
    ctx.lineTo(right, bottom - radius);
    ctx.arcTo(right, bottom, right - radius, bottom, radius)
    ctx.lineTo(left + radius, bottom);
    ctx.arcTo(left, bottom, left, bottom - radius, radius);
    ctx.lineTo(left, top + radius);
    ctx.arcTo(left, top, left + radius, top, radius);
    ctx.closePath();
  }

  /**
   * Get distance of p1 and p2.
   */
  static distance(p1, p2) {
    let dx = p1.x - p2.x;
    let dy = p1.y - p2.y;
    let dist = Math.sqrt(dx * dx + dy * dy);
    return dist;
  }

  /*
   * Get the angle of p1 and p2.
   */
  static angle(p1, p2) {
    let dx = p2.x - p1.x;
    let dy = p2.y - p1.y;
    return Math.atan2(dy, dx);
  }

  /**
   * Fill points between p1 and p2, by specified gap.
   */
  static fillPoints(p1, p2, gap) {
    let dist = Utils.distance(p1, p2);
    let angle = Utils.angle(p1, p2);
    let i;
    let pts = [], p;
    for (i = gap; i < dist; i += gap) {
      p = {};
      p.x = p1.x + i * Math.cos(angle);
      p.y = p1.y + i * Math.sin(angle);
      pts.push(p);
    }
    return pts;
  }

  /**
   * Create scaled image.
   */
  static createScaledImage(image, scale): Promise<HTMLImageElement> {
    let width = Math.round(image.width * scale);
    let height = Math.round(image.height * scale);
    let canvas = Utils.createCanvas(width, height);
    let ctx = canvas.getContext('2d');
    Utils.setImageSmoothing(ctx, false);
    ctx.drawImage(image, 0, 0, image.width, image.height, 0, 0, width, height);

    return new Promise(function (done, reject) {
      let img = new Image();
      img.onload = function () { done(img); };
      img.onerror = reject;
      img.src = canvas.toDataURL();
    });
  }

  /**
   * load file as array buffer.
   */
  static loadFileAsArrayBuffer(file: Blob) {
    return new Promise(function (done, reject) {
      let reader = new FileReader();
      reader.onload = function (e: any) { done(e.target.result); };
      reader.onerror = reject;
      reader.readAsArrayBuffer(file);
    });
  }

  /**
   * 将blob对象转成图片对象
   * @param blob 
   * @returns 
   */
  static blobToImage(blob: Blob): Promise<HTMLImageElement> {
    return new Promise((done, reject) => {
      let reader = new FileReader();
      let image = new Image();
      image.onerror = reject;
      image.onload = () => done(image);
      reader.addEventListener('load', () => {
        image.src = reader.result as string;
      }, false);
      reader.readAsDataURL(blob);
    });
  }


  /**
   * Convert image to png blob.
   * @param inputImg 
   * @returns 
   */
  static toPngBlob(inputImg: HTMLImageElement): Promise<Blob> {
    let canvas = Utils.createCanvas(inputImg.width, inputImg.height);
    let ctx = canvas.getContext('2d');
    ctx.drawImage(inputImg, 0, 0);
    return new Promise((done, reject) => {
      return canvas.toBlob(blob => done(blob), 'image/png');
    });
  }

  /**
   * convert image to dataURL
   * @param inputImg 
   * @param type inputImg type, default: image/png
   */
  static imageToDataURL(inputImg: HTMLImageElement, type?: string): string {
    let canvas = Utils.createCanvas(inputImg.width, inputImg.height);
    let ctx = canvas.getContext('2d');
    ctx.drawImage(inputImg, 0, 0);
    return canvas.toDataURL();
  }


  /**
   *
   * Count differenct colors of image
   */
  static countColors(image) {
    let imageData = Utils.getImageData(image);
    let pixels = new Uint32Array(imageData.data.buffer);
    let p, hash = {};
    for (let i = 0; i < pixels.length; i++) {
      p = pixels[i];
      if (hash[p])
        hash[p]++;
      else
        hash[p] = 1;
    }
    return Object.keys(hash).length;
  }



  static loadImageFromUrl(url): Promise<HTMLImageElement> {
    return new Promise((done, reject) => {
      let image = new Image();
      image.onload = () => done(image);
      image.onerror = reject;
      image.src = url;
    });
  }

  /**
   * Return image from a base64 string.
   * @param buffer 
   */
  static base64ToImage(base64str, mime): Promise<HTMLImageElement> {
    mime = mime || 'image/png';
    //if (!base64str) return ;
    let dataURI = `data:${mime};base64,${base64str}`;
    //console.log('dataURI: ', dataURI);
    return new Promise((done, reject) => {
      let image = new Image();
      image.onload = () => { done(image) }
      image.onerror = function (error) {
        let e = new Error(`base64ToImage failed with dataURI:${dataURI}`);
        reject(e);
      };
      image.src = dataURI;
    })
  }



  /**
   * 
   * @returns 当前是否全屏
   */
  public static isFullscreen() {
    let _doc: any = document;
    return _doc && (_doc.fullscreenElement || _doc.mozFullScreenElement ||
      _doc.webkitFullscreenElement || _doc.msFullscreenElement);

  }

  /**
   * 切换全屏
   * @param elem 
   */
  public static async toggleFullscreen(elem?) {
    try {
      elem = elem || document.documentElement;
      let _elem: any = elem;
      let _doc: any = document;

      if (!_doc.fullscreenElement && !_doc.mozFullScreenElement &&
        !_doc.webkitFullscreenElement && !_doc.msFullscreenElement) {
        if (_elem.requestFullscreen) {
          await _elem.requestFullscreen();
        } else if (_elem.msRequestFullscreen) {
          await _elem.msRequestFullscreen();
        } else if (_elem.mozRequestFullScreen) {
          await _elem.mozRequestFullScreen();
        } else if (_elem.webkitRequestFullscreen) {
          let _element: any = Element;
          await _elem.webkitRequestFullscreen(_element.ALLOW_KEYBOARD_INPUT);
        }
      } else {
        if (_doc.exitFullscreen) {
          await _doc.exitFullscreen();
        } else if (_doc.msExitFullscreen) {
          await _doc.msExitFullscreen();
        } else if (_doc.mozCancelFullScreen) {
          await _doc.mozCancelFullScreen();
        } else if (_doc.webkitExitFullscreen) {
          await _doc.webkitExitFullscreen();
        }
      }
    } catch (e) {
      console.warn(e);
    }
  }


  /*
static betterColor(hexColor) {
  let hsl = Utils.hexToHsl(hexColor);
  let out = hsluv.hsluvToHex(hsl);
  return out;
}


static hexToHsl(H) {
  let ex = /^#([\da-f]{3}){1,2}$/i;
  if (ex.test(H)) {
    // convert hex to RGB first
    let r = 0,
      g = 0,
      b = 0;
    if (H.length == 4) {
      r = "0x" + H[1] + H[1];
      g = "0x" + H[2] + H[2];
      b = "0x" + H[3] + H[3];
    } else if (H.length == 7) {
      r = "0x" + H[1] + H[2];
      g = "0x" + H[3] + H[4];
      b = "0x" + H[5] + H[6];
    }
    // then to HSL
    r /= 255;
    g /= 255;
    b /= 255;
    let cmin = Math.min(r, g, b),
      cmax = Math.max(r, g, b),
      delta = cmax - cmin,
      h = 0,
      s = 0,
      l = 0;

    if (delta == 0)
      h = 0;
    else if (cmax == r)
      h = ((g - b) / delta) % 6;
    else if (cmax == g)
      h = (b - r) / delta + 2;
    else
      h = (r - g) / delta + 4;

    h = Math.round(h * 60);

    if (h < 0)
      h += 360;

    l = (cmax + cmin) / 2;
    s = delta == 0 ? 0 : delta / (1 - Math.abs(2 * l - 1));
    s = +(s * 100).toFixed(1);
    l = +(l * 100).toFixed(1);

    //return "hsl(" + h + "," + s + "%," + l + "%)";
    return [Math.round(h), Math.round(s), Math.round(l)];

  } else {
    return "Invalid input color";
  }
}
*/

  public static delay(ms): Promise<any> {
    return new Promise((done) => {
      setTimeout(done, ms);
    });
  }


}
