/**
 * @class Ext.toolbar.Paging
 * @extends Ext.toolbar.Toolbar
 * <p>As the amount of records increases, the time required for the browser to render
 * them increases. Paging is used to reduce the amount of data exchanged with the client.
 * Note: if there are more records/rows than can be viewed in the available screen area, vertical
 * scrollbars will be added.</p>
 * <p>Paging is typically handled on the server side (see exception below). The client sends
 * parameters to the server side, which the server needs to interpret and then respond with the
 * appropriate data.</p>
 * <p><b>Ext.toolbar.Paging</b> is a specialized toolbar that is bound to a {@link Ext.data.Store}
 * and provides automatic paging control. This Component {@link Ext.data.Store#load load}s blocks
 * of data into the <tt>{@link #store}</tt> by passing {@link Ext.data.Store#paramNames paramNames} used for
 * paging criteria.</p>
 *
 * {@img Ext.toolbar.Paging/Ext.toolbar.Paging.png Ext.toolbar.Paging component}
 *
 * <p>PagingToolbar is typically used as one of the Grid's toolbars:</p>
 * <pre><code>
 *    var itemsPerPage = 2;   // set the number of items you want per page
 *    
 *    var store = Ext.create('Ext.data.Store', {
 *        id:'simpsonsStore',
 *        autoLoad: false,
 *        fields:['name', 'email', 'phone'],
 *        pageSize: itemsPerPage, // items per page
 *        proxy: {
 *            type: 'ajax',
 *            url: 'pagingstore.js',  // url that will load data with respect to start and limit params
 *            reader: {
 *                type: 'json',
 *                root: 'items',
 *                totalProperty: 'total'
 *            }
 *        }
 *    });
 *    
 *    // specify segment of data you want to load using params
 *    store.load({
 *        params:{
 *            start:0,    
 *            limit: itemsPerPage
 *        }
 *    });
 *    
 *    Ext.create('Ext.grid.Panel', {
 *        title: 'Simpsons',
 *        store: store,
 *        columns: [
 *            {header: 'Name',  dataIndex: 'name'},
 *            {header: 'Email', dataIndex: 'email', flex:1},
 *            {header: 'Phone', dataIndex: 'phone'}
 *        ],
 *        width: 400,
 *        height: 125,
 *        dockedItems: [{
 *            xtype: 'pagingtoolbar',
 *            store: store,   // same store GridPanel is using
 *            dock: 'bottom',
 *            displayInfo: true
 *        }],
 *        renderTo: Ext.getBody()
 *    });
 * </code></pre>
 *
 * <p>To use paging, pass the paging requirements to the server when the store is first loaded.</p>
 * <pre><code>
store.load({
    params: {
        // specify params for the first page load if using paging
        start: 0,          
        limit: myPageSize,
        // other params
        foo:   'bar'
    }
});
 * </code></pre>
 *
 * <p>If using {@link Ext.data.Store#autoLoad store's autoLoad} configuration:</p>
 * <pre><code>
var myStore = new Ext.data.Store({
    {@link Ext.data.Store#autoLoad autoLoad}: {start: 0, limit: 25},
    ...
});
 * </code></pre>
 *
 * <p>The packet sent back from the server would have this form:</p>
 * <pre><code>
{
    "success": true,
    "results": 2000,
    "rows": [ // <b>*Note:</b> this must be an Array
        { "id":  1, "name": "Bill", "occupation": "Gardener" },
        { "id":  2, "name":  "Ben", "occupation": "Horticulturalist" },
        ...
        { "id": 25, "name":  "Sue", "occupation": "Botanist" }
    ]
}
 * </code></pre>
 * <p><u>Paging with Local Data</u></p>
 * <p>Paging can also be accomplished with local data using extensions:</p>
 * <div class="mdetail-params"><ul>
 * <li><a href="http://sencha.com/forum/showthread.php?t=71532">Ext.ux.data.PagingStore</a></li>
 * <li>Paging Memory Proxy (examples/ux/PagingMemoryProxy.js)</li>
 * </ul></div>
 * @constructor Create a new PagingToolbar
 * @param {Object} config The config object
 * @xtype pagingtoolbar
 */

Ext.define('Ext.toolbar.Paging', {
    extend
: 'Ext.toolbar.Toolbar',
   
alias: 'widget.pagingtoolbar',
    alternateClassName
: 'Ext.PagingToolbar',
    requires
: ['Ext.toolbar.TextItem', 'Ext.form.field.Number'],
    /**
     * @cfg {Ext.data.Store} store
     * The {@link Ext.data.Store} the paging toolbar should use as its data source (required).
     */

    /**
     * @cfg {Boolean} displayInfo
     * <tt>true</tt> to display the displayMsg (defaults to <tt>false</tt>)
     */

    displayInfo
: false,
    /**
     * @cfg {Boolean} prependButtons
     * <tt>true</tt> to insert any configured <tt>items</tt> <i>before</i> the paging buttons.
     * Defaults to <tt>false</tt>.
     */

    prependButtons
: false,
    /**
     * @cfg {String} displayMsg
     * The paging status message to display (defaults to <tt>'Displaying {0} - {1} of {2}'</tt>).
     * Note that this string is formatted using the braced numbers <tt>{0}-{2}</tt> as tokens
     * that are replaced by the values for start, end and total respectively. These tokens should
     * be preserved when overriding this string if showing those values is desired.
     */

    displayMsg
: 'Displaying {0} - {1} of {2}',
    /**
     * @cfg {String} emptyMsg
     * The message to display when no records are found (defaults to 'No data to display')
     */

    emptyMsg
: 'No data to display',
    /**
     * @cfg {String} beforePageText
     * The text displayed before the input item (defaults to <tt>'Page'</tt>).
     */

    beforePageText
: 'Page',
    /**
     * @cfg {String} afterPageText
     * Customizable piece of the default paging text (defaults to <tt>'of {0}'</tt>). Note that
     * this string is formatted using <tt>{0}</tt> as a token that is replaced by the number of
     * total pages. This token should be preserved when overriding this string if showing the
     * total page count is desired.
     */

    afterPageText
: 'of {0}',
    /**
     * @cfg {String} firstText
     * The quicktip text displayed for the first page button (defaults to <tt>'First Page'</tt>).
     * <b>Note</b>: quick tips must be initialized for the quicktip to show.
     */

    firstText
: 'First Page',
    /**
     * @cfg {String} prevText
     * The quicktip text displayed for the previous page button (defaults to <tt>'Previous Page'</tt>).
     * <b>Note</b>: quick tips must be initialized for the quicktip to show.
     */

    prevText
: 'Previous Page',
    /**
     * @cfg {String} nextText
     * The quicktip text displayed for the next page button (defaults to <tt>'Next Page'</tt>).
     * <b>Note</b>: quick tips must be initialized for the quicktip to show.
     */

    nextText
: 'Next Page',
    /**
     * @cfg {String} lastText
     * The quicktip text displayed for the last page button (defaults to <tt>'Last Page'</tt>).
     * <b>Note</b>: quick tips must be initialized for the quicktip to show.
     */

    lastText
: 'Last Page',
    /**
     * @cfg {String} refreshText
     * The quicktip text displayed for the Refresh button (defaults to <tt>'Refresh'</tt>).
     * <b>Note</b>: quick tips must be initialized for the quicktip to show.
     */

    refreshText
: 'Refresh',
    /**
     * @cfg {Number} inputItemWidth
     * The width in pixels of the input field used to display and change the current page number (defaults to 30).
     */

    inputItemWidth
: 30,
   
    /**
     * Gets the standard paging items in the toolbar
     * @private
     */

    getPagingItems
: function() {
       
var me = this;
       
       
return [{
            itemId
: 'first',
            tooltip
: me.firstText,
            overflowText
: me.firstText,
            iconCls
: Ext.baseCSSPrefix + 'tbar-page-first',
            disabled
: true,
            handler
: me.moveFirst,
            scope
: me
       
},{
            itemId
: 'prev',
            tooltip
: me.prevText,
            overflowText
: me.prevText,
            iconCls
: Ext.baseCSSPrefix + 'tbar-page-prev',
            disabled
: true,
            handler
: me.movePrevious,
            scope
: me
       
},
       
'-',
        me
.beforePageText,
       
{
            xtype
: 'numberfield',
            itemId
: 'inputItem',
            name
: 'inputItem',
            cls
: Ext.baseCSSPrefix + 'tbar-page-number',
            allowDecimals
: false,
            minValue
: 1,
            hideTrigger
: true,
            enableKeyEvents
: true,
            selectOnFocus
: true,
            submitValue
: false,
            width
: me.inputItemWidth,
            margins
: '-1 2 3 2',
            listeners
: {
                scope
: me,
                keydown
: me.onPagingKeyDown,
                blur
: me.onPagingBlur
           
}
       
},{
            xtype
: 'tbtext',
            itemId
: 'afterTextItem',
            text
: Ext.String.format(me.afterPageText, 1)
       
},
       
'-',
       
{
            itemId
: 'next',
            tooltip
: me.nextText,
            overflowText
: me.nextText,
            iconCls
: Ext.baseCSSPrefix + 'tbar-page-next',
            disabled
: true,
            handler
: me.moveNext,
            scope
: me
       
},{
            itemId
: 'last',
            tooltip
: me.lastText,
            overflowText
: me.lastText,
            iconCls
: Ext.baseCSSPrefix + 'tbar-page-last',
            disabled
: true,
            handler
: me.moveLast,
            scope
: me
       
},
       
'-',
       
{
            itemId
: 'refresh',
            tooltip
: me.refreshText,
            overflowText
: me.refreshText,
            iconCls
: Ext.baseCSSPrefix + 'tbar-loading',
            handler
: me.doRefresh,
            scope
: me
       
}];
   
},

    initComponent
: function(){
       
var me = this,
            pagingItems
= me.getPagingItems(),
            userItems  
= me.items || me.buttons || [];
           
       
if (me.prependButtons) {
            me
.items = userItems.concat(pagingItems);
       
} else {
            me
.items = pagingItems.concat(userItems);
       
}
       
delete me.buttons;
       
       
if (me.displayInfo) {
            me
.items.push('->');
            me
.items.push({xtype: 'tbtext', itemId: 'displayItem'});
       
}
       
        me
.callParent();
       
        me
.addEvents(
            /**
             * @event change
             * Fires after the active page has been changed.
             * @param {Ext.toolbar.Paging} this
             * @param {Object} pageData An object that has these properties:<ul>
             * <li><code>total</code> : Number <div class="sub-desc">The total number of records in the dataset as
             * returned by the server</div></li>
             * <li><code>currentPage</code> : Number <div class="sub-desc">The current page number</div></li>
             * <li><code>pageCount</code> : Number <div class="sub-desc">The total number of pages (calculated from
             * the total number of records in the dataset as returned by the server and the current {@link #pageSize})</div></li>
             * <li><code>toRecord</code> : Number <div class="sub-desc">The starting record index for the current page</div></li>
             * <li><code>fromRecord</code> : Number <div class="sub-desc">The ending record index for the current page</div></li>
             * </ul>
             */

           
'change',
            /**
             * @event beforechange
             * Fires just before the active page is changed.
             * Return false to prevent the active page from being changed.
             * @param {Ext.toolbar.Paging} this
             * @param {Number} page The page number that will be loaded on change
             */

           
'beforechange'
       
);
        me
.on('afterlayout', me.onLoad, me, {single: true});

        me
.bindStore(me.store, true);
   
},
   
// private
    updateInfo
: function(){
       
var me = this,
            displayItem
= me.child('#displayItem'),
            store
= me.store,
            pageData
= me.getPageData(),
            count
, msg;

       
if (displayItem) {
            count
= store.getCount();
           
if (count === 0) {
                msg
= me.emptyMsg;
           
} else {
                msg
= Ext.String.format(
                    me
.displayMsg,
                    pageData
.fromRecord,
                    pageData
.toRecord,
                    pageData
.total
               
);
           
}
            displayItem
.setText(msg);
            me
.doComponentLayout();
       
}
   
},

   
// private
    onLoad
: function(){
       
var me = this,
            pageData
,
            currPage
,
            pageCount
,
            afterText
;
           
       
if (!me.rendered) {
           
return;
       
}

        pageData
= me.getPageData();
        currPage
= pageData.currentPage;
        pageCount
= pageData.pageCount;
        afterText
= Ext.String.format(me.afterPageText, isNaN(pageCount) ? 1 : pageCount);

        me
.child('#afterTextItem').setText(afterText);
        me
.child('#inputItem').setValue(currPage);
        me
.child('#first').setDisabled(currPage === 1);
        me
.child('#prev').setDisabled(currPage === 1);
        me
.child('#next').setDisabled(currPage === pageCount);
        me
.child('#last').setDisabled(currPage === pageCount);
        me
.child('#refresh').enable();
        me
.updateInfo();
        me
.fireEvent('change', me, pageData);
   
},

   
// private
    getPageData
: function(){
       
var store = this.store,
            totalCount
= store.getTotalCount();
           
       
return {
            total
: totalCount,
            currentPage
: store.currentPage,
            pageCount
: Math.ceil(totalCount / store.pageSize),
           
//pageCount :  store.getPageCount(),
            fromRecord
: ((store.currentPage - 1) * store.pageSize) + 1,
            toRecord
: Math.min(store.currentPage * store.pageSize, totalCount)
           
       
};
   
},

   
// private
    onLoadError
: function(){
       
if (!this.rendered) {
           
return;
       
}
       
this.child('#refresh').enable();
   
},

   
// private
    readPageFromInput
: function(pageData){
       
var v = this.child('#inputItem').getValue(),
            pageNum
= parseInt(v, 10);
           
       
if (!v || isNaN(pageNum)) {
           
this.child('#inputItem').setValue(pageData.currentPage);
           
return false;
       
}
       
return pageNum;
   
},

    onPagingFocus
: function(){
       
this.child('#inputItem').select();
   
},

   
//private
    onPagingBlur
: function(e){
       
var curPage = this.getPageData().currentPage;
       
this.child('#inputItem').setValue(curPage);
   
},

   
// private
    onPagingKeyDown
: function(field, e){
       
var k = e.getKey(),
            pageData
= this.getPageData(),
            increment
= e.shiftKey ? 10 : 1,
            pageNum
,
            me
= this;

       
if (k == e.RETURN) {
            e
.stopEvent();
            pageNum
= me.readPageFromInput(pageData);
           
if (pageNum !== false) {
                pageNum
= Math.min(Math.max(1, pageNum), pageData.total);
               
if(me.fireEvent('beforechange', me, pageNum) !== false){
                    me
.store.loadPage(pageNum);
               
}
           
}
       
} else if (k == e.HOME || k == e.END) {
            e
.stopEvent();
            pageNum
= k == e.HOME ? 1 : pageData.pageCount;
            field
.setValue(pageNum);
       
} else if (k == e.UP || k == e.PAGEUP || k == e.DOWN || k == e.PAGEDOWN) {
            e
.stopEvent();
            pageNum
= me.readPageFromInput(pageData);
           
if (pageNum) {
               
if (k == e.DOWN || k == e.PAGEDOWN) {
                    increment
*= -1;
               
}
                pageNum
+= increment;
               
if (pageNum >= 1 && pageNum <= pageData.pages) {
                    field
.setValue(pageNum);
               
}
           
}
       
}
   
},

   
// private
    beforeLoad
: function(){
       
if(this.rendered && this.refresh){
           
this.refresh.disable();
       
}
   
},

   
// private
    doLoad
: function(start){
       
if(this.fireEvent('beforechange', this, o) !== false){
           
this.store.load();
       
}
   
},

    /**
     * Move to the first page, has the same effect as clicking the 'first' button.
     */

    moveFirst
: function(){
       
var me = this;
       
if(me.fireEvent('beforechange', me, 1) !== false){
            me
.store.loadPage(1);
       
}
   
},

    /**
     * Move to the previous page, has the same effect as clicking the 'previous' button.
     */

    movePrevious
: function(){
       
var me = this,
            prev
= me.store.currentPage - 1;
       
       
if(me.fireEvent('beforechange', me, prev) !== false){
            me
.store.previousPage();
       
}
   
},

    /**
     * Move to the next page, has the same effect as clicking the 'next' button.
     */

    moveNext
: function(){
       
var me = this;        
       
if(me.fireEvent('beforechange', me, me.store.currentPage + 1) !== false){
            me
.store.nextPage();
       
}
   
},

    /**
     * Move to the last page, has the same effect as clicking the 'last' button.
     */

    moveLast
: function(){
       
var me = this,
           
last = this.getPageData().pageCount;
       
       
if(me.fireEvent('beforechange', me, last) !== false){
            me
.store.loadPage(last);
       
}
   
},

    /**
     * Refresh the current page, has the same effect as clicking the 'refresh' button.
     */

    doRefresh
: function(){
       
var me = this,
            current
= me.store.currentPage;
       
       
if(me.fireEvent('beforechange', me, current) !== false){
            me
.store.loadPage(current);
       
}
   
},

    /**
     * Binds the paging toolbar to the specified {@link Ext.data.Store}
     * @param {Store} store The store to bind to this toolbar
     * @param {Boolean} initial (Optional) true to not remove listeners
     */

    bindStore
: function(store, initial){
       
var me = this;
       
       
if (!initial && me.store) {
           
if(store !== me.store && me.store.autoDestroy){
                me
.store.destroy();
           
}else{
                me
.store.un('beforeload', me.beforeLoad, me);
                me
.store.un('load', me.onLoad, me);
                me
.store.un('exception', me.onLoadError, me);
           
}
           
if(!store){
                me
.store = null;
           
}
       
}
       
if (store) {
            store
= Ext.data.StoreManager.lookup(store);
            store
.on({
                scope
: me,
                beforeload
: me.beforeLoad,
                load
: me.onLoad,
                exception
: me.onLoadError
           
});
       
}
        me
.store = store;
   
},

    /**
     * Unbinds the paging toolbar from the specified {@link Ext.data.Store} <b>(deprecated)</b>
     * @param {Ext.data.Store} store The data store to unbind
     */

    unbind
: function(store){
       
this.bindStore(null);
   
},

    /**
     * Binds the paging toolbar to the specified {@link Ext.data.Store} <b>(deprecated)</b>
     * @param {Ext.data.Store} store The data store to bind
     */

    bind
: function(store){
       
this.bindStore(store);
   
},

   
// private
    onDestroy
: function(){
       
this.bindStore(null);
       
this.callParent();
   
}
});