/**-----------------------------------------------------------------------------
 * Imagery's slideshow.
 * (C) 2006 AKS <aksus-69@yandex.ru>
 * Thanks to all of members of dklab forum for wasting their time on me ;)
 *
 * This code is free software, so you can redistribute it and/or
 * modify it (even eat) under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation.
 * See http://www.gnu.org/copyleft/lesser.html (or inclusion of this package).
 *
 * This code is distributed 'cause it may be useful, but WITHOUT ANY WARRANTY!!!
 *
 *------------------------------------------------------------------------------/

/**
 * applyHandler
 *
 * It's just a wrapper for standard methods of registration of event listeners
 *
 * @scope public
 * @param {Object} Pointer to the object that will be event target
 * @param {String}or{Array} String or Array of two strings that specifies the standard events
 * @param {Function} Pointer to the function that supposed to be event listener
 * @returns {Function} Returns one of the specific method of registration of event listeners on
 *   the event target, if browser doesn't support one of these methods, returns false
 */

function applyHandler(o, e, f) {
  e = (e instanceof Array) ? (arguments.callee(o, e[1], f), e[0]) : e;
  return (o.attachEvent) ? o.attachEvent(e, f) : (o.addEventListener) ?
    o.addEventListener(e.substr(2), f, false) : false;
}

/**
 * initScroller
 *
 * Initializes all objects this program needs
 * Creates some important properties (see comments below)
 *   Note: these properties are public and applied straight off to DOM nodes,
 *         avoid using the same names in another scenario for the same page!!!
 *
 * @scope public
 * @see applyHandler
 * @returns {Function} Returns method to add an event listener(s)
 */

function initScroller() {

/**
 * c
 *
 * @type {Object} Pointer to a 'control' object
 */

  var c = document.getElementById('control'),

/**
 * s
 *
 * @type {Object} Pointer to a 'scroller' object
 *   Note: also it'll be available in a scroll_obj property of the 'control' object (c)
 */

  s = document.getElementById('scroller');

/**
 * back_control
 *
 * @type {Object} Pointer to the object that is considered as back scroll switcher
 *   Actually it's a <span> which contains 'back' text (later just <span>back)
 */

  c.back_control = c.getElementsByTagName('span')[0];

/**
 * scroll_position
 *
 * @type {Number} Provides a digital value (in pixels) for positioning the 'scroller' object
 *  (by default it's zero)
 *
 * scroll_active
 *
 * @type {Boolean} Indicates which one of the events fires on the 'control' object
 *   mouseover - it'll be true
 *   mouseout - false
 */

  (c.scroll_obj = s).scroll_position = s.scroll_active = 0;

/**
 * scroll_range
 *
 * @type {Number} Digital value (in pixels) that determines the maximum scrolling range
 */

  s.scroll_range = s.offsetHeight - s.parentNode.offsetHeight;
  return applyHandler(c, ['onmouseover', 'onmouseout'], scrollControl);
}

/**
 * scrollControl
 *
 * Initializes the only target that is needed for call scrollProcess function
 *
 * @scope public
 * @param {Object} Pointer to the event object that fires on the 'control' object
 * @see scrollProcess
 * @returns {Function}or{Boolean} Returns scrollProcess function or false
 */

function scrollControl(e) {

 /**
  * Get the target of the event
  */

  var el = (e = e || event).target || e.srcElement,

 /**
  * Get the tag name of the target
  */

  t = el.tagName.toLowerCase(), p, b;

 /**
  * Go on if only the target's tag name is 'span'
  */

  if(t == 'span') {

   /**
    * Get the pointer to the 'scroller' object
    */

    p = el.parentNode.scroll_obj;

   /**
    * The next operation requires a bit of explanation:
    *
    *   When a mouseover event fires on the target then the property of the 'scroller' scroll_active will
    *     be true and it'll cause the function named scrollProcess to be call
    *   scrollProcess'll deal with b (boolean) that could be true (if target is <span>back)
    *     or false (if target is <span>forward)
    *
    *   In other case (mouseout event) this operation returns false
    */

    return (p.scroll_active = !p.scroll_active) ?
      (b = (el == el.parentNode.back_control), scrollProcess(p, b)) : false;
  }
  else return false;
}

/**
 * scrollProcess
 *
 * The method that operates with an attitude of the 'scroller' object.
 *
 * @scope public
 * @param {Object} Pointer to the object ('scroller') that intended to be moved
 * @param {Boolean} Boolean value that indicates the direction of movement
 * @returns {Number}or{Boolean} Returns timeout for call scrollProcess function recursively or false
 */

function scrollProcess(o, b) {

 /**
  * Create a pointer to the scroll_position property of the 'scroller'.
  * Applied to avoid of several look-ups for this property in local scope.
  */

  var p = o.scroll_position;

 /**
  * The next operation requires a bit of explanation:
  *
  *   The scroll_position value depends on a few conditions:
  *
  *     If the 'scroller' moves forward (b == false) and reaches no limit (scroll_range)
  *       then it's value will be decreased by 5px
  *     Note: 'forward' is just a visual performance of the movement
  *       Indeed we move 'scroller's' left corner to the left and it's left position value
  *       grows in negative dimention until it's bigger then negative scroll_range!!!
  *
  *     If the 'scroller' moves back (b == true) and it's position still remains
  *       lesser than zero, it's value will be increased by 5px.
  *
  *     In other case the scroll_active property will be false, indicating that scrolling process is done
  *       Value of the scroll_position property will set to default or will be left as it is (it depends on b)
  */

  o.scroll_position = (!b && p > -o.scroll_range) ? p - 5 :
    (b && p < 0) ? p + 5 : (o.scroll_active = 0, b) ? 0 : p;

 /**
  * Set position of the left corner of the 'scroller' object
  */

  o.style.top = o.scroll_position + 'px';

 /**
  * If scrolling process is active, executes scrollProcess function after delay
  *   or returns false
  */

  return (o.scroll_active) ? window.setTimeout(function() {
    return scrollProcess(o, b); }, 10) : false;
}

/**
 * Call applyHandler function to add an event listener for onload event of the window
 */

applyHandler(window, 'onload', initScroller);