/*
 * Copyright (c) Joshua John Lawrence 2012, all rights reserved.
 *
 * This file is hardly complete for a maths library, but overkill for the
 * task this demo performs. I've written it in the style I would use in a real
 * product, expecting it to grow with reuse and needing it to be maintainable.
 */

/*
 * A 2D vector. Arguments must be numeric. Immutable.
 *
 * Immutable objects are a habit I have picked up from Java. They're easy to code
 * and easy to use correctly. However, they obviously are expensive in memory
 * allocation and work the garbage collector. So, I optimise when I need to.
 *
 * I also make use of the way a nested function retains a reference to the stack
 * frame that created it to implement private members and methods, another habit
 * from the OO world. This class has private members, mandlerbrot.js has examples
 * of private methods.
 */
function Vector( x, y ) {

  /*
   * Get the x ordinate.
   */
  this.getX = function() { return x; };

  /*
   * Get the y ordinate.
   */
  this.getY = function() { return y; };

  /*
   * Add the Vector v to this, returning the answer.
   */
  this.plus = function( v ) {
    return new Vector( x + v.getX(), y + v.getY() );
  };

  /*
   * For debugging.
   */
  this.toString = function() {
    return "( " + x + ", " + y + " )";
  };
}

/*
 * A 2x2 Matrix. Arguments must be numeric. Immutable.
 */
function Matrix( tl, tr, bl, br ) {

  /*
   * Multiply this by the Vector v, returning the answer.
   */
  this.times = function( v ) {
	  return new Vector(
	    tl * v.getX() + tr * v.getY(),
	    bl * v.getX() + br * v.getY()
	  );
  };
}

/*
 * A complex number. Arguments must be numeric. Mutable for performance.
 */
function Complex( re, im ) {

  /*
   * Get the real portion of the number.
   */
  this.getReal = function() { return re; };

  /*
   * Get the imaginary portion of the number, divided by i.
   */
  this.getImaginary = function() { return im; };

  /*
   * Add the Complex z to this, returning the answer.
   */
  this.plus = function( z ) {
    return new Complex( re + z.getReal(), im + z.getImaginary() );
  };

  /*
   * Find the square of this.
   */
  this.squared = function() {
    return new Complex( re * re - im * im, 2 * re * im );
  };

  /*
   * Square this, then add the Complex z. Mutates this.
   *
   * Replaces a call to squared() and plus() for speed.
   */
  this.inlineSquaredPlus = function( z ) {
    var newRe = re * re - im * im + z.getReal();
    var newIm = 2 * re * im + z.getImaginary();
    re = newRe;
    im = newIm;
  };

  /*
   * Find the square of the modulus of this.
   *
   * Omits the square root for speed.
   */
  this.modulusSquared = function() {
    return re * re + im * im;
  };

  /*
   * Deep copy this, since we have mutators.
   */
  this.copy = function() {
    return new Complex( re, im );
  };

  /*
   * For debugging.
   */
  this.toString = function() {
    return re + " + " + im + "i";
  };
}