
com.bezurk.namespace('com.bezurk.widget');

/**
 * <p>com.bezurk.widget.IFrameShim provides an iFrame to layer over Windows form
 * elements.</p>
 * requires Prototype
 *
 * @constructor
 * @param {element | string} DOM element reference or id of the element
 *        to apply the iframe shim to
 */
com.bezurk.widget.IFrameShim = function(element) {

  if (element) {

    if (typeof element == 'string') {
      this._element = $(element);
    } else {
      this._element = element;
    }

  } else {
    // Required arguments were not found.
  }
};


/**
 * Configurable iFrame src. Implementations over SSL should set this parameter
 * to an appropriate https location in order to avoid security-related browser
 * errors. Default: "about:blank".
 *
 * @type string
 */
com.bezurk.widget.IFrameShim.prototype.iFrameSrc = 'about:blank';

/**
 * Class name of the iFrame shim. Use spaces to separate multiple class names
 * (e.g. "class1 class2"). Default: "bezurk-iframe-shim".
 *
 * @type string
 */
com.bezurk.widget.IFrameShim.prototype.iFrameClassName = 'bezurk-iframe-shim';

/**
 * The interval (in number of seconds) to check whether the iFrame shim should
 * be visible or hidden. Default: 0.1.
 *
 * @type number
 */
com.bezurk.widget.IFrameShim.prototype.checkIFrameInterval = 0.1;

/**
 * Whether the displaying of the iFrame shim will be handled by client.
 * If false, the iFrame is shown automatically when the element it's shimming
 * is visible. It's not recommended to set this to false until I figure out a
 * way to show the shim immediately instead of after a delay.
 * Default: true.
 *
 * @type boolean
 */
com.bezurk.widget.IFrameShim.prototype.manualShim = true;

/**
 * Whether the hiding of the iFrame shim will be handled by client.
 * If false, the iFrame is hidden automatically when the element it's shimming
 * is not visible.
 * Default: false.
 *
 * @type boolean
 */
com.bezurk.widget.IFrameShim.prototype.manualDeshim = false;

/***************************************************************************
 * Public methods
 ***************************************************************************/
com.bezurk.widget.IFrameShim.prototype.startShim = function() {

  if (!this.manualShim) {
    this._startShimChecker();
  }
};

/**
 * Places iFrame shim behind the element, if it is visible.
 */
com.bezurk.widget.IFrameShim.prototype.shim = function() {

  if (!this._element._iFrame) {
    this._initIFrame();
  }

  if (Element.visible(this._element)) {
    // Sync the IFrame shim's dimensions with that of its element.
    Position.clone(this._element, this._element._iFrame);
    this._element._iFrame.style.zIndex = this._element.style.zIndex - 1;
    Element.show(this._element._iFrame);

    if (!this.manualShim) {
      this._shimPeriodicalExecuter.stop();
    }
    if (!this.manualDeshim) {
      this._startDeshimChecker();
    }
  }
};

/**
 * Hides the iFrame shim.
 */
com.bezurk.widget.IFrameShim.prototype.deshim = function() {

  if (this._element._iFrame && Element.visible(this._element._iFrame) && !Element.visible(this._element)) {
    Element.hide(this._element._iFrame);

    if (!this.manualDeshim) {
      this._stopDeshimChecker();
    }
    if (!this.manualShim) {
      this._startShimChecker();
    }
  }
};

/***************************************************************************
 * Private methods
 ***************************************************************************/
com.bezurk.widget.IFrameShim.prototype._initIFrame = function() {

  var iframe = document.createElement('iframe');
  iframe.src = this.iFrameSrc;
  iframe.frameBorder = 0;
  iframe.scrolling = 'no';
  iframe.style.position = 'absolute';
  iframe.style.display = 'none';
  new Element.ClassNames(iframe).set(this.iFrameClassName);

  this._element._iFrame = document.getElementsByTagName('body')[0].appendChild(iframe);
};

com.bezurk.widget.IFrameShim.prototype._startShimChecker = function() {
  this._shimPeriodicalExecuter = new StoppablePeriodicalExecuter(this.shim.bind(this), this.checkIFrameInterval);
};
com.bezurk.widget.IFrameShim.prototype._stopShimChecker = function() {
  this._shimPeriodicalExecuter.stop();
};
com.bezurk.widget.IFrameShim.prototype._startDeshimChecker = function() {
  this._deshimPeriodicalExecuter = new StoppablePeriodicalExecuter(this.deshim.bind(this), this.checkIFrameInterval);
};
com.bezurk.widget.IFrameShim.prototype._stopDeshimChecker = function() {
  this._deshimPeriodicalExecuter.stop();
};


// Extend Prototype's PeriodicalExecuter to add a stop() method.
var StoppablePeriodicalExecuter = Class.create();
Object.extend(StoppablePeriodicalExecuter.prototype, PeriodicalExecuter.prototype);
StoppablePeriodicalExecuter.prototype.registerCallback = function() {
  this.intervalId = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
}
StoppablePeriodicalExecuter.prototype.stop = function() {
  clearInterval(this.intervalId);
}

