/****************************************************************************************
  mrDropMenu - (c) Media Range Studio,
                   [  Kirill Losev (test@mediarange.ru) ]
  
  Спасибо http://www.mediatemple.net за их "менюшку", что сподвигла меня на
  созданение текущей, так же спасибо за их "неповторимый" стиль программирования.
  
  Использование данного скрипта в коммерческих проэктах, запрешено без согласования
  с автором 

*****************************************************************************************/


/****************************************************************************************
  Класс mrDropMenu - Само меню. набор ROOT итемов
*****************************************************************************************/
mrDropMenu.instances = [];

//mrDropMenu.img['spacer'] = '';
mrDropMenu.padding = {before: 5, after: 5};

mrDropMenu.Css = 'dropmenu';
mrDropMenu.img = {spacer: '/images/0x0.gif'}

mrDropMenu.directions = {down: 1, right: 2};
mrDropMenu.hidetime = 500; // in ms
mrDropMenu.defaultZ = 100;
// Проверка на поддержку
mrDropMenu.isSupported = function () {
  // Заглушка.
  return true;
};
//

// Констуртор и сам класс
function mrDropMenu () {
  // Переменные класа
  this.Menus = new Array();
  this.CurrentIndex = null;
  // Функции класса
  this.AddMenu = AddMenu;
  this.Init = Init;
  
  function AddMenu(oActivator,iDirection) {
    // Создает обьект mrDropRootItem
    var Root = new mrDropRootItem(this,oActivator,iDirection);
    return Root;
  };
  
  function Init () {
    for (var i=0; i < this.Menus.length; i++) {
      this.Menus[i].Init();
    };
  }; // end Init

};

/****************************************************************************************
  Класс mrDropRootItem 
*****************************************************************************************/
mrDropRootItem.instances = [];
function mrDropRootItem (oParent,oActivator,iDirection) {
  // Переменные класа
  this.Parent = oParent;
  // Assign to parent
  this.index = this.Parent.Menus.length;
  this.Parent.Menus[this.index] = this;
  // Assign to Global 
  this.id = mrDropRootItem.instances.length;
  mrDropRootItem.instances[this.id] = this;
  
  this.Activator = oActivator;
  if (typeof iDirection == 'undefined') { iDirection = mrDropMenu.directions.down; };
  this.Direction = iDirection;
  this.Items = new Array ();
  this.zIndex = 100;
  this.hTimeout = null; 
  
  
  // Функции класса
  this.AddItem = AddItem;
  this.Init = Init;
  this.Render = Render;
  this.InitCache = InitCache;
  this.InitSize  = InitSize;
  this.InitEvents = InitEvents;
  this.AlignMenu = AlignMenu;
  
  this.Show=Show;
  this.Hide=Hide;
  this.TimeoutHide = TimeoutHide;
  this.CancelHide  = CancelHide;
  
  // Глобальные переменные обьекта
  var Ready = false;
  var Cache = [];
  var FD = 0; // float distance
  var _this = this // small hack
  var AnimTimer = null;
  var Animating = false
  this.iTim = 1;
  
  function AddItem(sCaption,sLink) {
    var item = new mrDropItem(this,sCaption,sLink);
    return item;
  };
  
  function Init () {
    this.Render();
    this.InitCache();
    this.InitSize();
    this.InitEvents();
    Ready = true;
  };
  
  function Render() {
    var result = '';
    result += '<div id="mrDropRoot_'+this.id+'" class="' + mrDropMenu.Css +'"><div class="content">';
    result += '<div class="shadow"><img src='+mrDropMenu.img.spacer+' height="1" width="1" alt="" /></div>';
    result += '<table cellpadding="0" cellspacing="0" border="0" class="items">';
    result += '<tr><td colspan="3"><img src='+mrDropMenu.img.spacer+' height="'+mrDropMenu.padding.before+'" width="1" alt="" /></td></tr>';
    for (var i = 0; i < this.Items.length; i++) {
      result += this.Items[i].toString();
    };
    result += '<tr><td colspan="3"><img src='+mrDropMenu.img.spacer+' height="'+mrDropMenu.padding.after+'" width="1"></td></tr></table>';
    result += '</div></div>';
		document.write(result);
  };
  
  function InitCache() {
    var self = document.getElementById('mrDropRoot_'+this.id);
    var all = self.all ? self.all : self.getElementsByTagName("*"); 
    
    Cache["self"] = self;
    Cache["item"] = [];
    for (var i = 0, element = null; element = all[i]; i++) {
      switch (element.className) {
        case "menu":
        case "content":
        case "items": 
        case "shadow":
            Cache[element.className] = element;
            break;
        case "item":
            element._index = Cache['item'].length;
            Cache['item'][element._index] = element;
            break;
      }; // end switch
    }; // end for
  }; // end initcache

  function InitSize() {
    var ItemsWidth = Cache['items'].offsetWidth;
    var ItemsHeight = Cache['items'].offsetHeight;
    // Align Shadow
    Cache['shadow'].style.top  = "1px";
    Cache['shadow'].style.width = (ItemsWidth + 2 ) + "px";
    Cache['shadow'].style.left = "1px";
    Cache['shadow'].style.height = (ItemsHeight + 2 )+ "px";
    Cache['shadow'].style.zIndex = -1;
    
    
    Cache['content'].style.width = Cache['items'].offsetWidth + 'px';
    Cache['content'].style.height = ItemsHeight + 'px';
    Cache['self'].style.height = ItemsHeight + 2 +'px';
    Cache['self'].style.width = Cache['content'].offsetWidth + 2 +'px';

		////debug_view('offset '+Cache['content'].offsetTop);
    FD = this.Direction == mrDropMenu.directions.down ? ItemsHeight : ItemsWidth;
    if (this.Direction == mrDropMenu.directions.down) {
      Cache['content'].style.top = -FD +'px';
    } else {
      Cache['content'].style.left = -FD +'px';
    };
    
  };
  
  function InitEvents() {
    if (typeof this.Activator != 'undefined') { // Normamlly HTML object, not another menu
      this.Activator.onmouseover = activator_mouseover;
      this.Activator.onmouseout  = activator_mouseout;
    };
    
    Cache['content'].onmouseover = content_mouseover;
    Cache['content'].onmouseout  = content_mouseout;
    Cache['items'].onmouserover  = content_mouseover;
    Cache['items'].onmouseout    = content_mouseout;
    
    
    for (var i=0; i < Cache['item'].length; i++) {
      this.Items[Cache['item'][i]._index].HTMLObj = Cache['item'][i];
      Cache['item'][i].onmouseover = item_mouseover;
      Cache['item'][i].onmouseout = item_mouseout;
      //Cache['item'][i].onmousemove = item_mouseover;
      Cache['item'][i].onclick = item_click;
      
    };
  };
  
  function activator_mouseover() {
    _this.Show();
  };
  function activator_mouseout() {
    _this.TimeoutHide();
  };
  
  function content_mouseover() {
    if (!Animating) _this.Show();
  };
  
  function content_mouseout() {
    if (!Animating) _this.TimeoutHide();
  };
  
  function item_mouseover() {
    if (!Animating) {
      //_this.Show();
      _this.Items[this._index].HighLight();
    };
  }
  function item_mouseout() {
    if (!Animating) {
      _this.Items[this._index].DeHighLight();
    };
  }
  
  function item_click() {
    if (!Animating) {
      if (_this.Items[this._index].Link)  {
        location.href = _this.Items[this._index].Link; 
      };
    };
  };
  
  function AlignMenu() {
    var maxLeft = (window.innerWidth ? window.innerWidth : document.body.clientWidth) - parseInt(Cache["content"].style.width); 
      
  
    var ACoord = GetRelativeCoord(this.Activator);
    if (this.Direction == mrDropMenu.directions.down) {
      ACoord[0] += this.Activator.offsetHeight;
    } else {
      ACoord[1] += this.Activator.offsetWidth;
    };


    Cache['self'].style.top = ACoord[0]+'px';
    //if ((this.Direction == mrDropMenu.directions.down) && (ACoord[1] > maxLeft)) {
    //  ACoord[1] += this.Activator.offsetWidth;
    //   ACoord[1] -=  parseInt(Cache["content"].style.width);
    //}
    Cache['self'].style.left = ACoord[1] + 'px';

    Cache['self'].style.zIndex = mrDropMenu.defaultZ;
    Cache['self'].style.visibility = 'visible';
  };
  
  function Show() {
    if (this.Parent.CurrentIndex != this.index) {
      if (this.Parent.CurrentIndex != null) {
        //debug_view('Root_'+this.id+' Show, call Hide('+this.Parent.CurrentIndex+');');
        this.Parent.Menus[this.Parent.CurrentIndex].Hide();
      };
      this.Parent.CurrentIndex = this.index;
      
      // Preparing for show
      ////debug_view('z:'+Cache['self'].style.zIndex);
      
      this.AlignMenu();
      this.isOpen = true;
      AnimStart();
      //debug_view('Root_'+this.id+' Show() TimerActive ?:'+this.hTimeout);
    } else {
      //debug_view('Root_'+this.id+' Show, call CancelHide');
      this.CancelHide();
    };
  };
  function Hide () {
    if (Ready) {
      if (this.isOpen) {
        if (this.index == this.Parent.CurrentIndex) { this.Parent.CurrentIndex = null };
        if (this.hTimeout != null) window.clearTimeout(this.hTimeout);
        this.hTimeout = null;
        
        this.isOpen = false;
        for (var i =0; i < Cache['item'].length; i++) {
          this.Items[i].DeHighLight();
        };
        Cache['self'].style.zIndex = mrDropMenu.defaultZ - 1;
        AnimStart();
        //debug_view('Root_'+this.id+'.Hide('+str+')');
      };  
    };
  };
  
  function CancelHide() {
    //debug_view('Root_'+_this.id+' CancelHide() hTimeout='+this.hTimeout);
    window.clearTimeout(this.hTimeout);
    this.hTimeout = null;
  };
  
  function TimeoutHide() {
    if (this.hTimeout != null) { 
      //debug_view('Root_'+_this.id+' TimeoutHide Call CancelHide()');
      this.CancelHide();
    };
    if (this.isOpen) {
      //this.iTim += 1;
      this.hTimeout = window.setTimeout("mrDropRootItem.instances["+_this.id+"].Hide();",mrDropMenu.hidetime);
      //debug_view('Root_'+_this.id+' Timeout('+this.iTim+'), hTimeout='+this.hTimeout);
    };
  };
  
  function AnimStart() {
    var startp = _this.Direction == mrDropMenu.directions.down ? parseInt(Cache["content"].style['top']) : parseInt(Cache["content"].style['left']);
    var endp = _this.isOpen ? 0 : -FD;
    if (AnimTimer != null) { AnimTimer.stop(); };
    AnimTimer = new SlideTime(startp,endp,_this.isOpen);
    AnimTimer.OnSlide = AnimStep;
    AnimTimer.OnEnd = AnimEnd;
    Animating = true;
    AnimTimer.start();
  };
  
  function AnimStep(step) {
    if (_this.Direction == mrDropMenu.directions.down) { 
      // vertical
      Cache['content'].style.top = step+'px';
    } else {
      //horizontal
      Cache['content'].style.left = step+'px';
    };
  };
  function AnimEnd()  {
    Animating = false;
    if (!_this.isOpen) { Cache['self'].style.visibility = 'hidden'; };
    AnimTimer = null;
  };
};


/****************************************************************************************
  Класс mrDropItem 
*****************************************************************************************/
mrDropItem.instances = [];
function mrDropItem (oParent,sCaption,sLink) {
  this.Parent = oParent;
  // Assign to parent
  this.index = this.Parent.Items.length;
  this.Parent.Items[this.index] = this;
  // Assign to global
  this.id = mrDropItem.instances.length;
  mrDropItem.instances[this.id] = this;
  
    
  this.Caption = sCaption;
  this.Link = sLink;
  this.HTMLObj = null;
  // Функции класа
  this.toString = toString;
  
  this.HighLight = HighLight;
  this.DeHighLight = DeHighLight;
  
  function toString () {
    return '<TR class="item"><TD width="'+mrDropMenu.padding.before+'"><img src="'+mrDropMenu.img.spacer+'" height="1" width="'+mrDropMenu.padding.before+'" alt="" /></TD><TD nowrap>'+this.Caption+'</TD><TD width="'+mrDropMenu.padding.after+'"><img src="'+mrDropMenu.img.spacer+'" height="1" width="'+mrDropMenu.padding.after+'" alt="" /></TD></TR>';
  };
  
  
  function HighLight () {
    this.HTMLObj.className = 'hoveritem';
  };
  function DeHighLight () {
    this.HTMLObj.className = 'item';
  };

};

/****************************************************************************************
    Вспомогательные функции
*****************************************************************************************/
function GetRelativeCoord(oObject) {
  var Top = oObject.offsetTop;
  var Left = oObject.offsetLeft;
  while (oObject.offsetParent != null) {
    oObject = oObject.offsetParent;
    Top += oObject.offsetTop; 
    Left += oObject.offsetLeft; 
  };  
  return new Array(Top,Left);
};

/****************************************************************************************
  Slide Timer 
  Генератор событий для плавного движения обьекта за заданое время
  
  SlideTime(StartP,StopP,Time);
  где
     StartP - начальная точка
      StopP - конечная точка
       Time - желаемое время достижения конечной точки
  Direction - направление отсчета: увеличение (true) или уменьшение (false).

*****************************************************************************************/
function SlideTime(StartP, StopP, Direction, Time) {
  if (typeof Direction == "undefined") { Direction = true };
  this.Direction = Direction; 
  if (typeof Time == "undefined") { Time = 150 };
  this.Time  = Time;
  this.Start = StartP;
  this.Stop  = StopP;
  this.CurrentPos = this.Start;
  this.DeltaSlide = Math.round ((this.Stop - this.Start) / Math.round (this.Time / SlideTime.TimerResolution) );
  this.OnSlide = new Function ();
  this.OnEnd   = new Function ();
};

SlideTime.prototype.start = function () {
  SlideTime._add( this );
};

SlideTime.prototype.stop = function () {
  SlideTime._remove( this ); 
};

SlideTime.prototype._Slide = function () {
  this.CurrentPos += this.DeltaSlide; 
  if (this.Direction ? (this.CurrentPos > this.Stop): (Math.abs(this.CurrentPos) > Math.abs(this.Stop))) {
    SlideTime._remove ( this );
	  this.OnSlide(this.Stop);
	  this.OnEnd();
	  return;
  };
  this.OnSlide(this.CurrentPos); 
};

SlideTime._add = function (instance) {
  this.instances[this.instances.length] = instance;
  if ( this.instances.length == 1 ) {
    this.TimerID = window.setInterval("SlideTime.__TickAll()" , SlideTime.TimerResolution);
  };
};

SlideTime._remove = function (instance) {
  for (i=0; i<this.instances.length; i++) {
    if (this.instances[i] == instance) {
	    this.instances = this.instances.slice(0,i).concat (this.instances.slice(i+1)); 
	    break;
    };
  };
  if (this.instances.length == 0) {
    window.clearInterval(this.TimerID);
    this.TimerID = null;
  };
};

SlideTime.__TickAll = function () {
  for (i=0; i<this.instances.length; i++) {
    this.instances[i]._Slide(); 
  };
};

SlideTime.instances = [];
SlideTime.TimerResolution = 10;
SlideTime.TimerID = null;