// Rectangle.js: Defines Rectangle object class

function Rectangle_Width() {
  return this.right - this.left;
}

function Rectangle_Height() {
  return this.top - this.bottom;
}

function Rectangle_CenterX() {
  return (this.left + this.right) / 2.0;
}

function Rectangle_CenterY() {
  return (this.bottom + this.top) / 2.0;
}

function Rectangle_Offset(dx,dy) {
  if (dx) {
    this.left = this.left + dx;
    this.right = this.right + dx;
  }
  if (dy) {
    this.top = this.top + dy;
    this.bottom = this.bottom + dy;
  }
  return this;
}

function Rectangle_Scale(xfactor, yfactor) {
  if (!yfactor) yfactor = xfactor;

  var cx = (this.left + this.right);
  var cy = (this.bottom + this.top);
  var newW = this.width() * xfactor;
  var newH = this.height() * yfactor;
  this.left = (cx - newW)/2; 
  this.right = (cx + newW)/2;
  this.bottom = (cy - newH)/2; 
  this.top = (cy + newH)/2;
  return this;
}

function Rectangle_Round(magnitude) {
  if (!magnitude) magnitude = 1;

  this.left = magnitude * Math.floor(this.left / magnitude);
  this.bottom = magnitude * Math.floor(this.bottom / magnitude);
  this.right = magnitude * Math.ceil(this.right / magnitude);
  this.top = magnitude * Math.ceil(this.top / magnitude);
  return this;
}

function Rectangle_Clip(cage) {
  if (this.top > cage.top) 
    this.top = cage.top;
  if (this.bottom < cage.bottom) 
    this.bottom = cage.bottom;
  if (this.left < cage.left)
    this.left = cage.left;
  if (this.right > cage.right)
    this.right = cage.right;
  if (this.top < this.bottom) {
    this.top = null; this.bottom = null;
  }
  if (this.right < this.left) {
    //this.right = null; this.left = null;
  }

  return this;
}

function Rectangle_Constrain(cage) {
  var xoffset = 0;
  var yoffset = 0;
  var clipped = false;
  
  var origWidth = this.right - this.left;
  var origHeight = this.top - this.bottom;
  
  if (origWidth > cage.width()) {
    this.left = cage.left + 0;
    this.right = cage.right + 0;
    clipped = true;
  } else if (this.right > cage.right) {
    xoffset = cage.right - this.right;
  } else if (this.left < cage.left) {
    xoffset = cage.left - this.left;
  }
  
  if (origHeight > cage.height()) {
    this.top = cage.top + 0;
    this.bottom = cage.bottom + 0;
    clipped = true;
  } else if (this.top > cage.top) {
    yoffset = cage.top - this.top;
  } else if (this.bottom < cage.bottom) {
    yoffset = cage.bottom - this.bottom;
  }

  this.offset(xoffset, yoffset);
  
  if (clipped) {
    this.applyAspectRatio(origWidth, origHeight);
  }
  
  return this;
}


function Rectangle_Intersects(rect) {
  var test = rect.clone().clip(this);
  return (test.width() > 0) && (test.height() > 0);
}

function Rectangle_Contains(rect) {
  return (this.right >= rect.right) && (this.left <= rect.left)
    && (this.top >= rect.top) && (this.bottom <= rect.bottom);
}

function Rectangle_Clone() {
  return new Rectangle(this.left+0, this.bottom+0, this.right+0, this.top+0);
}

function Rectangle_ApplyAspectRatio(x, y) {
  if (!(y && this.height())) {
    this.bottom = this.top = this.centerY();
  } else if (x && this.width()) {
    var curAspect = this.width() / this.height();
    var newAspect = x / y;
    if (newAspect > curAspect) {
      this.scale(newAspect / curAspect, 1);
    } else if (newAspect < curAspect) {
      this.scale(1, curAspect / newAspect);
    }
  } else if (this.width()) {
    this.left = this.right = this.centerX();
  }
  return this;
}
    


function Rectangle_ToString() {
  return "Rectangle(" + this.left + "," + this.bottom + "," + this.right + "," + this.top + ")";
}

function Rectangle_SetMethods(vtbl) {
  vtbl.width = Rectangle_Width; 
  vtbl.height = Rectangle_Height;
  vtbl.centerX = Rectangle_CenterX;
  vtbl.centerY = Rectangle_CenterY;
  
  vtbl.toString = Rectangle_ToString;

  vtbl.intersects = Rectangle_Intersects;
  vtbl.contains = Rectangle_Contains;

  vtbl.clone = Rectangle_Clone;
  vtbl.offset = Rectangle_Offset; 
  vtbl.scale = Rectangle_Scale;

  vtbl.round = Rectangle_Round;
  vtbl.clip = Rectangle_Clip;
  vtbl.constrain = Rectangle_Constrain;
  vtbl.applyAspectRatio = Rectangle_ApplyAspectRatio;

  return;
}


function Rectangle(l,b,r,t) {
  this.left=l;
  this.bottom=b;
  this.right=r;
  this.top=t;
  if (!Rectangle.prototype) Rectangle_SetMethods(this);
}


new Rectangle(0,0,0,0);
if (Rectangle.prototype) Rectangle_SetMethods(Rectangle.prototype);




/**
 * These materials were developed by ESRI Canada and delivered under
 * contract to ECO-NOVA Productions.  The following license terms and
 * disclaimers apply.
 * 
 * Unless otherwise stated, the definition of "deliverables" includes the
 * complete contents of this file.  However, "deliverables" shall not not
 * include software, data and documentation that is subject to a separate
 * license from Environmental Systems Research Institute, Inc. of USA.
 * 
 * Copyright (c) 1997-2004 ESRI Canada Limited.
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this original work of authorship including all deliverables, to
 * deal with the deliverables without restriction, including without
 * limitation the rights to use, copy, modify, merge, publish, distribute,
 * sublicense, and/or sell copies of the deliverables, and to permit
 * persons to whom the deliverables are furnished to do so, subject to the
 * following conditions:
 * 
 *  * The above copyright notice and this permission notice shall be
 *    included in all copies of the software.
 *  
 *  * The name ESRI Canada shall not be used to endorse or promote
 *    products derived from the the software without specific prior
 *    written permission.
 * 
 * To the maximum extent permitted by applicable law, in no event shall
 * ESRI Canada be liable for any special, incidental, indirect or
 * consequential damanages whatsoever (including without limitation,
 * damages for loss of business profits, business interruption, loss of
 * business information, or any other pecuniary loss) arising out of the
 * use or inability to use the software, even if caused by ESRI Canada's
 * negligence or even if ESRI Canada has been advised of the possibility
 * of such damages.
 * 
 * ESRI Canada has extended a "Limited Warranty on Services" to ECO-NOVA
 * Productions as specified in the contract.  To the maximum extent
 * permitted by applicable law, ESRI Canada and its suppliers disclaim
 * all other warranties, representations, conditions or guarantees,
 * either express or implied, including but not limited to, implied
 * warranties of durability, merchantability and fitness for a
 * particular purpose, with regard to the software, services and any
 * accompanying documentation.
**/

