﻿IndexView = function(container, loadingContainer, showTopicsButton, closeTopicsButton, topicsCounter, topicListContainer, topicList, keywordInput, count) {
  this.container = container;
  this.loadingContainer = loadingContainer;
  this.showTopicsButton = showTopicsButton;
  this.closeTopicsButton = closeTopicsButton;
  this.topicsCounter = topicsCounter;
  this.topicListContainer = topicListContainer;
  this.topicList = topicList;
  this.keywordInput = keywordInput;
  this.count = count;
  this.ul = document.createElement("ul");
  $(this.ul).css("width", "auto");
  this.container.appendChild(this.ul);

  $(this.container).bind("scroll", this, this.onScroll);

  var eventName = $.browser.opera ? "keypress" : "keydown";
  $(this.container).bind(eventName, this, this.onContainerKeydown);
  $(this.topicList).bind(eventName, this, this.onTopicListKeydown);
  $(this.keywordInput).bind(eventName, this, this.onKeydown);

  $(this.keywordInput).bind("keyup", this, this.onKeywordChange);
  $(this.showTopicsButton).bind("click", this, this.onShowTopicsButtonClick);
  $(this.showTopicsButton).bind("keydown", this, this.onShowTopicsButtonKeydown);
  $(this.closeTopicsButton).bind("click", this, this.onCloseTopicsButtonClick);

  this.canScroll = true;
}

IndexView.prototype = {
  skipScrollTime: 500,
  skipSearchTime: 500,
  scrollNumber: 0,
  keywordNumber: 0,
  activeIndexPosition: null,
  lastKeyword: null,
  customKeyword: false,
  indexItems: null,
  lastFocused: null,
  lastActive: null,

  refresh: function() {
    this.activeIndexPosition = null;
    this.customKeyword = false;
    this.lastKeyword = null;
    this.initialize();
  },

  getKeywordValue: function() {
    return this.keywordInput.value;
  },

  setKeywordValue: function(value) {
    this.keywordInput.value = value;
    this.customKeyword = true;
    this.saveToCookie(value);
  },

  setKeywordValueInternal: function(value) {
    this.keywordInput.value = value;
    this.customKeyword = false;
    this.saveToCookie(value);
  },

  load: function(data) {
    $(this.ul).find("a").unbind();
    $(this.ul).empty();
    this.indexItems = [];
    for (var i = 0; i < data.length; i++) {
      var indexItem = data[i];
      var li = document.createElement("li");
      this.ul.appendChild(li);

      this.indexItems[indexItem.Position] = indexItem;
      $(li).attr("itemPosition", indexItem.Position);

      if (indexItem.Indent > 0)
        $(li).addClass("L1");

      var anchor;
      if (indexItem.Url != null && indexItem.Url.length > 0) {
        anchor = document.createElement("a");
        $(anchor).attr("href", "Content.aspx/" + indexItem.Url);
        $(anchor).attr("target", "contentFrame");
      }
      else if (indexItem.Topics.length == 1) {
        anchor = document.createElement("a");
        $(anchor).attr("href", "Content.aspx/" + indexItem.Topics[0].Url);
        $(anchor).attr("target", "contentFrame");
      }
      else
        anchor = $("<a href='#' onclick='javascript:return false;'></a>")[0];

      $(anchor).bind("click", { indexView: this, indexItem: indexItem, anchor: anchor }, this.onItemClick);
      $(anchor).bind(
        "focus",
        { indexView: this, anchor: anchor },
        function(event) {
          var indexView = event.data.indexView;
          $(indexView.ul).find("li[class*='ActiveIndexItem']").removeClass("ActiveIndexItem");
          var li = $(event.data.anchor).parents("li:first");
          li.addClass("ActiveIndexItem");
          indexView.lastFocused = li.attr("itemPosition");
          indexView.lastActive = indexView.lastFocused;
          var indexItem = indexView.indexItems[indexView.lastFocused];
          indexView.setKeywordValueInternal(indexItem.FullTitle != null ? indexItem.FullTitle : indexItem.Title);
        });
      $(anchor).html(indexItem.Title);
      li.appendChild(anchor);

      if (indexItem.Position == this.lastFocused)
        $(anchor).focus();
    }

    if (this.lastFocused != null && this.indexItems[this.lastFocused] != null)
      $(indexView.ul).find("li[itemPosition=" + this.lastFocused + "]:first>a").focus();
    else if (this.lastActive != null && this.indexItems[this.lastActive] != null)
      $(indexView.ul).find("li[itemPosition=" + this.lastActive + "]:first").addClass("ActiveIndexItem");

    if (data.length > 0) {
      var itemHeight = this.ul.offsetHeight / data.length;
      if (itemHeight != null && itemHeight != 0) {
        var first = $(this.ul).find("li:first")[0];
        var last = $(this.ul).find("li:last")[0];

        var firstItemHeight = (parseInt($(first).attr("itemPosition")) - 1) * itemHeight;

        if (firstItemHeight > 0) {
          if ($.browser.opera) {
            var li = document.createElement("li");
            $(li).css("height", firstItemHeight);
            this.ul.insertBefore(li, first);

            li = document.createElement("li");
            $(li).html(Resources.getInstance().loading);
            this.ul.insertBefore(li, first);
          }
          else {
            var li = document.createElement("li");
            $(li).css("margin-top", firstItemHeight);
            $(li).html(Resources.getInstance().loading);
            this.ul.insertBefore(li, first);
          }
        }

        //var lastItemHeight = this.count * itemHeight - last.offsetTop - itemHeight;
        var lastItemHeight = (this.count - parseInt($(last).attr("itemPosition")) - 2) * itemHeight;

        if (lastItemHeight > 0) {
          if ($.browser.opera) {
            var li = document.createElement("li");
            $(li).html(Resources.getInstance().loading);
            this.ul.appendChild(li);

            li = document.createElement("li");
            $(li).css("height", lastItemHeight);
            this.ul.appendChild(li);
          }
          else {
            var li = document.createElement("li");
            $(li).css("margin-bottom", lastItemHeight);
            $(li).html(Resources.getInstance().loading);
            this.ul.appendChild(li);
          }
        }
      }
    }
  },

  initialize: function() {
    try {
      this.keywordInput.focus();
      if ($.browser.msie) {
        if (this.keywordInput.createTextRange != null) {
          var r = this.keywordInput.createTextRange();
          r.collapse(false);
          r.select();
        }
      }
      else {
        if (this.keywordInput.selectionStart != null) {
          var end = this.keywordInput.value.length;
          this.keywordInput.setSelectionRange(end, end);
          this.keywordInput.focus();
        }
      }
    }
    catch (e) { }

    if (this.customKeyword) {
      var indexKeyword = this.keywordInput.value;
      this.searchKeyword(indexKeyword);
      this.customKeyword = false;
      return;
    }

    if (this.activeIndexPosition == null && window.navigator.cookieEnabled) {
      var cookie = document.cookie;
      var i = cookie.indexOf("indexKeyword=");
      if (i != -1) {
        var endIndex = cookie.indexOf(";", i + 13);
        var indexKeyword;
        if (endIndex == -1)
          indexKeyword = cookie.substring(i + 13);
        else
          indexKeyword = cookie.substring(i + 13, endIndex);
        this.keywordInput.value = indexKeyword;

        this.searchKeyword(indexKeyword);
        return;
      }
    }

    if (this.activeIndexPosition == null)
      this.activeIndexPosition = 0;

    var result = $(this.ul).find("li[itemPosition=" + this.activeIndexPosition + "]:first");
    if (result.length == 0) {
      this.showLoading();
      var indexView = this;
      Xtensive.HelpServer.Web.IndexProvider.Load(null, this.activeIndexPosition, function(data) {
        indexView.load(data.Items);
        indexView.hideLoading();
        var active = $(indexView.ul).find("li[itemPosition=" + indexView.activeIndexPosition + "]:first")[0];
        active.scrollIntoView(true);
        indexView.container.scrollLeft = 0;
      });
    }
    else {
      var active = result[0];
      active.scrollIntoView(true);
      this.container.scrollLeft = 0;
    }
  },

  isTopicListVisible: function() {
    return this.topicListContainer.style.display != 'none';
  },

  isShowTopicsButtonVisible: function() {
    return this.showTopicsButton.style.display != 'none';
  },

  hideTopicList: function(resetFocus) {
    this.topicListContainer.style.display = 'none';
    if (resetFocus)
      this.keywordInput.focus();
  },

  showTopicList: function() {
    this.topicListContainer.style.display = 'block';
    $(this.topicListContainer).find("a").focus();
  },

  onScroll: function(event) {
    var indexView = event.data;
    var scrollNumber = indexView.scrollNumber + 1;
    indexView.scrollNumber = scrollNumber;
    setTimeout(function() { indexView.scrollHandler(scrollNumber); }, indexView.skipScrollTime);
  },

  scrollHandler: function(scrollNumber) {
    if (scrollNumber != this.scrollNumber)
      return;
    var scrollPosition = this.container.scrollTop;
    var first = $(this.ul).find("li[itemPosition]:first")[0];
    var last = $(this.ul).find("li[itemPosition]:last")[0];
    var lowerBound = first.offsetTop;
    var itemHeight = this.container.scrollHeight / this.count;
    if (itemHeight == 0)
      return;
    var upperBound = last.offsetTop + itemHeight - this.container.clientHeight;
    var indexPosition = Math.round(scrollPosition / itemHeight);
    this.activeIndexPosition = indexPosition;
    if (scrollPosition > upperBound || scrollPosition < lowerBound) {
      if (!this.canScroll)
        return;
      this.canScroll = false;
      var indexView = this;
      this.showLoading();
      Xtensive.HelpServer.Web.IndexProvider.Load(null, indexPosition, function(data) {
        indexView.load(data.Items);
        indexView.hideLoading();
        var active = $(indexView.ul).find("li[itemPosition=" + indexPosition + "]:first")[0];
        active.scrollIntoView(true);
        indexView.container.scrollLeft = 0;
        indexView.canScroll = true;
        indexView.activeIndexPosition = indexPosition;
      });
    }
  },

  onKeywordChange: function(event) {
    if (event.keyCode == 40 || event.keyCode == 38 || event.keyCode == 13 || event.keyCode == 9 ||
        event.keyCode == 27 || event.keyCode == 33 || event.keyCode == 34)
      return;
    var indexView = event.data;
    var keywordNumber = indexView.scrollNumber + 1;
    indexView.keywordNumber = keywordNumber;
    this.customKeyword = false;
    setTimeout(function() { indexView.keywordChangeHandler(keywordNumber); }, indexView.skipSearchTime);
  },

  keywordChangeHandler: function(keywordNumber) {
    if (keywordNumber != this.keywordNumber)
      return;

    var newValue = this.keywordInput.value;
    if (this.lastKeyword != newValue) {
      this.lastKeyword = newValue;
      this.saveToCookie(newValue);
      this.searchKeyword(newValue);
    }
  },

  saveToCookie: function(value) {
    if (window.navigator.cookieEnabled) {
      var cookieDate = new Date();
      cookieDate.setFullYear(cookieDate.getFullYear() + 1);
      document.cookie = "indexKeyword=" + value + ";expires=" + cookieDate.toGMTString();
    }
  },

  searchKeyword: function(keyword) {
    var indexView = this;
    var open = this.customKeyword;
    indexView.showLoading();
    Xtensive.HelpServer.Web.IndexProvider.Load(keyword, null, function(data) {
      indexView.load(data.Items);
      indexView.hideLoading();
      $(indexView.ul).find("li[class*='ActiveIndexItem']").removeClass("ActiveIndexItem");
      var active = $(indexView.ul).find("li[itemPosition=" + data.IndexPosition + "]:first")[0];
      $(active).addClass("ActiveIndexItem");
      indexView.lastActive = data.IndexPosition;
      indexView.lastFocused = null;
      active.scrollIntoView(true);
      indexView.container.scrollLeft = 0;
      indexView.canScroll = true;
      indexView.activeIndexPosition = data.IndexPosition;
      if (open)
        indexView.showIndexItem(indexView.indexItems[data.IndexPosition], true);
    });
  },

  onItemClick: function(event) {
    event.data.anchor.focus();
    var indexItem = event.data.indexItem;
    var indexView = event.data.indexView;
    indexView.showIndexItem(indexItem, true);
  },

  onKeydown: function(event) {
    var indexView = event.data;
    indexView.lastFocused = null;
    if (event.keyCode == 13) {
      event.preventDefault();
      event.stopPropagation();
      var result = $(searchView.ul).find("li[itemPosition][class*='ActiveIndexItem']:first");
      if (result.length > 0)
        indexView.showIndexItem(indexView.indexItems[$(result[0]).attr('itemPosition')], true);
    }
    else if (event.keyCode == 9) {
      var result = $(indexView.ul).find("li[class*='ActiveIndexItem']:first>a")
      if (result.length > 0) {
        var anchor = result[0];
        anchor.focus();
      }
      else {
        result = $(indexView.ul).find("li[itemPosition=" + indexView.activeIndexPosition + "]:first>a");
        if (result.length > 0) {
          var anchor = result[0];
          anchor.focus();
        }
      }
      event.preventDefault();
      event.stopPropagation();
    }
    else if (event.keyCode == 40 || event.keyCode == 38) {
      // down || up
      var activeElements = $(indexView.container).find("li[class*='ActiveIndexItem']");
      if (activeElements.length == 0)
        activeElements = $(indexView.ul).find("li[itemPosition=" + indexView.activeIndexPosition + "]:first");
      if (activeElements.length > 0) {
        var keyUp = event.keyCode == 38;
        var elements;
        if (keyUp)
          elements = activeElements.prev("li[itemPosition]:first");
        else
          elements = activeElements.next("li[itemPosition]:first");

        if (elements.length > 0) {
          activeElements.removeClass("ActiveIndexItem");
          elements.addClass("ActiveIndexItem");
          var nextElement = elements[0];

          if ((keyUp && nextElement.offsetTop < indexView.container.scrollTop) ||
            (!keyUp && (nextElement.offsetTop + nextElement.scrollHeight > indexView.container.scrollTop + indexView.container.clientHeight))) {
            nextElement.scrollIntoView(keyUp);
            indexView.container.scrollLeft = 0;
          }
          indexView.lastActive = $(nextElement).attr("itemPosition");
          var indexItem = indexView.indexItems[indexView.lastActive];
          indexView.setKeywordValueInternal(indexItem.FullTitle != null ? indexItem.FullTitle : indexItem.Title);
        }
        else {
          var itemHeight = indexView.container.scrollHeight / indexView.count;
          if (itemHeight != 0)
            indexView.container.scrollTop += (keyUp ? -itemHeight : itemHeight);
        }
        event.preventDefault();
        event.stopPropagation();
      }
    }
    else if (event.keyCode == 34 || event.keyCode == 33) {
      // pageDown || pageUp
      var activeElements = $(indexView.container).find("li[class*='ActiveIndexItem']");
      if (activeElements.length == 0)
        activeElements = $(indexView.ul).find("li[itemPosition=" + indexView.activeIndexPosition + "]:first");
      if (activeElements.length > 0) {
        var itemHeight = indexView.container.scrollHeight / indexView.count;
        if (itemHeight != 0) {
          var toJump = Math.floor(indexView.container.clientHeight / itemHeight) - 2;
          if (toJump > 0) {
            var elements;
            var pageUp = event.keyCode == 33;
            if (event.keyCode == 33)
              elements = activeElements.prevAll("li[itemPosition]");
            else
              elements = activeElements.nextAll("li[itemPosition]");

            var nextElement = null;
            if (elements.length > toJump)
              nextElement = elements[toJump];
            else if (elements.length > 0)
              nextElement = elements[elements.length - 1];

            if (nextElement != null) {
              activeElements.removeClass("ActiveIndexItem");
              $(nextElement).addClass("ActiveIndexItem");

              if ((pageUp && nextElement.offsetTop < indexView.container.scrollTop) ||
                (!pageUp && (nextElement.offsetTop + nextElement.scrollHeight > indexView.container.scrollTop + indexView.container.clientHeight))) {
                nextElement.scrollIntoView(keyUp);
                indexView.container.scrollLeft = 0;
              }
              indexView.lastActive = $(nextElement).attr("itemPosition");
              var indexItem = indexView.indexItems[indexView.lastActive];
              indexView.setKeywordValueInternal(indexItem.FullTitle != null ? indexItem.FullTitle : indexItem.Title);
            }
            else
              indexView.container.scrollTop += (pageUp ? -indexView.container.clientHeight : indexView.container.clientHeight);
          }
        }
      }
      event.preventDefault();
      event.stopPropagation();
    }
  },

  showIndexItem: function(indexItem, open) {
    $(this.topicList).find("a").unbind();
    $(this.topicList).empty();

    var length = indexItem.Topics.length;
    if (length > 1) {
      $(this.topicsCounter).html(String.format(Resources.getInstance().indexResults, length));
      this.showTopicsButton.style.display = "block";
      var ul = document.createElement("ul");
      $(ul).css("width", "auto");
      this.topicList.appendChild(ul);

      for (var i = 0; i < length; i++) {
        var topic = indexItem.Topics[i];
        var li = document.createElement("li");
        ul.appendChild(li);

        var anchor = document.createElement("a");
        var url = "Content.aspx/" + topic.Url;
        $(anchor).attr("href", url);
        $(anchor).attr("target", "contentFrame");
        $(anchor).html(topic.Title);
        $(anchor).bind(
          "click",
          indexView,
          function(event) { event.data.hideTopicList(true); })
        $(anchor).bind(
          "focus",
          { indexView: this, anchor: anchor },
          function(event) {
            $(event.data.indexView.topicList).find("a[class*='ActiveTopic']").removeClass("ActiveTopic");
            $(event.data.anchor).addClass("ActiveTopic");
          });
        li.appendChild(anchor);

        if (open && i == 0) {
          indexView.showTopicList();

          var contentFrame = document.getElementById("contentFrame");
          contentFrame.contentWindow.location.href = url;
        }
      }
    }
    else {
      this.showTopicsButton.style.display = "none";
      this.hideTopicList(false);
      if (length == 1) {
        var topic = indexItem.Topics[0];
        var url = "Content.aspx/" + topic.Url;
        var contentFrame = document.getElementById("contentFrame");
        contentFrame.contentWindow.location.href = url;
      }
      else if (indexItem.Url != null && indexItem.Url.length > 0) {
        var url = "Content.aspx/" + indexItem.Url;
        var contentFrame = document.getElementById("contentFrame");
        contentFrame.contentWindow.location.href = url;
      }
    }
  },

  onShowTopicsButtonKeydown: function(event) {
    if (event.keyCode == 9) {
      var indexView = event.data;
      if (indexView.isTopicListVisible())
        indexView.setFocusOnTopicList();
      else
        indexView.keywordInput.focus();
      event.stopPropagation();
      event.preventDefault();
    }
  },

  onTopicListKeydown: function(event) {
    var indexView = event.data;
    if (event.keyCode == 40) {
      // down
      $(indexView.topicList).find("a[class*='ActiveTopic']").parents("li:first").next("li:first").find("a:first").focus();
      event.preventDefault();
    }
    else if (event.keyCode == 38) {
      // up
      prevElements = $(indexView.topicList).find("a[class*='ActiveTopic']").parents("li:first").prev("li:first").find("a:first").focus();
      event.preventDefault();
    }
    else if (event.keyCode == 9) {
      indexView.keywordInput.focus();
      event.preventDefault();
      event.stopPropagation();
    }
    else if (event.keyCode == 27) {
      event.data.hideTopicList(true);
      event.preventDefault();
      event.stopPropagation();
    }
  },

  onContainerKeydown: function(event) {
    var indexView = event.data;
    if (event.keyCode == 40 || event.keyCode == 38) {
      // down || up
      var elements;
      if (event.keyCode == 40)
        elements = $(indexView.container).find("li[class*='ActiveIndexItem']").next("li:first").find("a:first");
      else
        elements = $(indexView.container).find("li[class*='ActiveIndexItem']").prev("li:first").find("a:first");
      if (elements.length > 0) {
        elements.focus();
        event.preventDefault();
      }
    }
    else if (event.keyCode == 34 || event.keyCode == 33) {
      // pageDown || pageUp
      var itemHeight = indexView.container.scrollHeight / indexView.count;
      if (itemHeight != 0) {
        var toJump = Math.floor(indexView.container.clientHeight / itemHeight) - 2;
        if (toJump > 0) {
          var elements;
          if (event.keyCode == 34)
            elements = $(indexView.container).find("li[class*='ActiveIndexItem']").nextAll("li[itemPosition]");
          else
            elements = $(indexView.container).find("li[class*='ActiveIndexItem']").prevAll("li[itemPosition]");
          if (elements.length > toJump) {
            $(elements[toJump]).find("a:first").focus();
            event.preventDefault();
          }
          else if (elements.length > 0) {
            $(elements[elements.length - 1]).find("a:first").focus();
            event.preventDefault();
          }
        }
      }
    }
    else if (event.keyCode == 9) {
      if (indexView.isTopicListVisible())
        indexView.setFocusOnTopicList();
      else if (indexView.isShowTopicsButtonVisible())
        indexView.showTopicsButton.focus();
      else
        indexView.keywordInput.focus();
      event.preventDefault();
      event.stopPropagation();
    }
  },

  setFocusOnTopicList: function() {
    var result = $(this.topicList).find("a[class*='ActiveTopic']");
    if (result.length > 0)
      result[0].focus();
    else {
      result = $(this.topicList).find("a:first");
      if (result.length > 0)
        result[0].focus();
      else
        this.keywordInput.focus();
    }
  },

  hideLoading: function() {
    $(this.loadingContainer).css("display", "none");
    if (!$.browser.msie && !/chrome/.test(navigator.userAgent.toLowerCase()))
      $(this.container).css("opacity", "1");
  },

  showLoading: function() {
    $(this.loadingContainer).css("display", "");
    if (!$.browser.msie && !/chrome/.test(navigator.userAgent.toLowerCase()))
      $(this.container).css("opacity", "0.3");
  },

  onShowTopicsButtonClick: function(event) {
    var indexView = event.data;
    indexView.showTopicList();
    event.preventDefault();
    event.stopPropagation();
  },

  onCloseTopicsButtonClick: function(event) {
    var indexView = event.data;
    indexView.hideTopicList(true);
    event.preventDefault();
    event.stopPropagation();
  }
}