var stubRenderer = function (records) {
    alert('render function is not defined');
    return "";
}

// define $RENDERER function on page to use it instead of default
if (!$RENDERER)
    var $RENDERER = stubRenderer;

if (!$BEFORE_LOAD_LISTENER)
    var $BEFORE_LOAD_LISTENER = function() {};

if (!$ACTION_URL){
    var $ACTION_URL = "";
    alert('No $ACTION_URL specified')
}

if (!$DATA_FIELDS){
    var $DATA_FIELDS;// example var $DATA_FIELDS = ['name', 'descr', 'author', 'title', 'imgSrc'],
    alert('no fields defined for JSONStore');
}

if (!$REQUST_PARAMS)
    var $REQUST_PARAMS = {}
//define also $PAGEBAR_ID, $ELEMENTS_PER_PAGE

Ext.onReady(function() {
    // create connectio, proxy, dataStore
    var connection = new Ext.data.Connection({
        url: $ACTION_URL,
        extraParams: $REQUST_PARAMS
    });

    var httpProxy = new Ext.data.HttpProxy(connection);
/*
    httpProxy.addListener("loadexception", function() {
        alert('ProxData load error')
    });
*/


    var store = new Ext.data.JsonStore({
        root: 'thumbs',
        totalProperty: 'totalCount',
        idProperty: 'descr',
        remoteSort: true,

        fields: $DATA_FIELDS,
        proxy: httpProxy
    });

    store.addListener("loadexception", function() {
        alert('Ошибка при загрузке страницы');
    });


    // (re)render table on data load
    store.addListener("load",
            function(store, records, options) {
                $RENDERER(records);
            });

    store.addListener("beforeload", $BEFORE_LOAD_LISTENER);


    Paging = new Paging($PAGEBAR_ID, store, {
        elementsPerPage:$ELEMENTS_PER_PAGE,
        pagesTotal:$PAGES_TOTAL,
        maxLinks: 5,
        clsASelected: 'selected',
        clsTable: 'paging-table',
        titlePrev: '<span class="arr">&larr;</span> Предыдущая',
        titleNext: 'Следующая <span class="arr">&rarr;</span>'
    });

    // trigger the data store load
    //store.load({params:{start:0, limit: $ELEMENTS_PER_PAGE}});
});


/** @private **/
var Paging = function(containerId, extJsStore, config) {
    if (!config) config = {};
    this.store = extJsStore;
    this.rangeLength = config.maxLinks ? config.maxLinks : 5;
    this.activePage = this.rangeStart = 1;
    this.elementsPerPage = config.elementsPerPage;

    this.clsASelected = config.clsASelected ? config.clsASelected :'selected';
    this.store.on("load", this.onLoad, this);

    this.pagesTotal = config.pagesTotal;
    // takes apresent paging and attaches itself on top to make ajax paging
    this.attachToPagebar();
}

/** @private **/
Paging.prototype.attachToPagebar = function() {
    if(document.getElementById("paging.table") == null)
        return;

    this.pageAchors = [];
    for (var i = 0; i < 100; i++) {
        var page = document.getElementById("paging.p_" + i);
        if (page) {
            page = page.firstChild;
            page.context = this;
            page.onclick = this.onLinkClick;
            this.pageAchors.push(page);

        } else
            break;
    }

    // attach handlers
    this.pr = document.getElementById("paging.pr").firstChild;
    this.nr = document.getElementById("paging.nr").firstChild;
    this.pr.context = this.nr.context = this;
    this.pr.onclick = this.nr.onclick = this.onLinkClick;

    this.ppCell = document.getElementById("paging.pp");
    var prevP = this.ppCell.firstChild;
    if(prevP.nodeName.toLowerCase() == "a"){
        prevP.context = this;
        prevP.onclick = this.onLinkClick;
    }

    this.npCell = document.getElementById("paging.np");
    var nextP = this.npCell.firstChild;
    if(nextP.nodeName.toLowerCase() == "a"){
        nextP.context = this;
        nextP.onclick = this.onLinkClick;
    }
    this.createShortcuts(prevP, nextP);
}

/** @private
 * refreshes '...' links
* **/
Paging.prototype.refreshRangeLinks = function() {

    var visible = this.rangeStart > 1;
    this.refreshPageAnchor(this.pr, null,this.rangeStart-1, visible, '');

    var end = this.rangeStart + this.pageAchors.length;
    visible = end <= this.pagesTotal
    this.refreshPageAnchor(this.nr,null, end, visible, '');

}

/** @private **/
Paging.prototype.refreshPrevNextLinks = function() {
    // enable prev link
    var anchor = this.ppCell.firstChild;
    var prevA = null;
    if(this.activePage > 1){
        if(anchor.nodeName.toLowerCase() != "a"){
            // wrap innerHTML with <A> tag
            var a = this.pageAchors[0].cloneNode(true);
            a.innerHTML = this.ppCell.innerHTML;
            anchor = a;
            this.ppCell.innerHTML = "";
            this.ppCell.appendChild(anchor);


        }
        this.refreshPageAnchor(anchor,null,this.activePage-1,true,'');
        prevA = anchor;

    } else if (anchor.nodeName.toLowerCase() == "a")
            this.ppCell.innerHTML = anchor.innerHTML;

    // enable next link

    anchor = this.npCell.firstChild;
    var nextA = null;
    if(this.activePage < this.pagesTotal){
        if(anchor.nodeName.toLowerCase() != "a"){
            // wrap innerHTML with <A> tag
            a = this.pageAchors[0].cloneNode(true);
            a.innerHTML = this.npCell.innerHTML;
            anchor = a;
            this.npCell.innerHTML = "";
            this.npCell.appendChild(anchor);
        }
        this.refreshPageAnchor(anchor,null,this.activePage+1,true,'');
        nextA = anchor;
    } else if (anchor.nodeName.toLowerCase() == "a")
            this.npCell.innerHTML = anchor.innerHTML;


    this.createShortcuts(prevA, nextA);
};

Paging.prototype.createShortcuts = function(prevAnchor, nextAnchor) {
    function navigate(a) {
        if (!a || !a.href) return;
        //document.location = a.href;
        a.onclick();
    }
    var PREV = "Ctrl+left";
    var NEXT = "Ctrl+right";
    // Externaly defined in shortcut.js
    if(!shortcut) return;
    shortcut.remove(PREV);
    shortcut.add(PREV, function() {navigate(prevAnchor);});
    shortcut.remove(NEXT);
    shortcut.add(NEXT, function() {navigate(nextAnchor);});
}

/** @private **/
Paging.prototype.onLinkClick = function() {
    var page = this.page;
    if (!page)
        page = this.context.extractPageNumberFromHref(this.href, "p");
    this.context.switchPage(page);
    return false;
}

/** @private **/
Paging.prototype.refreshPaging = function() {
    this.refreshRangeLinks();
    this.refreshPrevNextLinks();

    //var cells = this.container.firstChild.rows[0].cells;
    // rerender page numbers ....1 2 3...
    for (var ci = 0; ci < this.pageAchors.length; ci++) {
        var pn = this.rangeStart + ci;
        if (pn <= this.pagesTotal) {
            var cssClass = (pn == this.activePage) ? this.clsASelected : '';
            this.refreshPageAnchor(this.pageAchors[ci], pn, pn, true, cssClass);
        }
    }
}

/** @private **/
Paging.prototype.refreshPageAnchor = function(anchor, innerHTML, pageNumber, visible, cssClass) {

    var currentPage = this.extractPageNumberFromHref(anchor.href,"p");
    anchor.href = anchor.href.replace("p="+currentPage, "p="+pageNumber);
    if(innerHTML !=null)
        anchor.innerHTML = innerHTML;
    anchor.page = pageNumber;
    anchor.style.display= visible?"":"none";
    if(cssClass!=null)
        anchor.className = cssClass;

    anchor.context = this;
    anchor.onclick = this.onLinkClick;
}

/** @private **/
Paging.prototype.extractPageNumberFromHref = function(href, pageNumberParamName) {
    var params = href.split("?")[1];
    params = params.split("&");
    for (var i = 0; i < params.length; i++)
        if (params[i].indexOf(pageNumberParamName+"=") == 0) {
            return params[i].split("=")[1];
        }
    return -1;
}



/** @private **/
Paging.prototype.onLoad = function(store, r, o) {

    this.elTotal = store.getTotalCount();
    this.pagesTotal = this.elTotal < this.elementsPerPage ? 1 : Math.ceil(this.elTotal / this.elementsPerPage);

    this.activePage = parseInt(o.params ? o.params['p'] : 1);

    //this.renderAll();
    this.refreshPaging();
}


Paging.prototype.switchPage = function(pageNum) {
    if(pageNum >= this.rangeStart + this.pageAchors.length){
        this.shiftRange(1);
    }else if(pageNum < this.rangeStart)
        this.shiftRange(-1);

    var o = {};
    //o['start'] = (pageNum - 1) * this.elementsPerPage;
    //o['limit'] = this.elementsPerPage;
    o['p'] = pageNum;
    //if(this.fireEvent('beforechange', this, o) !== false){
    this.store.load({params:o});
    return false;
}

/** @private
* changes ranage
* i.e. 1 2 3 4  -> 5 6 7 8
* **/
Paging.prototype.shiftRange = function(dir) {
    if (dir > 0) {
        this.rangeStart += this.pageAchors.length;
        this.activePage = this.rangeStart;

        var end = this.rangeStart + this.pageAchors.length;
        if (end > this.pagesTotal) {
            this.rangeStart -= (end - this.pagesTotal - 1);
        }
    } else if (dir < 0) {
        this.rangeStart -= this.pageAchors.length;
        if(this.rangeStart < 1)
            this.rangeStart = 1;

        this.activePage = this.rangeStart;
    }
 }