/* =============================================================================
* fonts.js
*
* iscapeJS.fontcontrol class definition for font control widgets
*
* ------------------------------------------------------------------------------
*
* USAGE:
*
* Include this script in the document it will be used by:
*   <script type="text/javascript" src="/common/js/library/fonts.js"></script>
*
* Create one or more instances of the class:
*   var font_widget = new iscapeJS.fontcontrol();
*
* And use the variable storage to modify properties as needed:
*   font_widget.minimum = 65;
*   font_widget.maximum = 120;
*   font_widget.container = 'hd-fonts';
*   font_widget.use_display = true;
*   font_widget.display_show = 'inline';
*
* ------------------------------------------------------------------------------
*
* Developed by Jake Kronika <jkronika@imagescape.com>
* For Imaginary Landscape, LLC <www.imagescape.com>
* Copyright (c) 2006
*
* Last updated 2006.12.29
*
* Reuse or modification without permission is prohibited.
* =========================================================================== */

// call in iscapeJS javascript library method object
var iscapeJS = iscapeJS || {};

// define a new class for the font control widget
iscapeJS.fontcontrol = function() {

  /* == PUBLIC VARIABLES =======================================================
  *
  * (iscapeJS.fontcontrol).base
  *   This should be the same as the base font size for the BODY tag (int)
  * (iscapeJS.fontcontrol).unit
  *   This should be the same unit used for the base font of the BODY tag (str)
  * (iscapeJS.fontcontrol).step
  *   This should be the amount to add/subtract from base to change size (float)
  * (iscapeJS.fontcontrol).minimum
  *   The smallest number that the size should be allowed to reach (float)
  * (iscapeJS.fontcontrol).maximum
  *   The largest number that the size should be allowed to reach (float)
  * (iscapeJS.fontcontrol).container
  *   The id of an element into which the font controls will be built ('string')
  * (iscapeJS.fontcontrol).use_plusminus
  *   Determines the way the font controls are displayed (boolean)
  *   - if [true], the controls will display as A- A A+ in increasing size
  *   - if [false], the controls will display as A A A to allow for styling as
  *     the indicator of use
  * (iscapeJS.fontcontrol).use_display
  *   Determines whether to use display or visibility style for show/hide (str)
  * (iscapeJS.fontcontrol).display_show
  *   Determines how items shown using display style appear (str)
  *
  * USAGE
  *
  * These are the customizable properties of the font control widget, and can be
  * modified at any time following the usage instructions above.
  *
  * ------------------------------------------------------------------------- */
  this.base = 85;
  this.unit = '%';
  this.step = 5;
  this.minimum = 70;
  this.maximum = 115;
  this.container = 'widget-fonts';
  this.use_plusminus = false;
  this.use_display = false;
  this.display_show = 'block';
  this.setup = false;

  /* == PRIVATE VARIABLE =======================================================
  *
  * (iscapeJS.fontcontrol).body
  *
  * This serves as storage for the body element of the current document and
  * should not be accessed or modified from outside the object's internal
  * methods. It is automatically filled upon page load using browser-neutral
  * techniques.
  *
  * ------------------------------------------------------------------------- */
  this._body = null;

  /* == PRIVATE VARIABLE =======================================================
  *
  * (iscapeJS.fontcontrol).anchors
  *
  * This serves as storage for the anchor elements corresponding to the
  * increase, decrease, and reset methods of the font control object. The
  * anchors are automatically created upon page load using browser-neutral
  * techniques.
  *
  * ------------------------------------------------------------------------- */
  this._anchors = {};

  /* == PRIVATE VARIABLE =======================================================
  *
  * (iscapeJS.fontcontrol).current
  *
  * This serves as storage for the current base font size for the BODY tag. The
  * current size is updated automatically by the
  * (iscapeJS.fontcontrol).get_current method
  *
  * ------------------------------------------------------------------------- */
  this._current = this.base;

  /* ===========================================================================
  *
  * (iscapeJS.fontcontrol).increase
  *
  * Increase the base font size of the BODY tag. If the site is created with
  * relative font sizes throughout, this will in turn increase the size of all
  * copy proportionately.
  *
  * USAGE:
  *
  * Usage is automatically invoked via anchors build in the init method. See
  * the iscapeJS.fontcontrol.init method description below for usage details.
  *
  * ------------------------------------------------------------------------- */
  this.increase = function() {
    if (this.get_current()) {
      if ((this._current + this.step) <= this.maximum) {
        this._current += this.step;
      } else {
        this._current = this.maximum;
      }

      this.update();
    }

    return false;
  };

  /* ===========================================================================
  *
  * (iscapeJS.fontcontrol).decrease
  *
  * Decrease the base font size of the BODY tag. If the site is created with
  * relative font sizes throughout, this will in turn decrease the size of all
  * copy proportionately.
  *
  * USAGE:
  *
  * Usage is automatically invoked via anchors build in the init method. See
  * the iscapeJS.fontcontrol.init method description below for usage details.
  *
  * ------------------------------------------------------------------------- */
  this.decrease = function() {
    if (this.get_current()) {
      if ((this._current - this.step) >= this.minimum) {
        this._current -= this.step;
      } else {
        this._current = this.minimum;
      }

      this.update();
    }

    return false;
  };

  /* ===========================================================================
  *
  * (iscapeJS.fontcontrol).reset
  *
  * Reset the base font size of the BODY tag. If the site is created with
  * relative font sizes throughout, this will in turn reset the size of all
  * copy proportionately.
  *
  * USAGE:
  *
  * Usage is automatically invoked via anchors build in the init method. See
  * the iscapeJS.fontcontrol.init method description below for usage details.
  *
  * ------------------------------------------------------------------------- */
  this.reset = function() {
    this._current = this.base;

    this.update();

    return false;
  };

  /* ===========================================================================
  *
  * (iscapeJS.fontcontrol).update
  *
  * Update the base font size of the BODY tag. If the site is created with
  * relative font sizes throughout, this will in turn update the size of all
  * copy proportionately.
  *
  * USAGE:
  *
  * Usage is automatically invoked via the decrease, reset, and increase
  * methods. See the iscapeJS.fontcontrol.decrease, iscapeJS.fontcontrol.reset,
  * and iscapeJS.fontcontrol.increase method descriptions above for usage
  * details.
  *
  * ------------------------------------------------------------------------- */
  this.update = function() {
    if (this._current > this.maximum) {
      this._current = this.maximum;
    }

    if (this._current < this.minimum) {
      this._current = this.minimum;
    }

    this._body.style.fontSize = (this._current + this.unit).toString();

    if (this.setup) {
      alert(this._body.style.fontSize);
    }

    this.set_cookie(this.current);

    this.adjust();
  };

  /* ===========================================================================
  *
  * (iscapeJS.fontcontrol).adjust
  *
  * Performs additional adjustments as necessary to ensure proper interaction
  * with other scripts.
  *
  * USAGE:
  *
  * Usage is automatically invoked via the update method. See the
  * iscapeJS.fontcontrol.update method description above for usage details.
  *
  * ------------------------------------------------------------------------- */
  this.adjust = function() {
    var iMenuRePosition;

    if (typeof (iMenuRePosition) == 'function') {
      iMenuRePosition();
    }

    var iTab;

    if (typeof (iTab) == 'object'
        && typeof (iTab.resizeBlocks) == 'function') {
      iTab.resizeBlocks();
    }

    this.extra_adjustment();
  };

  /* ===========================================================================
  *
  * (iscapeJS.fontcontrol).extra_adjustment
  *
  * Function storage to allow for additional adjustments as needed. This may be
  * overridden for any or all instances of the class, but must be done manually.
  * This method basically adds to the process of the base adjust method.
  *
  * USAGE:
  *
  * Once an instance of the fontcontrol class is created:
  *   var font_control = new iscapeJS.fontcontrol();
  * Override this method with a new function object that performs all necessary
  * actions to ensure property site display as font sizes change:
  *   font_control.extra_adjustment = function() {
  *     // method actions here
  *   };
  *
  * ------------------------------------------------------------------------- */
  this.extra_adjustment = function() {
    return;
  };

  /* ===========================================================================
  *
  * (iscapeJS.fontcontrol).get_body
  *
  * Stores a reference to the BODY element in (iscapeJS.fontcontrol)._body for
  * future use.
  *
  * Usage is automatically invoked via the init method. See the
  * iscapeJS.fontcontrol.init method description below for usage details.
  *
  * ------------------------------------------------------------------------- */
  this.get_body = function() {
    if (document.body) {
      this._body = document.body;
    } else if (document.getElementsByTagName) {
      var bodies = document.getElementsByTagName('body');

      if (typeof (bodies) == 'object'
          && typeof (bodies[0]) == 'object') {
        this._body = bodies[0];
      }
    } else {
      this._body = null;
    }

    return this._body;
  };

  /* ===========================================================================
  *
  * (iscapeJS.fontcontrol).get_current
  *
  * Retrieves the current font size from the BODY element's style, using
  * (iscapeJS.fontcontrol).base if no style is found.
  *
  * USAGE
  *
  * Usage is automatically invoked via the decrease and increase methods. See
  * the iscapeJS.fontcontrol.decrease and iscapeJS.fontcontrol.increase method
  * descriptions above for usage details.
  *
  * ------------------------------------------------------------------------- */
  this.get_current = function() {
    if (typeof (this._body) == 'object'
        && typeof (this._body.style) == 'object'
        && typeof (this._body.style.fontSize) == 'string'
        && isFinite (parseInt (this._body.style.fontSize))) {
      this._current = parseInt (this._body.style.fontSize);
    } else {
      this._current = this.base;
    }

    if (typeof (this._current) == 'number'
        && isFinite (this._current)) {
      return true;
    }

    return false;
  };

  /* ===========================================================================
  *
  * (iscapeJS.fontcontrol).get_cookie
  *
  * Retrieves the stored font size from the cookies, if one exists. If found,
  * (iscapeJS.fontcontrol)._current is corrected and the update method is
  * invoked to set the font size to the user preference.
  *
  * USAGE
  *
  * Usage is automatically invoked via the init method. See the
  * iscapeJS.fontcontrol.init method description below for usage details.
  *
  * ------------------------------------------------------------------------- */
  this.get_cookie = function() {
    var fs = document.cookie.match(/fontsize=([0-9]+)[icemnptx% ]+;?/i);

    if (fs && fs[1] && fs[1] != '') {
      this._current = fs[1];
      this.update(this._current);
    }
  };

  /* ===========================================================================
  *
  * (iscapeJS.fontcontrol).set_cookie
  *
  * Updates the stored font size in the cookies, using the current font size and
  * unit.
  *
  * USAGE
  *
  * Usage is automatically invoked via the update method. See the
  * iscapeJS.fontcontrol.update method description above for usage details.
  *
  * ------------------------------------------------------------------------- */
  this.set_cookie = function() {
    document.cookie = 'fontsize=' + this._current + this.unit;
  };

  /* ===========================================================================
  *
  * (iscapeJS.fontcontrol).init
  *
  * Initializes the widget by populating the (iscapeJS.fontcontrol)._body
  * property, updating the (iscapeJS.fontcontrol).container property with the
  * element having the original string value as an ID, building the appropriate
  * control anchors and adding them to the (iscapeJS.fontcontrol).container,
  * and updating the font based on the cookie value.
  *
  * USAGE
  *
  * Usage is automatically invoked via the onload event handler.
  *
  * ------------------------------------------------------------------------- */
  this.init = function() {
    this.get_body();

    if (typeof (this._body) != 'object'
        || typeof (this._body.style) != 'object'
        || typeof (this.container) != 'string'
        || !document.getElementById
        || !document.createElement
        || !document.createTextNode) {
      return;
    }

    this.container = document.getElementById(this.container);

    if (typeof (this.container) != 'object'
        || !this.container.appendChild) {
      return;
    }

    if (this.container.hasChildNodes) {
      while (this.container.hasChildNodes()) {
        this.container.removeChild(this.container.childNodes[0]);
      }

      if (!this.container.hasChildNodes()
          && typeof (this.container.style) == 'object') {
        if (this.use_display) {
          this.container.style.display = this.display_show;
        } else {
          this.container.style.visiblity = 'visible';
        }
      }
    }

    this._anchors.decrease = document.createElement('a');
    this._anchors.reset = document.createElement('a');
    this._anchors.increase = document.createElement('a');

    if (!this.verify_anchor(this._anchors.decrease)
        || !this.verify_anchor(this._anchors.reset)
        || !this.verify_anchor(this._anchors.increase)) {
      return;
    }

    this._anchors.decrease.className = 'font-smaller';
    this.build_control('decrease');
    this._anchors.decrease.appendChild(
      document.createTextNode('A' + (this.use_plusminus ? '-' : '')));

    this._anchors.reset.className = 'font-reset';
    this.build_control('reset');
    this._anchors.reset.appendChild(document.createTextNode('A'));

    this._anchors.increase.className = 'font-larger';
    this.build_control('increase');
    this._anchors.increase.appendChild(
      document.createTextNode('A' + (this.use_plusminus ? '+' : '')));

    this.container.appendChild(this._anchors.decrease);
    this.container.appendChild(document.createTextNode(' '));
    this.container.appendChild(this._anchors.reset);
    this.container.appendChild(document.createTextNode(' '));
    this.container.appendChild(this._anchors.increase);

    if (this.minimum > this.maximum) {
      var tmp = this.minimum;
      this.minimum = this.maximum;
      this.maximum = tmp;
    }

    this.get_cookie();
  };

  this.verify_anchor = function(anchor) {
    if (typeof (anchor) == 'object'
        && anchor.setAttribute
        && anchor.appendChild) {
      return true;
    }

    return false;
  }

  this.build_control = function(control) {
    this._anchors[control].setAttribute('href', '#' + control);
    this._anchors[control].widget = this;
    this._anchors[control].onclick = function() {
      return this.widget[control]();
    };
  };

  /* ===========================================================================
  *
  * Add initialization of this object to the window.onload event handler.
  *
  * ------------------------------------------------------------------------- */
  var onload = window.onload,
      self = this;

  window.onload = function() {
    if (typeof (onload) == 'function') {
      onload();
    }

    self.init();
  };
};
