/*globals AZCAT,YAHOO */

AZCAT.search = function () {
  // Shared private functions
  function _showLoader() {
    var loader = document.getElementById(this._loaderEl);
    if (loader) {
      YAHOO.util.Dom.setStyle(loader, "display", "block");
    }
  }

  function _hideLoader() {
    var loader = document.getElementById(this._loaderEl);
    if (loader) {
      YAHOO.util.Dom.setStyle(loader, "display", "none");
    }
  }

  function _showResultsEl() {
    var resultsField = document.getElementById(this._resultsField);
    YAHOO.util.Dom.setStyle(resultsField, "visibility", "visible");
  }

  function _hideResultsEl() {
    var resultsField = document.getElementById(this._resultsField);
    YAHOO.util.Dom.setStyle(resultsField, "visibility", "hidden");
  }

  function _getForm() {
    return document.getElementById(this._searchForm);
  }

  function _updateFromServerCallback(o) {
    var fadeIn;
    this._hideLoader();
    if (this._fadeOut.isAnimated) {
      this._fadeOut.stop();
    }
    this._showResultsEl();
    var resultsField = document.getElementById(this._resultsField);
    this.dataReturnEvent.fire({"results" : o, "el" : resultsField, "formEl" : this._searchForm});
    fadeIn = new YAHOO.util.Anim(this._resultsField, {opacity: {to: 1}}, 0.3);
    fadeIn.animate();
  }

  function _updateFromServer() {
    var query, x;
    this._fadeOut = new YAHOO.util.Anim(this._resultsField, {opacity: {to: 0}}, 0.3);
    this._showLoader();
    this._fadeOut.onComplete.subscribe(this._hideResultsEl, this, true);
    this._fadeOut.animate();
    YAHOO.util.Connect.setForm(this._getForm());
    query = "page:int=" + this.getCurrentPage();
    if (!this._rowsPerPageInForm) {
      query += "&" + this._rowsPerPageName + ":int=" + this.getRowsPerPage();
    }
    for (x in this._submitVars) {
      if (this._submitVars.hasOwnProperty(x)) {
        query += ("&" + x + "=" + this._submitVars[x]);
      }
    }
    YAHOO.util.Connect._sFormData += ("&" + query);
    YAHOO.util.Connect.asyncRequest("POST", this._requestURL, {success : this._updateFromServerCallback, scope : this});
    YAHOO.util.Connect.resetFormState();
  }

  // Shared public functions
  function getCurrentPage() {
    return this._currentPage;
  }

  function setCurrentPage(page, fireChange) {
    var pag;
    this._currentPage = page;
    pag = this.getPaginator();
    if (pag) {
      pag.setPage(page, !fireChange);
    }
  }

  function submitSearch(e) {
    var el = YAHOO.util.Event.getTarget(e);
    if (el.type.toLowerCase() === "submit") {
      YAHOO.util.Event.stopEvent(e);
    }
    this.setCurrentPage(1);
    this.beforeSearchEvent.fire({"el" : el, "formEl" : this._searchForm});
    this._updateFromServer();
  }

  function resetSearch() {
    var searchField;
    if (!this._searchField) {
      return;
    }
    searchField = document.getElementById(this._searchField);
    if (searchField) {
      searchField.value = "";
      this.setCurrentPage(1);
      this._updateFromServer();
    } else {
      throw {"name" : "Unknown Element",
             "message" : "Unable to find field " + this._searchField};
    }
  }

  function searchFieldEnter(e) {
    if ((e.keyCode ? e.keyCode : e.which) === 13) {
      YAHOO.util.Event.stopEvent(e);
      this.setCurrentPage(1);
      this._updateFromServer();
    }
  }

  function getPaginator() {
    return this._paginator;
  }

  function setPaginator(pag) {
    this._paginator = pag;
  }

  function showPaginator() {
    var els, x, xlen;
    els = this._paginator.getContainerNodes();
    for (x = 0, xLen = els.length; x < xLen; x += 1) {
      YAHOO.util.Dom.setStyle(els[x], "visibility", "visible");
    }
  }

  function hidePaginator() {
    var els, x, xlen;
    els = this._paginator.getContainerNodes();
    for (x = 0, xLen = els.length; x < xLen; x += 1) {
      YAHOO.util.Dom.setStyle(els[x], "visibility", "hidden");
    }
  }

  function getTotalRecords() {
    return this._totalRecords;
  }

  function setTotalRecords(num, fireChange) {
    var pag;
    this._totalRecords = num;
    pag = this.getPaginator();
    if (pag) {
        pag.set('totalRecords', num);
      if (num === 0) {
        this.hidePaginator();
      } else {
        this.showPaginator();
      }
      if (fireChange) {
        pag.setTotalRecords(num);
      }
    }
  }

  function getRowsPerPage() {
    return this._rowsPerPage;
  }

  function setRowsPerPage(num, fireChange) {
    var pag;
    this._rowsPerPage = num;
    pag = this.getPaginator();
    if (pag) {
      pag.set('rowsPerPage', num);
      if (fireChange) {
        pag.setRowsPerPage(num);
      }
    }
  }

  function handlePagination(newState) {
    var pag;
    this.setCurrentPage(newState.page);
    this._updateFromServer();
    pag = this.getPaginator();
    pag.setState(newState);
  }

  return function (config) {
    // My resources, this instance
    // Private varables, actual
    var pagConfig, paginator, configItem, el, x, xLen, eventType,
        that = {//Private varables, by convention not actually hidden
      _currentPage : 1,
      _rowsPerPage : config.rowsPerPage,
      _rowsPerPageName : config.rowsPerPageName ? config.rowsPerPageName : "rows_per_page",
      _rowsPerPageInForm : config.rowsPerPageInForm ? config.rowsPerPageInForm : false,
      _totalRecords : config.totalRecords ? config.totalRecords : 0,
      _loaderEl: config.loader,
      _requestURL : config.requestURL,
      _submitVars : config.submitVars ? config.submitVars : {},
      _searchForm : config.searchForm,
      _searchField : config.searchField,
      _submitFields : config.submitFields,
      _resetFields : config.resetFields,
      _resultsField : config.resultsField,
      _paginator : null,
      _fadeOut : null,

      //Private Methods
      _showLoader : _showLoader,
      _hideLoader : _hideLoader,
      _showResultsEl : _showResultsEl,
      _hideResultsEl : _hideResultsEl,
      _getForm : _getForm,
      _updateFromServer : _updateFromServer,
      _updateFromServerCallback : _updateFromServerCallback,

      // Public methods
      getCurrentPage : getCurrentPage,
      setCurrentPage : setCurrentPage,
      submitSearch : submitSearch,
      resetSearch : resetSearch,
      searchFieldEnter : searchFieldEnter,
      getPaginator : getPaginator,
      setPaginator : setPaginator,
      showPaginator : showPaginator,
      hidePaginator : hidePaginator,
      getTotalRecords : getTotalRecords,
      setTotalRecords : setTotalRecords,
      getRowsPerPage : getRowsPerPage,
      setRowsPerPage : setRowsPerPage,
      handlePagination : handlePagination,

      // Public Variables

      // Public Events
      dataReturnEvent : new YAHOO.util.CustomEvent("dataReturnEvent", this),
      beforeSearchEvent : new YAHOO.util.CustomEvent("beforeSearchEvent", this)
    };

    // Init

    // Setup Paginator
    if (config.paginatorEls && config.paginatorEls.length) {
      pagConfig = {containers : config.paginatorEls,
                   rowsPerPage : config.rowsPerPage,
                   totalRecords : config.totalRecords};
      if (config.paginatorTemplate) {
        pagConfig.template = config.paginatorTemplate;
      }
      paginator = new YAHOO.widget.Paginator(pagConfig);
      that.setPaginator(paginator);
      if (config.pagConfig) {
        for (configItem in config.pagConfig) {
          if (config.pagConfig.hasOwnProperty(configItem)) {
            paginator.setAttributeConfig(configItem, {value : config.pagConfig[configItem]});
          }
        }
      }
      paginator.subscribe('changeRequest', handlePagination, that, true);
      paginator.render();
      if (that._totalRecords === 0) {
        that.hidePaginator();
      }
    }
    // Setup Search Field
    if (that._searchField) {
      el = document.getElementById(that._searchField);
      if (el) {
        YAHOO.util.Event.on(el, "keydown", that.searchFieldEnter, that, true);
      }
    }
    // Setup Submit Fields
    if (that._submitFields) {
      if (!YAHOO.lang.isArray(that._submitFields)) {
        that._submitFields = [that._submitFields];
      }
      for (x = 0, xLen = that._submitFields.length; x < xLen; x += 1) {
        if (YAHOO.lang.isString(that._submitFields[x])) {
          el = document.getElementById(that._submitFields[x]);
        } else {
          el = that._submitFields[x];
        }
        if (!el) {
          continue;
        }
        switch (el.tagName.toLowerCase()) {
          case "select":
            eventType = "change";
            break;

          case "input":
            switch (el.type.toLowerCase()) {
              case "submit":
              case "radio":
              case "checkbox":
                eventType = "click";
                break;

            }
            break;
        }
        if (!eventType) {
          throw {"name" : "Unknown Event For Element",
                 "message" : "Unable to determine what type of event to subscribe to field " + that._submitFields[x]};
        }
        YAHOO.util.Event.on(el, eventType, that.submitSearch, that, true);
      }
    }
    // Setup Reset Fields
    if (that._resetFields) {
      if (!YAHOO.lang.isArray(that._resetFields)) {
        that._resetFields = [that._resetFields];
      }
      for (x = 0, xLen = that._resetFields.length; x < xLen; x += 1) {
        if (YAHOO.lang.isString(that._resetFields[x])) {
          el = document.getElementById(that._resetFields[x]);
        } else {
          el = that._resetFields[x];
        }
        YAHOO.util.Event.on(el, "click", that.resetSearch, that, true);
      }
    }

    return that;
  };
}();





(function () {

var Paginator = YAHOO.widget.Paginator,
    l         = YAHOO.lang;


/**
 * ui Component to generate the page links
 *
 * @namespace YAHOO.widget.Paginator.ui
 * @class PageLinks
 * @for YAHOO.widget.Paginator
 *
 * @constructor
 * @param p {Pagintor} Paginator instance to attach to
 */
Paginator.ui.PageLinksSeparated = function (p) {
    this.paginator = p;

    p.subscribe('recordOffsetChange',this.update,this,true);
    p.subscribe('rowsPerPageChange',this.update,this,true);
    p.subscribe('totalRecordsChange',this.update,this,true);
    p.subscribe('pageLinksChange',   this.rebuild,this,true);
    p.subscribe('pageLinkClassChange', this.rebuild,this,true);
    p.subscribe('currentPageClassChange', this.rebuild,this,true);
    p.subscribe('destroy',this.destroy,this,true);

    //TODO: Make this work
    p.subscribe('pageLinksContainerClassChange', this.rebuild,this,true);
};

/**
 * Decorates Paginator instances with new attributes. Called during
 * Paginator instantiation.
 * @method init
 * @param p {Paginator} Paginator instance to decorate
 * @static
 */
Paginator.ui.PageLinksSeparated.init = function (p) {

    /**
     * Separator.
     * @attribute pageSeparator
     * @default ' | '
     */
    p.setAttributeConfig('pageSeparator', {
        value : ' | ',
        validator : l.isString
    });

    /**
     * CSS class assigned to each page link/span.
     * @attribute pageLinkClass
     * @default 'yui-pg-page'
     */
    p.setAttributeConfig('pageLinkClass', {
        value : 'yui-pg-page',
        validator : l.isString
    });

    /**
     * CSS class assigned to the current page span.
     * @attribute currentPageClass
     * @default 'yui-pg-current-page'
     */
    p.setAttributeConfig('currentPageClass', {
        value : 'yui-pg-current-page',
        validator : l.isString
    });

    /**
     * CSS class assigned to the span containing the page links.
     * @attribute pageLinksContainerClass
     * @default 'yui-pg-pages'
     */
    p.setAttributeConfig('pageLinksContainerClass', {
        value : 'yui-pg-pages',
        validator : l.isString
    });

    /**
     * Maximum number of page links to display at one time.
     * @attribute pageLinks
     * @default 10
     */
    p.setAttributeConfig('pageLinks', {
        value : 10,
        validator : Paginator.isNumeric
    });

    /**
     * Function used generate the innerHTML for each page link/span.  The
     * function receives as parameters the page number and a reference to the
     * paginator object.
     * @attribute pageLabelBuilder
     * @default function (page, paginator) { return page; }
     */
    p.setAttributeConfig('pageLabelBuilder', {
        value : function (page, paginator) { return page; },
        validator : l.isFunction
    });
};

/**
 * Calculates start and end page numbers given a current page, attempting
 * to keep the current page in the middle
 * @static
 * @method calculateRange
 * @param {int} currentPage  The current page
 * @param {int} totalPages   (optional) Maximum number of pages
 * @param {int} numPages     (optional) Preferred number of pages in range
 * @return {Array} [start_page_number, end_page_number]
 */
Paginator.ui.PageLinksSeparated.calculateRange = function (currentPage,totalPages,numPages) {
    var UNLIMITED = Paginator.VALUE_UNLIMITED,
        start, end, delta;

    // Either has no pages, or unlimited pages.  Show none.
    if (!currentPage || numPages === 0 || totalPages === 0 ||
        (totalPages === UNLIMITED && numPages === UNLIMITED)) {
        return [0,-1];
    }

    // Limit requested pageLinks if there are fewer totalPages
    if (totalPages !== UNLIMITED) {
        numPages = numPages === UNLIMITED ?
                    totalPages :
                    Math.min(numPages,totalPages);
    }

    // Determine start and end, trying to keep current in the middle
    start = Math.max(1,Math.ceil(currentPage - (numPages/2)));
    if (totalPages === UNLIMITED) {
        end = start + numPages - 1;
    } else {
        end = Math.min(totalPages, start + numPages - 1);
    }

    // Adjust the start index when approaching the last page
    delta = numPages - (end - start + 1);
    start = Math.max(1, start - delta);

    return [start,end];
};


Paginator.ui.PageLinksSeparated.prototype = {

    /**
     * Current page
     * @property current
     * @type number
     * @private
     */
    current     : 0,

    /**
     * Span node containing the page links
     * @property container
     * @type HTMLElement
     * @private
     */
    container   : null,


    /**
     * Generate the nodes and return the container node containing page links
     * appropriate to the current pagination state.
     * @method render
     * @param id_base {string} used to create unique ids for generated nodes
     * @return {HTMLElement}
     */
    render : function (id_base) {
        var p = this.paginator;

        // Set up container
        this.container = document.createElement('span');
        this.container.id        = id_base + '-pages';
        this.container.className = p.get('pageLinksContainerClass');
        YAHOO.util.Event.on(this.container,'click',this.onClick,this,true);

        // Call update, flagging a need to rebuild
        this.update({newValue : null, rebuild : true});

        return this.container;
    },

    /**
     * Update the links if appropriate
     * @method update
     * @param e {CustomEvent} The calling change event
     */
    update : function (e) {
        if (e && e.prevValue === e.newValue) {
            return;
        }

        var p           = this.paginator,
            currentPage = p.getCurrentPage();

        // Replace content if there's been a change
        if (this.current !== currentPage || !currentPage || e.rebuild) {
            var labelBuilder = p.get('pageLabelBuilder'),
                range        = Paginator.ui.PageLinks.calculateRange(
                                currentPage,
                                p.getTotalPages(),
                                p.get('pageLinks')),
                start        = range[0],
                end          = range[1],
                content      = '',
                pageSeparator = p.get('pageSeparator'),
                linkTemplate,i;

            linkTemplate = '<a href="#" class="' + p.get('pageLinkClass') +
                           '" page="';
            for (i = start; i <= end; ++i) {
                if (i === currentPage) {
                    content +=
                        '<span class="' + p.get('currentPageClass') + ' ' +
                                          p.get('pageLinkClass') + '">' +
                        labelBuilder(i,p) + '</span>';
                } else {
                    content +=
                        linkTemplate + i + '">' + labelBuilder(i,p) + '</a>';
                }
                if (i !== end) {
                    content += pageSeparator;
                }
            }

            this.container.innerHTML = content;
        }
    },

    /**
     * Force a rebuild of the page links.
     * @method rebuild
     * @param e {CustomEvent} The calling change event
     */
    rebuild     : function (e) {
        e.rebuild = true;
        this.update(e);
    },

    /**
     * Removes the page links container node and clears event listeners
     * @method destroy
     * @private
     */
    destroy : function () {
        YAHOO.util.Event.purgeElement(this.container,true);
        this.container.parentNode.removeChild(this.container);
        this.container = null;
    },

    /**
     * Listener for the container's onclick event.  Looks for qualifying link
     * clicks, and pulls the page number from the link's page attribute.
     * Sends link's page attribute to the Paginator's setPage method.
     * @method onClick
     * @param e {DOMEvent} The click event
     */
    onClick : function (e) {
        var t = YAHOO.util.Event.getTarget(e);
        if (t && YAHOO.util.Dom.hasClass(t,
                        this.paginator.get('pageLinkClass'))) {

            YAHOO.util.Event.stopEvent(e);

            this.paginator.setPage(parseInt(t.getAttribute('page'),10));
        }
    }

};

})();
