// Place your application-specific JavaScript functions and classes here
// This file is automatically included by javascript_include_tag :defaults

function blindBlock(id, duration)
{
    var e = document.getElementById(id);
    if (e != null) {
        if (e.style.display == "none") {
            Effect.BlindDown(id, {duration: duration})
        } else {
            Effect.BlindUp(id, {duration: duration})
        }
    }
}

MyTransitions = {
  ease_in_out: function(pos) {
    return (1 + Math.sin(-Math.PI/2 + Math.PI * pos)) / 2;
  },
  ease_in: function(pos) {
    return Math.cos((1 - pos) * (Math.PI/2));
  }
};

function fix_hide_hacks()
{
    var hackedElements;
    $$('.hidehack').invoke('hide').invoke('removeClassName', 'hidehack');

    var hidden_submit_style = Prototype.Browser.IE ? {width: '0px'} : {display: 'none'}
    submits = $$('.hidden-submit').invoke('setStyle', hidden_submit_style).invoke('removeClassName', 'hidden-submit');
}

// dummy function for non-IE browsers
function pngfix() {}

var initialFocus = null;

function initializePage()
{
    if (initialFocus != null) {
        e = document.getElementById(initialFocus);
        if (e != null) {
            e.focus();
        }
    }
}

document.observe('dom:loaded', initializePage);

// Mouse/Event manager. Events are monitored at the document level, and
// distributed to event handlers by looking at the event target and working up
// the tree. An element with 'mouse_handler' attribute defined will receive
// all the subsequent events until the mouse is released, even if/when the
// mouse is dragged outside the element that wants the events. When a
// mouse_handler is in use, Mouse.is_down is true.
//
// Other elements in the UI can change their behavior if the mouse moves over
// them while Mouse.is_down is true.

Mouse = {
  is_down: false,
  target: null,
  last: null,
  down_evt: null,
  was_active: false,
  was_drag: false,
  now: function() {
    return new Date().getTime();
  },
  touch: function() {
    Mouse.last = new Date().getTime();
  },
  on_mouse_down: function(evt) {
    var evt = Event.extend(evt || window.event);
    var element = evt.element();
    Mouse.down_evt = evt;
    Mouse.target = null;
    Mouse.was_drag = false;
    Mouse.was_active = false;
    while (element != null) {
      if (element.mouse_handler != null) {
        Mouse.target = element;
        break;
      }
      element = $(element.parentNode);
    }
    var result = true;
    if (Mouse.target != null && Mouse.target.mouse_handler.mouse_down) {
      Mouse.is_down = true;
      result = Mouse.target.mouse_handler.mouse_down(evt);
      evt.stop();
    }
    Mouse.touch();
    return result;
  },
  on_mouse_move: function(evt) {
    var result = true;
    evt = Event.extend(evt || window.event);
    if (!Mouse.is_down) {
      return Mouse.handle_hovering(evt);
    }
    if (Mouse.is_down && Mouse.target != null && Mouse.target.mouse_handler.mouse_drag) {

      // make sure it was a drag event (IE6 fires mousemove right after mousedown)
      if (Mouse.down_evt != null) {
        p0 = Mouse.down_evt.pointer();
        p1 = evt.pointer();
        if (Math.abs(p0.x - p1.x) + Math.abs(p0.y - p1.y) < 4) {
          return false;
        }
        // now it's a drag - don't check again
        Mouse.down_evt = null;
      }
      result = Mouse.target.mouse_handler.mouse_drag(evt);
      if (!Mouse.was_drag) {
        Mouse.was_drag = true;
      }
      evt.stop();
    }
    Mouse.touch();
    return result;
  },
  on_mouse_up: function(evt) {
    evt = Event.extend(evt || window.event);
    Mouse.is_down = false;
    var result = true;
    if (Mouse.target != null && Mouse.target.mouse_handler.mouse_up) {
      result = Mouse.target.mouse_handler.mouse_up(evt);
      evt.stop();
    }
    Mouse.was_active = (Mouse.target != null);
    Mouse.target = null;
    Mouse.touch();
    return result;
  },
  void_click: function(evt) {
    if (Mouse.was_drag && Mouse.was_active) {
      evt = Event.extend(evt || window.event);
      evt.stop();
      return false;
    }
    return true;
  },
  idle_time_millis: function() {
    return new Date().getTime() - Mouse.last;
  },
  handle_hovering: function(evt) {
    var e = evt.element();
    while (e != null) {
      if (e.hover_handler != null) {
        break;
      }
      e = e.parentNode;
    }
    if (e == Mouse.hover_target)  {
      // same handler as before - do nothing
      return true;
    }
    if (Mouse.hover_target && Mouse.hover_target.hover_handler.mouse_exit) {
      Mouse.hover_target.hover_handler.mouse_exit(evt);
    }
    Mouse.hover_target = e;
    if (e != null && e.hover_handler.mouse_enter) {
      e.hover_handler.mouse_enter(evt);
    }
  }
};

// document.observe('mousedown', Mouse.on_mouse_down);
// document.observe('mousemove', Mouse.on_mouse_move);
// document.observe('mouseup', Mouse.on_mouse_up);
// document.observe('click', Mouse.void_click);

// 
// Horizontal scrollbar class.
//
function HScrollbar(id, tid, options) {
  this.init(id, tid, options);
}
HScrollbar.prototype = {      
  _get: function(id) {
    var e = $(id);
    if (e == null) {
      alert("Coudln't find scrollbar element: " + id);
    }
    return e;
  },
  init: function(id, t_id, options) {
    if (options == null) options = {};
    this.button_width = options.button_width || 6;        
    this.container = this._get(id);       // container for the scrollbar UI elements
    this.container.mouse_handler = this;  // we need access to this scrollbar in the event handlers
    this.target = this._get(t_id);        // the object we're moving inside its parent
    this.scrollee = new Scrollee(this.target, this);
    var targetpNode = $(this.target.parentNode);
    var img_bg = this._get(id + "_bg");
    var img_bubble = this._get(id + "_fg");

    this.img_bubble = img_bubble;
    var bg_size = img_bg.getDimensions();
    var fg_size = img_bubble.getDimensions();

    // position the two image elements
    var height = options.height || this.container.getHeight();
    var bg_top = (height - bg_size.height) / 2;
    this.moveto(img_bg, 0, bg_top);
    this.moveto(img_bubble, 0, bg_top + (bg_size.height - fg_size.height) / 2);

    var left = this.container.cumulativeOffset()[0];
    this.bubble_width = fg_size.width;
    this.x0 = left + this.button_width;
    this.x1 = left + bg_size.width - this.button_width - this.bubble_width;
    this.drag_x = 0;
    this.update();
  },
  
  target_dragged_to: function(tx)
  {
    if (tx > 0) {
      tx = 0;
    } else if (-tx > this.get_target_max_value()) {
      tx = -this.get_target_max_value();
    }
    this.drag_x = (-tx * (this.x1 - this.x0)) / this.get_target_max_value();
    this.update();
  },
  
  get_target_max_value: function()
  {
    return this.target.getWidth() - this.target.parentNode.getWidth();
  },

  get_event_x: function(evt) {
    var evt_x = evt.pointerX();
    var x = evt_x - this.bubble_width / 2;
    x = Math.min(this.x1, Math.max(this.x0, x));
    
    return x;
  },

  mouse_down: function(evt) {
    var x = this.get_event_x(evt);
    this.drag_x = x - this.x0;
    this.update(true);
    return false;
  },
  mouse_drag: function(evt) {
    var x = this.get_event_x(evt);
    this.drag_x = x - this.x0;
    this.update(false);
    return false;
  },
  mouse_up: function(evt) {
    return false;
  },
  update: function(smooth_scroll) {
    this.moveto(this.img_bubble, this.button_width + this.drag_x);
    var tx = Math.round(this.get_target_max_value() * this.drag_x / (this.x1 - this.x0));
    if (smooth_scroll) {
      this.smooth = new Effect.Move(this.target, {x: -tx, mode: 'absolute', duration: 0.2});
    } else {
      if (this.smooth && !this.smooth.canceled) {
        // cancel the smooth scrolling if we start dragging right away otherwise they
        // will compete with each other
        this.smooth.cancel();
        this.smooth.canceled = true;
      }
      this.moveto(this.target, -tx, null);
    }
  },
  // Moves the specified element to the specified x/y position
  moveto: function(element, x, y) {
    coord = {position: 'absolute'}
    if (x != null) coord.left = x + 'px';
    if (y != null) coord.top = y + 'px';
    element.setStyle(coord);
  }
};

function Scrollee(id, sbar)
{
  this.init(id, sbar);
}
Scrollee.prototype = {
  init: function(id, sbar) {
    this.scrollee = $(id);
    this.scrollee.mouse_handler = this;
    this.sbar = sbar;
  },
  mouse_down: function(evt) {
    this.t0 = Mouse.now();
    this.x0 = evt.pointerX();
    this.startx = this.scrollee.positionedOffset().left;
    return false;
  },
  mouse_drag: function(evt) {
    this.dragt = Mouse.now();
    sbar.target_dragged_to(this.startx + evt.pointerX() - this.x0);
    return false;
  },
  mouse_up: function(evt) {
    var dx = evt.pointerX() - this.x0;
    var dt = Mouse.now() - this.t0;
    return false;
  }
};


// 
// Vertical scrollbar class.
//
function VScrollbar(id, tid, options) {
  this.init(id, tid, options);
}
VScrollbar.prototype = {      
  _get: function(id) {
    var e = $(id);
    if (e == null) {
      alert("Coudln't find scrollbar element: " + id);
    }
    return e;
  },
  init: function(id, t_id, options) {
    if (options == null) options = {};
    this.container = this._get(id);       // container for the scrollbar UI elements
    this.container.mouse_handler = this;  // so the Mouse sends us events
    this.target = this._get(t_id);        // the object we're moving inside its parent

    this.button_height = options.button_height || 6;        

    // this.scrollee = new Scrollee(this.target);
    var targetpNode = $(this.target.parentNode);
    var img_bg = this._get(id + "_bg");
    var img_bubble = this._get(id + "_fg");

    this.img_bubble = img_bubble;
    var bg_size = img_bg.getDimensions();
    var fg_size = img_bubble.getDimensions();

    // center the background in the main div, and center the bubble in that.
    var width = options.width || this.container.getWidth();
    var bg_left = (width - bg_size.width) / 2;
    this.moveto(img_bg, bg_left, 0);
    this.moveto(img_bubble, bg_left + (bg_size.width - fg_size.width) / 2, 0);

    // get the top position in the page of the scrollbar
    this.top = this.container.cumulativeOffset()[1];
    this.bubble_height = fg_size.height;
    this.y0 = this.button_height;
    this.bottom = bg_size.height;
    this.y1 = this.bottom - this.button_height - this.bubble_height;
    // scrollbar range is 0 to our height minus size of the bubble
    this.max_value = this.y1 - this.y0;
    // targets range is 0 to the targets height minus the size of the target's parent
    this.target_max_value = this.target.getHeight() - targetpNode.getHeight();

    this.page_size = (targetpNode.getHeight() / this.target_max_value) * this.max_value;
    this.page_size = Math.round(this.page_size * .95);
    this.line_size = options.line_size || this.page_size / 10;
    this.drag_y = 0;
    this.update();
  },

  process_mouse_action: function(evt) {
    // convert Y to internal coordinates of container
    var y = evt.pointerY() - this.top;
    var current_y = this.img_bubble.positionedOffset().top;

    // window.status = "";
    if (this.mode == null) {
      if (y < this.button_height) {
        this.mode = 'line-up';
        y = current_y - this.line_size;
      } else if (y < current_y) {
        this.mode = 'page-up';
        y = current_y - this.page_size;
      } else if (y < current_y + this.bubble_height) {
        this.mode = 'drag'
      } else if (y < this.bottom - this.button_height) {
        this.mode = 'page-down'
        y = current_y + this.page_size;
      } else {
        this.mode = 'line-down'
        y = current_y + this.line_size;
      }
    }
    if (this.mode == 'drag') {
      // drag from the middle of the bubble
      y -= this.bubble_height / 2;
    }
    this.drag_y = Math.min(this.y1, Math.max(this.y0, y)) - this.y0;
  },

  mouse_down: function(evt) {
    this.process_mouse_action(evt);
    this.update(true);
    return false;
  },
  mouse_drag: function(evt) {
    if (this.mode != 'drag') {
      return false;
    }
    this.process_mouse_action(evt);
    this.update(false);
    return false;
  },
  mouse_up: function(evt) {
    this.mode = null;
    return false;
  },
  update: function(smooth_scroll) {
    this.moveto(this.img_bubble, null, this.button_height + this.drag_y);
    var ty = Math.round(this.target_max_value * this.drag_y / (this.y1 - this.y0));
    if (smooth_scroll) {
      this.smooth = new Effect.Move(this.target, {y: -ty, mode: 'absolute', duration: 0.2});
    } else {
      if (this.smooth && !this.smooth.canceled) {
        // cancel the smooth scrolling if we start dragging right away otherwise they
        // will compete with each other
        this.smooth.cancel();
        this.smooth.canceled = true;
      }
      this.moveto(this.target, null, -ty);
    }
  },
  // Moves the specified element to the specified x/y position
  moveto: function(element, x, y) {
    coord = {position: 'absolute'}
    if (x != null) coord.left = x + 'px';
    if (y != null) coord.top = y + 'px';
    element.setStyle(coord);
  }
};

// 
// Popup menu support
//

function PopupMenu(id)
{
  this.init(id);
}

PopupMenu.prototype = {
  init: function(id) {
    var menus = $(id).select('ul');
    if (menus.length <= 1) {
      alert("Warning: no sub-menus in " + id);
      return;
    }
    this.menu_root = menus[0];

    // The top-level LIs need to be relatively positioned
    // so the UL sub menus can be positioned inside them
    var lis = this.menu_root.select('li');
    for (var i = lis.length; --i >= 0; ) {
      if (lis[i].parentNode == this.menu_root) {
        lis[i].setStyle({
          position: 'relative',
          float: 'left',
          paddingLeft: '10px',
          verticalAlign: 'text-bottom'
        });
      }
    }

    // the sub menus are absolute positionined inside the relative positioned top-level LI's
    for (var i = 1; i < menus.length; i++) {
      var menu = menus[i];
      var pli = $(menus[i].parentNode);
      pli.hover_handler = this;
      menu.setStyle({
        position: 'absolute',
        top: '1.2em',
        padding: '0px',
        marginTop: '0px',
        marginBottom: '0px',
        marginRight: '0px'
      });
      menu.select('li').invoke('setStyle', {
        display: 'list-item',
        float: 'none'
      });
      menu.hide();
    }
  },
  mouse_enter: function(evt) {
    var e = evt.findElement('li');
    if (e && e.parentNode == this.menu_root) {
      var sub = e.select('ul')[0];
      sub.show();
      this.current = sub;
    }
    return true;
  },
  mouse_exit: function(evt) {
    this.current.hide();
    this.current = null;
    return false;
  }
}


// 
// menu image links
// 

function onMenuExit() { toImage(this, 1); }
function onMenuEnter() { toImage(this, 3); }
function toImage(img, num) {
  if (img.hasClassName('current')) {
    // current page doesn't react to mouse inputs
    return;
  }
  var src = img.src;
  var end = src.indexOf("?");
  if (end < 0) {
      end = src.length;
  }
  img.src = menuImageUrl(img, num);
}
function menuImageUrl(img, n) {
  var src = img.src;
  var end = src.indexOf("?");
  if (end < 0) {
      end = src.length;
  }
  return src.substring(0, end - 5) + n + src.substring(end - 4);	
}
function initMenu() {
  imgs = $$('#menu li img');
  for (var i = 0; i < imgs.length; i++) {
    var img = imgs[i];

    img.observe("mouseover", onMenuEnter);
    img.observe("mouseout", onMenuExit);
	  new Image().src = menuImageUrl(img, 2);
	  new Image().src = menuImageUrl(img, 3);
  }
}

// 
// Rotating images: pattern contains "%" which is substituted with the args
//
//  rotateImages('imgs', "image%.jpg", [1, 2, 3])
// 
// Store in image:
//    - pattern
//    - args
//    - current index
// 
function ImageRotater(id, config, pattern, args)
{
  this.init(id, config, pattern, args);
}

ImageRotater.prototype = {
  init: function(id, config, pattern, args) {
    this.id = id;
    this.fade = config.fade || 1;
    this.div = $(id);
    this.div.innerHTML = '<img id="' + id + '-1" /> <img id="' + id + '-0"/>';
    this.fg = $(id + "-1");
    this.bg = $(id + "-0");

    // make the new image elements absolute
    var style = {position: 'absolute', top: 0, left: 0};
    this.fg.setStyle(style);
    this.bg.setStyle(style);
    this.args = args;
    
    // parse the format string to allow for quick substitution later
    var percent = pattern.indexOf("%");
    this.prefix = pattern.substring(0, percent);
    this.suffix = pattern.substring(percent + 1);

    // initialize current image to the 0'th element
    this.index = 0;
    this.fg.src = this.imageUrl();

    // prefetch the next image
    new Image().src = this.imageUrl(this.index + 1);

    this.bg.setOpacity(0.01);
    this.pe = new PeriodicalExecuter(this.pe_callback, config.delay);
    this.pe.me = this;
  },
  pe_callback: function(pe) {
    pe.me.nextImage();
  },
  nextImage: function() {
    // swap fg/bg image elements
    var tmp = this.bg;
    this.bg = this.fg;
    this.fg = tmp;

    // move to the next image
    this.index = (this.index + 1) % this.args.length;
    this.fg.src = this.imageUrl();

    // fade out the new bg and fade in the new fg
    new Effect.Fade(this.bg, {duration: this.fade, to: 0.01});
    new Effect.Fade(this.fg, {duration: this.fade, to: 1.0});

    // prefetch the next image
    new Image().src = this.imageUrl(this.index + 1);
  },
  imageUrl: function(n) {
    if (n == null) {
      n = this.index;
    }
    n = n % this.args.length;
    var url = this.prefix + this.args[n] + this.suffix;
    return url;
  }
}
