import * as echarts from 'echarts/lib/echarts';

function makeSprite(size, canvas, draw) {
  // http://simonsarris.com/blog/346-how-you-clear-your-canvas-matters
  // http://jsperf.com/canvasclear
  // Set width and height is fast
  // And use the exist canvas if possible
  // http://jsperf.com/create-canvas-vs-set-width-height/2
  var canvas = canvas || document.createElement('canvas');
  canvas.width = size;
  canvas.height = size;
  var ctx = canvas.getContext('2d');
  draw && draw(ctx);
  return canvas;
}

function makePath(symbol, symbolSize, style, marginBias) {
  if (!echarts.util.isArray(symbolSize)) {
    symbolSize = [symbolSize, symbolSize];
  }

  var margin = spriteUtil.getMarginByStyle(style, marginBias);
  var width = symbolSize[0] + margin.left + margin.right;
  var height = symbolSize[1] + margin.top + margin.bottom;
  var path = echarts.helper.createSymbol(symbol, 0, 0, symbolSize[0], symbolSize[1]);
  var size = Math.max(width, height);
  path.x = margin.left;
  path.y = margin.top;

  if (width > height) {
    path.y += (size - height) / 2;
  } else {
    path.x += (size - width) / 2;
  }

  var rect = path.getBoundingRect();
  path.x -= rect.x;
  path.y -= rect.y;
  path.setStyle(style);
  path.update();
  path.__size = size;
  return path;
} // http://www.valvesoftware.com/publications/2007/SIGGRAPH2007_AlphaTestedMagnification.pdf


function generateSDF(ctx, sourceImageData, range) {
  var sourceWidth = sourceImageData.width;
  var sourceHeight = sourceImageData.height;
  var width = ctx.canvas.width;
  var height = ctx.canvas.height;
  var scaleX = sourceWidth / width;
  var scaleY = sourceHeight / height;

  function sign(r) {
    return r < 128 ? 1 : -1;
  }

  function searchMinDistance(x, y) {
    var minDistSqr = Infinity;
    x = Math.floor(x * scaleX);
    y = Math.floor(y * scaleY);
    var i = y * sourceWidth + x;
    var r = sourceImageData.data[i * 4];
    var a = sign(r); // Search for min distance

    for (var y2 = Math.max(y - range, 0); y2 < Math.min(y + range, sourceHeight); y2++) {
      for (var x2 = Math.max(x - range, 0); x2 < Math.min(x + range, sourceWidth); x2++) {
        var i = y2 * sourceWidth + x2;
        var r2 = sourceImageData.data[i * 4];
        var b = sign(r2);
        var dx = x2 - x;
        var dy = y2 - y;

        if (a !== b) {
          var distSqr = dx * dx + dy * dy;

          if (distSqr < minDistSqr) {
            minDistSqr = distSqr;
          }
        }
      }
    }

    return a * Math.sqrt(minDistSqr);
  }

  var sdfImageData = ctx.createImageData(width, height);

  for (var y = 0; y < height; y++) {
    for (var x = 0; x < width; x++) {
      var dist = searchMinDistance(x, y);
      var normalized = dist / range * 0.5 + 0.5;
      var i = (y * width + x) * 4;
      sdfImageData.data[i++] = (1.0 - normalized) * 255;
      sdfImageData.data[i++] = (1.0 - normalized) * 255;
      sdfImageData.data[i++] = (1.0 - normalized) * 255;
      sdfImageData.data[i++] = 255;
    }
  }

  return sdfImageData;
}

var spriteUtil = {
  getMarginByStyle: function (style) {
    var minMargin = style.minMargin || 0;
    var lineWidth = 0;

    if (style.stroke && style.stroke !== 'none') {
      lineWidth = style.lineWidth == null ? 1 : style.lineWidth;
    }

    var shadowBlurSize = style.shadowBlur || 0;
    var shadowOffsetX = style.shadowOffsetX || 0;
    var shadowOffsetY = style.shadowOffsetY || 0;
    var margin = {};
    margin.left = Math.max(lineWidth / 2, -shadowOffsetX + shadowBlurSize, minMargin);
    margin.right = Math.max(lineWidth / 2, shadowOffsetX + shadowBlurSize, minMargin);
    margin.top = Math.max(lineWidth / 2, -shadowOffsetY + shadowBlurSize, minMargin);
    margin.bottom = Math.max(lineWidth / 2, shadowOffsetY + shadowBlurSize, minMargin);
    return margin;
  },
  // TODO Not consider shadowOffsetX, shadowOffsetY.

  /**
   * @param {string} symbol
   * @param {number | Array.<number>} symbolSize
   * @param {Object} style
   */
  createSymbolSprite: function (symbol, symbolSize, style, canvas) {
    var path = makePath(symbol, symbolSize, style);
    var margin = spriteUtil.getMarginByStyle(style);
    return {
      image: makeSprite(path.__size, canvas, function (ctx) {
        echarts.innerDrawElementOnCanvas(ctx, path);
      }),
      margin: margin
    };
  },
  createSDFFromCanvas: function (canvas, size, range, outCanvas) {
    // TODO Create a low resolution SDF from high resolution image.
    return makeSprite(size, outCanvas, function (outCtx) {
      var ctx = canvas.getContext('2d');
      var imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);
      outCtx.putImageData(generateSDF(outCtx, imgData, range), 0, 0);
    });
  },
  createSimpleSprite: function (size, canvas) {
    return makeSprite(size, canvas, function (ctx) {
      var halfSize = size / 2;
      ctx.beginPath();
      ctx.arc(halfSize, halfSize, 60, 0, Math.PI * 2, false);
      ctx.closePath();
      var gradient = ctx.createRadialGradient(halfSize, halfSize, 0, halfSize, halfSize, halfSize);
      gradient.addColorStop(0, 'rgba(255, 255, 255, 1)');
      gradient.addColorStop(0.5, 'rgba(255, 255, 255, 0.5)');
      gradient.addColorStop(1, 'rgba(255, 255, 255, 0)');
      ctx.fillStyle = gradient;
      ctx.fill();
    });
  }
};
export default spriteUtil;