function IBEMenuManager() {

  this.menuList = new Array();

  this.addMenu = function (menu) {
    this.menuList[this.menuList.length] = menu;
  };

  this.findMenuById = function (id) {
    for (var i = 0; i < this.menuList.length; i++) {
      if (this.menuList[i].id == id) {
        return this.menuList[i];
      }
    }
    return null;
  };

  this.clickTabOnMenu = function (menuId, tabId) {
    var menu = this.findMenuById(menuId);
    if (menu) {
      menu.selectTabById(tabId);
    } else {
      ibeerror('IBEMenuManager trying to click tab of menu that does not exist, menu ID=' + menuId);
    }
  };

}
;

function IBETab(id, title, callback, url, cssClass) {
  // Constants
  var left = 'Left';
  var right = 'Right';
  var middle = 'Middle';
  var selected = 'Selected';

  // Constructor
  this.title = title;
  if (typeof callback == 'function' || callback === undefined) {
    this.callback = callback;
  } else {
    ibeerror('Tab "' + title + '" has invalid callback.');
  }

  // Members
  this.selected = false;
  this.parentMenu = undefined;
  this.url = url;
  this.id = id;
  this.index = undefined;
  this.parentObject = undefined;
  this.callbackScope = window;

  // CSS stuff
  this.leftCss = cssClass ? cssClass + left : undefined;
  this.middleCss = cssClass ? cssClass + middle : undefined;
  this.rightCss = cssClass ? cssClass + right : undefined;
  this.leftCssSelected = cssClass ? cssClass + left + selected : this.leftCss;
  this.middleCssSelected = cssClass ? cssClass + middle + selected : this.middleCss;
  this.rightCssSelected = cssClass ? cssClass + right + selected : this.rightCss;

  // Td node objects
  this.tdLeft = undefined;
  this.tdMiddle = undefined;
  this.tdRight = undefined;

  /**
   * Internal callback function. Is executed by parent class to select the tab.
   * @param doCallback If true, the callback will be executed. Defaults to true if not specified.
   * @param forceRender Forces the updates of the tabs CSS classes.
   */
  this.selectTab = function (doCallback, forceRender) {
    if (doCallback === undefined) doCallback = true;
    var isOk = undefined;
    if (!this.selected) {
      if (this.callback && doCallback) {
        isOk = this.callback.call(this.callbackScope, this.index, this, this.parentObject);
      }
      if (this.url && doCallback) {
        window.location = this.url;
        isOk = true;
      }
      if (isOk === undefined) isOk = true;
      if (isOk) {
        if (this.parentMenu.renderTabOnClick || forceRender) {
          if (this.leftCssSelected) this.tdLeft.className = this.leftCssSelected;
          if (this.middleCssSelected) this.tdMiddle.className = this.middleCssSelected;
          if (this.rightCssSelected) this.tdRight.className = this.rightCssSelected;
        }
        this.selected = true;
      }

    } else {
      isOk = false;
    }
    return isOk;

  };

  this.unselectTab = function (forceRender) {
    if (this.parentMenu.renderTabOnClick || forceRender) {
      if (this.leftCss) this.tdLeft.className = this.leftCss;
      if (this.middleCss) this.tdMiddle.className = this.middleCss;
      if (this.rightCss) this.tdRight.className = this.rightCss;
    }
    this.selected = false;
  };

  this.setCallbackScope = function(obj) {
    this.callbackScope = obj;
  };
}

function IBETabMenu(id, elementId) {
  this.id = id ? id : '';
  this.tabList = new Array();
  this.selectedIndex = undefined;
  this.elementId = elementId ? elementId : id;
  this.defaultTabIndex = 0;

  this.runCallbackAtRender = false;
  this.startWithSeparator = false;
  this.useHref = false; // Defines if we use href when using URL. Otherwise, use only window.location = ..

  this.separatorCss = 'tabMenuEmpty';
  this.tableCss = 'tabMenuTable';
  this.rowCss = 'tabMenuRow';

  // This can be set to false, then, if a tab is clicked, the CSS wont change. This is good when using URL instead of event.
  this.renderTabOnClick = true;

  // Tab default CSS (only used if tab has no CSS)
  this.leftCss = undefined;
  this.rightCss = undefined;
  this.middleCss = undefined;
  this.leftCssSelected = undefined;
  this.rightCssSelected = undefined;
  this.middleCssSelected = undefined;

  this.setRenderOnClick = function(enabled) {
    this.renderTabOnClick = enabled;
  };

  this.addTab = function (tab) {
    this.tabList[this.tabList.length] = tab;
    tab.parentMenu = this;
  };

  this.getTabByIndex = function(i) {
    return this.tabList[i];
  };

  this.getTabById = function (id) {
    for (var i = 0; i < this.tabList.length; i++) {
      if (this.tabList[i].id == id) {
        return this.tabList[i];
      }
    }
    return null;
  };

  this.getTabIndexById = function (id) {
    for (var i = 0; i < this.tabList.length; i++) {
      if (this.tabList[i].id == id) {
        return i;
      }
    }
    return null;
  };

  this.getTabIndexByTitle = function (title) {
    for (var i = 0; i < this.tabList.length; i++) {
      if (this.tabList[i].title == title) {
        return i;
      }
    }
    return null;
  };

  this.getFirstTab = function () {
    return this.tabList[0];
  };

  this.getLastTab = function () {
    return this.tabList[this.tabList.length - 1];
  };

  this.clearSelected = function () {
    for (var i = 0; i < this.tabList.length; i++) {
      var tab = this.tabList[i];
      tab.selected = false;
      var id = 'tabMenuButton' + i + this.id;
      setElementsClass(id, 'tabMenuButton');
    }
  };

  this.setDefault = function (id) {
    for (var i = 0; i < this.tabList.length; i++) {
      var tab = this.tabList[i];
      if (tab.id == id) {
        this.defaultTabIndex = i;
        return;
      }
    }
  };

  /**
   * Sets default tab to the tab with title=title. If success, returns true. If false, uses defaultIndex if it is set, and then returns false.
   * @param title
   */
  this.setDefaultByTitle = function (title, defaultIndex) {
    var index = this.getTabIndexByTitle(title);
    if (!nullOrUndefined(index) && index >= 0) {
      this.setDefaultIndex(index);
      return true;
    } else {
      if (defaultIndex >= 0) this.setDefaultIndex(defaultIndex);
      return false;
    }
  };

  this.setDefaultIndex = function (i) {
    this.defaultTabIndex = i;
  };

  this.getDefaultId = function() {
    return this.tabList[this.defaultTabIndex].id;
  };

  this.getDefaultIndex = function() {
    return this.defaultTabIndex;
  };

  this.render = function () {
    var placeHolder = getObj(this.elementId);
    if (placeHolder == null) {
      ibeerror('Trying to render tab view to non existing element, id=', this.elementId);
      return;
    }

    // Table
    var table = document.createElement('table');
    table.id = this.id + 'Table';
    table.className = this.tableCss;
    table.cellSpacing = '0';
    table.cellPadding = '0';
    table.border = '0';

    // Tr
    var tr = table.insertRow(0);
    tr.className = this.rowCss;

    if (this.startWithSeparator) {
      var emptytd = tr.insertCell(-1);
      emptytd.className = this.separatorCss;
    }

    for (var i = 0; i < this.tabList.length; i++) {
      var tab = this.tabList[i];
      var tdL = tab.leftCss || this.leftCss ? tr.insertCell(-1) : undefined;
      var tdM = tr.insertCell(-1);
      var tdR = tab.rightCss || this.rightCss ? tr.insertCell(-1) : undefined;

      if (tdL) {
        if (!tab.leftCss) tab.leftCss = this.leftCss;
        if (!tab.leftCssSelected) tab.leftCssSelected = this.leftCssSelected;
        tdL.id = this.id + '_Button_' + i + '_Left';
        YAHOO.util.Event.on(tdL, "click", this.selectTabEvent, i, this);
      }

      tdM.id = this.id + '_Button_' + i + '_Middle';
      if (!tab.middleCss) tab.middleCss = this.middleCss;
      if (!tab.middleCssSelected) tab.middleCssSelected = this.middleCssSelected;
      YAHOO.util.Event.on(tdM, "click", this.selectTabEvent, i, this);
      if (tab.url && this.useHref) tdM.innerHTML = '<a href="' + tab.url + '">' + tab.title + '</a>';
      else tdM.innerHTML = tab.title;
      tdM.innerHTML = '<span class="tabTitle">' + tdM.innerHTML + '</span>';

      if (tdR) {
        if (!tab.rightCss) tab.rightCss = this.rightCss;
        if (!tab.rightCssSelected) tab.rightCssSelected = this.rightCssSelected;
        tdR.id = this.id + '_Button_' + i + '_Right';
        YAHOO.util.Event.on(tdR, "click", this.selectTabEvent, i, this);
      }

      // Add empty
      var emptytd = tr.insertCell(-1);
      emptytd.className = this.separatorCss;

      // Store td nodes.
      tab.tdLeft = tdL;
      tab.tdMiddle = tdM;
      tab.tdRight = tdR;

      tab.index = i;

      tab.unselectTab(true); // Activate unselected CSS

    }

    while (placeHolder.firstChild) placeHolder.removeChild(placeHolder.firstChild);
    placeHolder.appendChild(table);
    disableSelection(table);
    this.selectTabByIndex(this.defaultTabIndex, this.runCallbackAtRender, undefined, true);
  };

  this.selectTabEvent = function (e, obj) {
    // obj = index of tab pressed, e = event, this = TabMenu object
    this.selectTabByIndex(obj);
  };

  /**
   * This function is run when a user clicks on a tab. If callback returns false, selectOk will be false and tab switch will be cancelled.
   * @param i The index of the tab that has been clicked.
   * @param doCallback Defines whether we should run the callback or not. When selected default tab at render, this is false.
   * @param forceSelect If true, we ignore callback result and switch tab regardless.
   * @param forceRender Forces the update of tabs CSS classes, regardless of anything else.
   */
  this.selectTabByIndex = function (i, doCallback, forceSelect, forceRender) {
    if (i != this.selectedTabIndex) {
      var indexToUnselect = this.selectedTabIndex;
      if (this.tabList[i]) {
        var selectOk = this.tabList[i].selectTab(doCallback, forceRender);

        if (selectOk || forceSelect) {
          this.selectedTabIndex = i;
          if (indexToUnselect >= 0 && indexToUnselect != this.selectedTabIndex) {
            this.tabList[indexToUnselect].unselectTab();
          }
        } else {
          ibelog('Tab selection was cancelled by callback');
        }
      } else {
        ibewarning('Trying to select tab which doesn\'t exist, index=' + i);
      }
    } else {
      ibelog('Trying to select tab that is already selected');
    }
  };

  this.selectTabById = function (id, doCallback, forceRender) {
    var i = this.getTabIndexById(id);
    if (i != null) {
      this.selectTabByIndex(i, doCallback, forceRender);
    }
  };

  this.selectTabByTitle = function (title, doCallback, forceRender) {
    var i = this.getTabIndexByTitle(title);
    if (i != null) {
      this.selectTabByIndex(i, doCallback);
    }
  };

  this.clickOnTabWithId = function (id) {
    this.selectTabById(id);
  };

  this.clickOnTabWithTitle = function (title) {
    this.selectTabByTitle(title);
  };
}

