Ext.namespace('DND');

/**
 *  @class DND.Scroller
 */
DND.Scroller = function(el)
{
  var tt = {
    'created': {
      'init' : [
        {
          action: this.init,
          state: 'initialized'
        }
      ]
    },
    'initialized' : {
      'mouseover' : [
        {
          predicate: this.isScrollable,
          action: this.setMoveCursor
        },
        {
          action: this.setOriginalCursor
        }
      ],
      'mousedown' : [
        {
          predicate: this.isTargetFormInputControl
          // do nothing
        },
        {
          predicate: this.isScrollable,
          action: [
            this.startDragScroll,
            this.attachToBodyMouseMoveEvent,
            this.attachToBodyMouseUpEvent, 
            this.stopBrowserEvent
          ],
          state: 'drag-scroll'
        },
        {
          // Если не скролируемо, то и делать нечего.
        }
      ]
    },
    'drag-scroll' : {
      'mousemove' : [
        {
          action: [this.dragScroll, this.stopBrowserEvent]
        }
      ],
      'mouseup' : [
        {
          action: [
            this.detachFromBodyMouseMoveEvent,
            this.detachFromBodyMouseUpEvent, 
            this.stopDragScroll,
            this.stopBrowserEvent
          ],
          state: 'initialized'
        }
      ],
      'mouseover' : [{}],
      'mousedown' : [{}]
    }
  }
  this.fsa = new Ext.ux.Utils.FSA('created', tt, this);
  this.fsa.postEvent('init', el);
}

Ext.override(DND.Scroller, {
  fsa : null,
  el : null,
  original_cursor : null,
  drag_scroll_start_point : null,
  last_scroll_time : null,
  
  init : function(el) 
  {
    this.el = Ext.get(el);
    this.el.position();
    this.el.setStyle('overflow', 'hidden');
    this.original_cursor = this.el.getStyle('cursor');
    //this.el.unselectable();
    
    var fsa = this.fsa;
    this.el.on('mouseover', function(ev) {fsa.postEvent('mouseover', ev);});
    this.el.on('mousedown', function(ev) {fsa.postEvent('mousedown', ev);});
    if (Ext.isIE) {
      this.el.on('dragstart', function(ev) { ev.stopEvent(); });
    }
  },
  
  isTargetFormInputControl : function(ev)
  {
    var tagName = ev.getTarget().tagName.toLowerCase();
    return tagName == 'input' || 
           tagName == 'textarea' || 
           tagName == 'button' ||
           tagName == 'select';
  },
  
  isScrollable : function(ev)
  {
    return this.el.isScrollable();
  },
  
  setMoveCursor : function(ev)
  {
    this.el.setStyle('cursor', 'move');
  },
  
  setOriginalCursor : function(ev)
  {
    this.el.setStyle('cursor', this.original_cursor);
  },
  
  stopBrowserEvent : function(ev)
  {
    ev.stopEvent();
  },
  
  attachToBodyMouseMoveEvent : function(ev)
  {
    Ext.EventManager.addListener(document.body, 'mousemove', this.onBodyMouseMove, this);
  },
  
  detachFromBodyMouseMoveEvent : function(ev)
  {
    Ext.EventManager.removeListener(document.body, 'mousemove', this.onBodyMouseMove, this);
  },
  
  onBodyMouseMove : function(ev)
  {
    this.fsa.postEvent('mousemove', ev);
  },
  
  attachToBodyMouseUpEvent : function()
  {
    Ext.EventManager.addListener(document.body, 'mouseup', this.bodyMouseUpHandler, this);
  },
  
  detachFromBodyMouseUpEvent : function()
  {
    Ext.EventManager.removeListener(document.body, 'mouseup', this.bodyMouseUpHandler);
  },
  
  bodyMouseUpHandler : function(ev)
  {
    this.fsa.postEvent('mouseup', ev);
  },
  
  startDragScroll : function(ev)
  {
    this.drag_scroll_start_point = ev.getXY();
    this.last_scroll_time = ev.getTime();
  },
  
  dragScroll : function(ev)
  {
    var xy = ev.getXY(); xy.x = xy[0]; xy.y = xy[1];
    var pxy = this.drag_scroll_start_point; pxy.x = pxy[0]; pxy.y = pxy[1];
    
    if (xy.x < pxy.x) {
      this.el.scroll('left', pxy.x - xy.x, false);
    }
    else {
      this.el.scroll('right', xy.x - pxy.x, false);
    }
    if (xy.y < pxy.y) {
      this.el.scroll('bottom', pxy.y - xy.y, false);
    }
    else {
      this.el.scroll('top', xy.y - pxy.y, false);
    }
    
    this.drag_scroll_start_point = xy;
  },
  
  stopDragScroll : function(ev)
  {
    this.drag_scroll_start_point = null;
  },
  
  lastScrollStartTime : function()
  {
    return this.last_scroll_time;
  }
});

/**
 *  @class DND.FolioMenu
 */
DND.FolioMenu = function(callback, scope)
{
  this.callback = callback || Ext.emptyFn;
  this.scope = scope || window;

  var tt = {
    // --------------
    'created' : {
    // --------------
      'init' : [
        {
          action: [this.init, this.hideFolioMenuSublevels, this.attachToFolioMenuItems],
          state: 'level-2'
        }
      ]
    },
    // --------------
    'level-2' : {
    // --------------
      'item-2-over' : [
        {
          predicate: this.isNotActiveItem,
          action: this.delayItem2ClickTask
        },
        {
          // If is active then do nothing
        }
      ],
      'item-2-out' : [
        {
          action: this.cancelDelayedTask
        }
      ],
      'item-2-click' : [
        {
          predicate: this.isNotActiveItem,
          action: [
            this.cancelDelayedTask, 
            this.resetLevel2MenuActiveItem, 
            this.setItemActive, 
            this.showLevel3Menu
          ],
          state: 'level-3'
        },
        {
          // If is active then do nothing
        }
      ],
      'close-click-3' : [{}] // Может прийти из метода closeMenu()
    },
    // --------------
    'level-3' : {
    // --------------
      'item-2-over' : [
        {
          predicate: this.isNotActiveItem,
          action: this.delayItem2ClickTask
        },
        {
          // If is active then do nothing
        }
      ],
      'item-2-out' : [
        {
          action: this.cancelDelayedTask
        }
      ],
      'item-2-click' : [
        {
          predicate: this.isNotActiveItem,
          action: [
            this.cancelDelayedTask, 
            this.resetLevel2MenuActiveItem, 
            this.setItemActive, 
            this.showLevel3Menu
          ]
        },
        {
          // If is active then do nothing
        }
      ],
      'item-3-over' : [
        {
          predicate: this.isNotActiveItem,
          action: this.delayItem3ClickTask
        },
        {
          // If is active then do nothing
        }
      ],
      'item-3-out' : [
        {
          action: this.cancelDelayedTask
        }
      ],
      'item-3-click' : [
        {
          predicate: this.isNotActiveItem,
          action: [
            this.cancelDelayedTask, 
            this.resetLevel3MenuActiveItem,
            this.setItemActive, 
            this.showLevel4Menu
          ],
          state: 'level-4'
        },
        {
          // If is active then do nothing
        }
      ],
      'close-click-3' : [
        {
          action: [this.resetLevel2MenuActiveItem, this.removeLevel3Menu],
          state: 'level-2'
        }
      ]
    },
    // --------------
    'level-4' : {
    // --------------
      'item-2-over' : [
        {
          predicate: this.isNotActiveItem,
          action: this.delayItem2ClickTask
        },
        {
          // If is active then do nothing
        }
      ],
      'item-2-out' : [
        {
          action: this.cancelDelayedTask
        }
      ],
      'item-2-click' : [
        {
          predicate: this.isNotActiveItem,
          action: [
            this.cancelDelayedTask, 
            this.resetLevel2MenuActiveItem, 
            this.setItemActive, 
            this.showLevel3Menu
          ],
          state: 'level-3'
        },
        {
          // If is active then do nothing
        }
      ],
      'item-3-over' : [
        {
          predicate: this.isNotActiveItem,
          action: this.delayItem3ClickTask
        },
        {
          // If is active then do nothing
        }
      ],
      'item-3-out' : [
        {
          action: this.cancelDelayedTask
        }
      ],
      'item-3-click' : [
        {
          predicate: this.isNotActiveItem,
          action: [
            this.cancelDelayedTask, 
            this.resetLevel3MenuActiveItem,
            this.setItemActive, 
            this.showLevel4Menu
          ]
        },
        {
          // If active then do nothing
        }
      ],
      'close-click-3' : [
        {
          action: [this.resetLevel2MenuActiveItem, this.removeLevel3Menu],
          state: 'level-2'
        }
      ],
      'close-click-4' : [
        {
          action: [this.resetLevel3MenuActiveItem, this.removeLevel4Menu],
          state: 'level-3'
        }
      ],
      'item-4-click' : [
        {
          action: [this.fireSeriesClickEvent, this.resetLevel2MenuActiveItem, this.removeLevel3Menu],
          state: 'level-2'
        }
      ]
    }
  }
  this.fsa = new Ext.ux.Utils.FSA('created', tt, this);
  this.fsa.postEvent('init');
}

Ext.override(DND.FolioMenu, {

  fsa : null,
  
  callback : null,
  
  scope : null,
  
  level_2_menu_el : null,
  
  level_3_menu_el : null,
  
  level_4_menu_el : null,
  
  delayed_task : null,
  
  delay_interval : 300,
  
  init : function()
  {
    this.delayed_task = new Ext.util.DelayedTask();
    this.level_2_menu_el = Ext.get('folio-menu-level-2');
    //this.level_2_menu_el.x_scroller = new DND.Scroller(this.level_2_menu_el);
  },
  
  hideFolioMenuSublevels : function()
  {
    var nodes = this.level_2_menu_el.query('li.level-3');
    for (var i = 0, len = nodes.length; i < len; i++) {
      var node = Ext.get(nodes[i]);
      node.enableDisplayMode().hide();
    }
  },
  
  attachToFolioMenuItems : function()
  {
    var items = this.level_2_menu_el.query('h2');
    for (var i = 0, len = items.length; i < len; i++) {
      var item = Ext.get(items[i]);
      item.addClassOnOver('over');
      item.on('mouseover', this.onFolioMenuItem2Over, this);
      item.on('mouseout', this.onFolioMenuItem2Out, this);
      item.on('click', this.onFolioMenuItem2Click, this);
    }
  },
  
  closeMenu : function()
  {
    this.fsa.postEvent('close-click-3');
  },
  
  isNotActiveItem : function(el)
  {
    return Ext.fly(el).hasClass('active') == false;
  },
  
  isActiveItem : function(el)
  {
    return Ext.fly(el).hasClass('active') == true;
  },
  
  setItemActive : function(el)
  {
    Ext.fly(el).addClass('active');
  },
  
  resetLevel2MenuActiveItem : function()
  {
    var el = this.level_2_menu_el.child('.active');
    if (el) {
      el.removeClass('active');
    }
  },
  
  resetLevel3MenuActiveItem : function()
  {
    var el = this.level_3_menu_el.child('.active');
    if (el) {
      el.removeClass('active');
    }
  },
  
  cancelDelayedTask : function()
  {
    this.delayed_task.cancel();
  },
  
  delayItem2ClickTask : function(el)
  {
    this.delayed_task.delay(this.delay_interval, this.postDelayedItem2ClickEvent, this, [el]); 
  },
  
  postDelayedItem2ClickEvent : function(el)
  {
    this.fsa.postEvent('item-2-click', el);
  },
  
  showLevel3Menu : function(el)
  {
    this.removeLevel3Menu();
    this.createLevel3Menu(el);
  },
  
  removeLevel3Menu : function()
  {
    if (this.level_3_menu_el) {
      this.level_3_menu_el.remove();
      this.level_3_menu_el = null;
    }
    if (this.level_4_menu_el) {
      this.level_4_menu_el.remove();
      this.level_4_menu_el = null;
    }
  },
  
  createLevel3Menu : function(el)
  {
    el = Ext.get(el);
    var parent = el.findParent('li', this.level_2_menu_el, true);
    var items = parent.query('li>h3');
    
    if (items.length > 0) {
      this.createLevel3MenuFrame(items)
    }
  },
  
  createLevel3MenuFrame : function(items)
  {
    this.level_3_menu_el = Ext.DomHelper.append(
      //'content-frame',
      document.body,
      {
        tag: 'div',
        id: 'folio-menu-level-3',
        children: [
          {
            tag: 'div',
            cls: 'trans-back'
          },
          {
            tag: 'div',
            cls: 'header',
            children: [
              {
                tag: 'div',
                cls: 'close'
              }
            ]
          },
          {
            tag: 'div',
            cls: 'scroller',
            children: [{
              tag: 'ul',
              cls: 'folio-menu'
            }]
          }
        ]
      },
      true
    );
    
    
    var trans_back = this.level_3_menu_el.child('.trans-back');
    trans_back.setOpacity(0.8);
    var close = this.level_3_menu_el.child('.close');
    close.on('click', this.onFolioMenu3CloseClick, this);
    var ul = this.level_3_menu_el.child('ul');
    
    for (var i = 0, len = items.length; i < len; i++) {
      var folio_id = Ext.id(items[i]);
      folio_id = folio_id.substr(6); // folio-xx
      var item = Ext.DomHelper.append(
        ul,
        {
          tag: 'li',
          id: 'folio-item-3-' + folio_id,
          cls: 'level-3',
          children: [{
            tag: 'h3',
            html: items[i].innerHTML
          }]
        },
        true
      );
      item.addClassOnOver('over');
      item.on('mouseover', this.onFolioMenuItem3Over, this);
      item.on('mouseout', this.onFolioMenuItem3Out, this);
      item.on('click', this.onFolioMenuItem3Click, this);
    }

    var scroller = this.level_3_menu_el.child('.scroller');
    this.level_3_menu_el.x_scroller = new DND.Scroller(scroller);
  },
  
  delayItem3ClickTask : function(el)
  {
    this.delayed_task.delay(this.delay_interval, this.postDelayedItem3ClickEvent, this, [el]); 
  },
  
  postDelayedItem3ClickEvent : function(el)
  {
    this.fsa.postEvent('item-3-click', el);
  },
  
  showLevel4Menu : function(el)
  {
    this.removeLevel4Menu();
    this.createLevel4Menu(el);
  },
  
  removeLevel4Menu : function()
  {
    if (this.level_4_menu_el) {
      this.level_4_menu_el.remove();
      this.level_4_menu_el = null;
    }
  },
  
  createLevel4Menu : function(el)
  {
    var id = Ext.id(el);
    id = id.substr(13); // folio-item-3-xx
    this.level_4_menu_el = Ext.DomHelper.append(
      //'content-frame',
      document.body,
      {
        tag: 'div',
        id: 'folio-menu-level-4',
        children: [
          {
            tag: 'div',
            cls: 'trans-back'
          },
          {
            tag: 'div',
            cls: 'header',
            children: [
              {
                tag: 'div',
                cls: 'close'
              }
            ]
          },
          {
            tag: 'div',
            cls: 'scroller',
            children: [{
              tag: 'ul',
              cls: 'folio-menu'
            }]
          }
        ]
      },
      true
    );
    
    var trans_back = this.level_4_menu_el.child('.trans-back');
    trans_back.setOpacity(0.8);
    var close = this.level_4_menu_el.child('.close');
    close.on('click', this.onFolioMenu4CloseClick, this);
    
    var scroller = this.level_4_menu_el.child('.scroller');
    this.level_4_menu_el.x_scroller = new DND.Scroller(scroller);
    
    var mgr = scroller.getUpdateManager();
    mgr.on('update', this.onFolioPreviewLoaded, this);
    mgr.update('/folio-preview/' + id);
  },
  
  fireSeriesClickEvent : function(ev)
  {
    this.callback.call(this.scope, ev);
  },
  
  onFolioMenu3CloseClick : function(ev)
  {
    this.fsa.postEvent('close-click-3');
    ev.preventDefault();
  },
  
  onFolioMenu4CloseClick : function(ev)
  {
    this.fsa.postEvent('close-click-4');
    ev.preventDefault();
  },
  
  onFolioMenuItem2Over : function(ev)
  {
    this.fsa.postEvent('item-2-over', ev.getTarget());
    ev.preventDefault();
  },
  
  onFolioMenuItem2Out : function(ev)
  {
    this.fsa.postEvent('item-2-out', ev.getTarget());
    ev.preventDefault();
  },
  
  onFolioMenuItem2Click : function(ev)
  {
    this.fsa.postEvent('item-2-click', ev.getTarget());
    ev.preventDefault();
  },
  
  onFolioMenuItem3Over : function(ev)
  {
    this.fsa.postEvent('item-3-over', ev.getTarget('li'));
    ev.preventDefault();
  },
  
  onFolioMenuItem3Out : function(ev)
  {
    this.fsa.postEvent('item-3-out', ev.getTarget('li'));
    ev.preventDefault();
  },
  
  onFolioMenuItem3Click : function(ev)
  {
    this.fsa.postEvent('item-3-click', ev.getTarget('li'));
  },
  
  onFolioMenuItem4Click : function(ev)
  {  
    var scroll_time = this.level_4_menu_el.x_scroller.lastScrollStartTime();
    var event_time = ev.getTime();
    
    if (scroll_time == null || (event_time - scroll_time) < 350) {   
      this.fsa.postEvent('item-4-click', ev.getTarget('a'));
    }
    ev.preventDefault();
  },
  
  onFolioPreviewLoaded : function(el, response)
  {
    var links = el.query('a');
    for (var i = 0, len = links.length; i < len; i++) {
      var link = Ext.get(links[i]);
      link.on('click', this.onFolioMenuItem4Click, this);
    }
  }
});

/**
 * @class DND.SiteController
 */
DND.SiteController = function()
{
  var content_el = null;
  var cup_mgr = null;
  var content_scroller = null;
  var folio_menu_scroller = null;
  var folio_menu = null;
  
  var module_load_handler = null;
  var module_load_handler_scope = null;
  
  function attachToContentElement()
  {
    content_el = Ext.get('content');
    cup_mgr = content_el.getUpdateManager();
    cup_mgr.loadScripts = true;
    cup_mgr.on('beforeupdate', onBeforeContentUpdate);
    cup_mgr.on('update', onContentUpdateSuccess);
    cup_mgr.on('failure', onContentUpdateFailure);
    content_scroller = new DND.Scroller(content_el);
  }
  
  function createFolioMenu()
  {
    folio_menu = new DND.FolioMenu(onSeriesItemSelect);
  }
  
  function requestContent(link)
  {
    folio_menu.closeMenu();
  
    content_el.scrollTo('top', 0);
    content_el.scrollTo('left', 0);
  
    var href = link.href;
    var matches = href.match(/(?:http|https):\/\/[^\/]+(.+)/);
    if (matches && matches.length > 1) {
      cup_mgr.update(href);
      href = matches[1];
      window.location.hash = '#' + href;
    }
  }
  
  function resetModule()
  {
    resetModuleLoadHandler();
    DND.SiteController.Module = null;
  }
  
  function resetModuleLoadHandler()
  {
    module_load_handler = null;
    module_load_handler_scope = null;
  }
  
  function applyHash()
  {
    var hash = window.location.hash;
    if (hash.length < 2) {
      return;
    }
    cup_mgr.update(hash.substr(2));
  }
  
  function onSeriesItemSelect(link)
  {
    requestContent(link);
  }
  
  function onBeforeContentUpdate(el, url, params)
  {
    resetModule();
  }
  
  function onContentUpdateSuccess(el, response)
  {
    if (module_load_handler) {
      module_load_handler.call(module_load_handler_scope);
    }
  }
  
  function onContentUpdateFailure(el, response)
  {
    // TODO: Сделать какую-нибудь обработку и сигнализацию
  }
  
  // Заглушки
  function attachToLogo()
  {
    var logo = Ext.get('logo');
    logo.setStyle('cursor', 'pointer');
    logo.on('click', onLogoClick);
  }
  
  function onLogoClick(el)
  {
    content_el.update('');
    window.location.hash = '#';
  }
  
  function attachToMenu()
  {
    var contacts = Ext.get('top-menu-contacts');
    var rental = Ext.get('top-menu-about');
    var video = Ext.get('top-menu-news');
    video.setStyle('text-decoration', 'line-through');
    contacts.on('click', onContactsClick);
    rental.on('click', onRentalClick);
  }
  
  function onContactsClick(ev)
  {
    requestContent(ev.getTarget());
    ev.stopEvent();
  }
  
  function onRentalClick(ev)
  {
    requestContent(ev.getTarget());
    ev.stopEvent();
  }
  // ----------------------

  return {
    run : function()
    {
      if (
        typeof(XMLHttpRequest) != 'undefined' || 
        window.navigator.appVersion.search(/MSIE\s6/) != -1
      ) {
        attachToContentElement();
        createFolioMenu();
        applyHash();
        attachToLogo();
        attachToMenu();
      }
    },
    
    onModuleLoad : function(handler, scope)
    {
      module_load_handler = handler || Ext.emptyFn;
      module_load_handler_scope = scope || DND.SiteController.Module || window;
    },
    
    Module : null
  }
}()

Ext.onReady(DND.SiteController.run);