'use strict';

var Thing = require('./thing.js');

/**
 * Note: this is not used as a subclass for Circle since drawing ovals
 * is much more complex than drawing circles, and there is no point in
 * complicating the drawing just for some code reuse.
 */

/**
 * @class Oval
 * @augments Thing
 * @param {number} radius - Desired radius
 */
function Oval(width, height) {
  if (typeof width != 'number' || typeof height != 'number') {
    throw new TypeError('You must pass two numbers to new Oval(width, height)');
  }

  Thing.call(this);
  this.width = width;
  this.height = height;
  this.type = 'Oval';
}

Oval.prototype = new Thing();
Oval.prototype.constructor = Oval;

/**
 * Draws an ellipse centered at this.x and this.y.
 * adapted from http://stackoverflow.com/questions/2172798/
 * how-to-draw-an-oval-in-html5-canvas
 * @param {CodeHSGraphics} __graphics__ - Instance of the __graphics__ module.
 */
Oval.prototype.draw = function(__graphics__) {
  var context = __graphics__.getContext();

  var w = this.width,
      h = this.height,
      x = this.x - w / 2,
      y = this.y - h / 2;

  var kappa = 0.5522848,
      ox = (w / 2) * kappa, // control point offset horizontal
      oy = (h / 2) * kappa, // control point offset vertical
      xe = x + w,           // x-end
      ye = y + h,           // y-end
      xm = x + w / 2,       // x-middle
      ym = y + h / 2;       // y-middle

  context.beginPath();
  context.moveTo(x, ym);
  context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y);
  context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym);
  context.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye);
  context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym);

  context.fillStyle = this.color.toString();
  context.fill();

  if (this.hasBorder) {
    context.strokeStyle = this.stroke.toString();
    context.lineWidth = this.lineWidth;
    context.stroke();
  }

  context.closePath();
};

/**
 * Gets the height of the oval.
 * @returns {number} Height of the oval.
 */
Oval.prototype.getHeight = function() {
  return this.height;
};

/**
 * Gets the width of the oval.
 * @returns {number} Width of the oval.
 */
Oval.prototype.getWidth = function() {
  return this.width;
};

/**
 * Sets the width of the oval.
 * @param {number} width - Desired width of the resulting oval.
 */
Oval.prototype.setWidth = function(width) {
  this.width = width;
};

/**
 * Sets the height of the oval.
 * @param {number} height - Desired height of the resulting oval.
 */
Oval.prototype.setHeight = function(height) {
  this.height = height;
};

/**
 * Checks if the passed point is contained in the oval.
 * Uses the equation for an oval.
 * @param {number} x - The x coordinate of the point being tested.
 * @param {number} y - The y coordinate of the point being tested.
 * @returns {boolean} Whether the passed point is contained in the circle.
 */
Oval.prototype.containsPoint = function(x, y) {
  var xRadiusSquared = Math.pow(this.width / 2, 2);
  var yRadiusSquared = Math.pow(this.height / 2, 2);
  var xDifferenceSquared = Math.pow(x - this.x, 2);
  var yDifferenceSquared = Math.pow(y - this.y, 2);

  var result = xDifferenceSquared / xRadiusSquared +
    yDifferenceSquared / yRadiusSquared;

  return result <= 1;
};

module.exports = Oval;
