function Canvas() {}

Canvas.prototype.drawStrokeRect = function(
    ctx, color, x, y, width, height, lineWidth) {
  ctx.strokeStyle = color;
  ctx.lineWidth = lineWidth;
  ctx.strokeRect(x, y, width, height);
}

Canvas.prototype.drawFillRect = function(ctx, color, x, y, width, height) {
  ctx.fillStyle = color;
  ctx.fillRect(x, y, width, height);
}

Canvas.prototype.drawEllipse = function(
    ctx, color, x, y, xAxis, yAxis, lineWidth, type) {
  var startX = x + xAxis;
  var startY = y;
  ctx.beginPath();
  ctx.lineWidth = lineWidth;
  ctx.moveTo(startX, startY);
  for (var i = 0; i <= 360; i++) {
    var degree = i * Math.PI / 180;
    startX = x + (xAxis - 2) * Math.cos(degree);
    startY = y - (yAxis - 2) * Math.sin(degree);
    ctx.lineTo(startX, startY);
  }
  if (type == 'rect') {
    ctx.fillStyle = changeColorToRgba(color, 0.5);
    ctx.fill();
  } else if (type == 'border') {
    ctx.strokeStyle = color;
    ctx.stroke();
  }
  ctx.closePath();
}

// Divide an entire phrase in an array of phrases, all with the max pixel
// length given.
Canvas.prototype.getLines = function(ctx, text, width, font) {
  var words = text.split(" ");
  var lines = [];
  var lastLine = "";
  var measure = 0;
  ctx.font = font;
  for (var i = 0; i < words.length; i++) {
    var word = words[i];
    measure = ctx.measureText(lastLine + word).width;
    if (measure <= width || word == "") {
      lastLine += word + " ";
    } else {
      if (lastLine != "")
        lines.push(lastLine);

      // break the word if necessary 
      measure = ctx.measureText(word).width;
      if (measure <= width) {
        lastLine = word + " ";
      } else {
        lastLine = word[0];
        for (var j = 1; j < word.length; j++) {
          measure = ctx.measureText(lastLine + word[j]).width;
          if (measure <= width) {
            lastLine += word[j];
          } else {
            lines.push(lastLine);
            lastLine = word[j];
          } 
        }
        lastLine += " ";
      }
    }
  }
  if (lastLine != "")
    lines.push(lastLine);
  return lines;
}

Canvas.prototype.setText = function(
    ctx, text, color, fontSize, fontFamily, lineHeight, x, y, width) {
  ctx.textBaseline = 'top';
  ctx.fillStyle = color;
  ctx.font = fontSize + ' ' + fontFamily;
  ctx.lineHeight = lineHeight;
  var lines = Canvas.prototype.getLines(ctx, text, width - 2, ctx.font);
  for (var i = 0; i < lines.length; i++)
    ctx.fillText(lines[i], x, y + lineHeight * i, width);
}

Canvas.prototype.drawLine = function(
    ctx, color, lineCap, lineWidth, startX, startY, endX, endY) {
  ctx.beginPath();
  ctx.moveTo(startX, startY);
  ctx.strokeStyle = color;
  ctx.lineWidth = lineWidth;
  ctx.lineCap = lineCap;
  ctx.lineTo(endX, endY);
  ctx.closePath();
  ctx.stroke();
}

Canvas.prototype.drawArrow = function(
    ctx, color, lineWidth, arrowWidth, arrowHeight, lineCap,
    startX, startY, endX, endY) {
  var arrowCoordinates = calculateArrowCoordinates(
      arrowWidth, arrowHeight,startX, startY, endX, endY);
  ctx.beginPath();
  ctx.strokeStyle = color;
  ctx.lineWidth = lineWidth;
  ctx.lineCap = lineCap;
  ctx.moveTo(startX, startY);
  ctx.lineTo(endX, endY);
  ctx.lineTo(arrowCoordinates.p1.x, arrowCoordinates.p1.y);
  ctx.moveTo(endX, endY);
  ctx.lineTo(arrowCoordinates.p2.x, arrowCoordinates.p2.y);
  ctx.closePath();
  ctx.stroke();
}

Canvas.prototype.drawRoundedRect = function(
    ctx, color, x, y, width, height, radius, type) {
  ctx.beginPath();
  ctx.moveTo(x, y + radius);
  ctx.lineTo(x, y + height - radius);
  ctx.quadraticCurveTo(x, y + height, x + radius, y + height);
  ctx.lineTo(x + width - radius, y + height);
  ctx.quadraticCurveTo(x + width, y + height, x + width, y + height - radius);
  ctx.lineTo(x + width, y + radius);
  ctx.quadraticCurveTo(x + width, y, x + width - radius, y);
  ctx.lineTo(x + radius, y);
  ctx.quadraticCurveTo(x, y, x, y + radius);
  if (type == 'rect') {
    ctx.fillStyle = changeColorToRgba(color, 0.5);
    ctx.fill();
  } else if (type == 'border') {
    ctx.strokeStyle = color;
    ctx.lineWidth = 2;
    ctx.stroke();
  }
  ctx.closePath();
}

Canvas.prototype.blurImage = function(
    realCanvas, simulateCanvas, layerId, startX, startY, endX, endY) {
  var x = startX < endX ? startX : endX;
  var y = startY < endY ? startY : endY;
  var width = Math.abs(endX - startX - 1);
  var height = Math.abs(endY - startY - 1);
  simulateCanvas.width = $(layerId).clientWidth + 10;
  simulateCanvas.height = $(layerId).clientHeight + 10;
  var ctx = simulateCanvas.getContext('2d');
  try {
    ctx.drawImage(realCanvas, x, y, width, height, 0, 0, width, height);
  } catch(error) {
    console.log(error + ' width : height' + width + ' : ' + height) ;
  }
  var imageData = ctx.getImageData(0, 0, width, height);
  imageData = this.boxBlur(imageData, width, height, 10);
  ctx.putImageData(imageData, 0, 0);
}

Canvas.prototype.boxBlur = function(image, width, height, count) {
  var j;
  var pix = image.data;
  var inner = 0;
  var outer = 0;
  var step = 0;
  var rowOrColumn;
  var nextPosition;
  var nowPosition;
  for(rowOrColumn = 0; rowOrColumn < 2; rowOrColumn++) {
    if (rowOrColumn) {
      // column blurring
      outer = width;
      inner = height;
      step = width * 4;
    } else {
      // Row blurring
      outer = height;
      inner = width;
      step = 4;
    }
    for (var i = 0; i < outer; i++) {
      // Calculate for r g b a
      nextPosition = (rowOrColumn == 0 ? (i * width * 4) : (4 * i));
      for (var k = 0; k < 4; k++) {
        nowPosition = nextPosition + k;
        var pixSum = 0;
          for(var m = 0; m < count; m++) {
            pixSum += pix[nowPosition + step * m];
          }
          pix[nowPosition] = pix[nowPosition + step] =
              pix[nowPosition + step * 2] = Math.floor(pixSum/count);
          for (j = 3; j < inner-2; j++) {
            pixSum = Math.max(0, pixSum - pix[nowPosition + (j - 2) * step]
                + pix[nowPosition + (j + 2) * step]);
            pix[nowPosition + j * step] = Math.floor(pixSum/count);
          }
          pix[nowPosition + j * step] = pix[nowPosition + (j + 1) * step] =
              Math.floor(pixSum / count);
      }
    }
  }
  return image;
}

function changeColorToRgba(color, opacity) {
  var sColor = color.toLowerCase();
  var sColorChange = [];
  for (var i = 1; i < sColor.length; i += 2) {
    sColorChange.push(parseInt("0x" + sColor.slice(i, i + 2)));
  }
  return "rgba(" + sColorChange.join(",") + "," + opacity + ")";
}

// Calculate coordinates of arrow
function calculateArrowCoordinates(
    arrowWidth, arrowHeight, startX, startY, endX, endY) {
  var p1 = function() {
    var x = startX - endX;
    var y = startY - endY;
    var hypotenuse = Math.sqrt(x * x + y * y);
    hypotenuse = (hypotenuse == 0 ? arrowHeight : hypotenuse);
    var dx = Math.round(x / hypotenuse * arrowHeight);
    var dy = Math.round(y / hypotenuse * arrowHeight);
    return {x: endX + dx, y: endY + dy};
  }

  var p2 = function(p1, direct) {
    var x = p1.x - startX;
    var y = p1.y - startY;
    var hypotenuse = Math.sqrt(x * x + y * y);
    hypotenuse = (hypotenuse == 0 ? arrowHeight : hypotenuse);
    var dx = Math.round((y / hypotenuse * arrowWidth) * direct);
    var dy = Math.round((x / hypotenuse * arrowWidth) * direct);
    return {x: p1.x + dx, y: p1.y - dy }
  }

  return {p1:p2(p1(), 1), p2: p2(p1(), -1) } ;
}


