﻿//Shivam Technologies
//Author: Sam Critchley
//Ajax Table - jQuery plugin
var listTarget = 'tbody';
jQuery(function() {
    //this code from 3rd party
    jQuery.templateParser =
        {
            _tmplCache: {},
            parseTemplate: function(str, data) {
                var err = "";
                try {
                    var func = this._tmplCache[str];
                    if (!func) {
                        var strFunc =
                        "var p=[],print=function(){p.push.apply(p,arguments);};" +
                                    "with(obj){p.push('" +

                        str.replace(/[\r\t\n]/g, " ")
                           .replace(/'(?=[^#]*#>)/g, "\t")
                           .split("'").join("\\'")
                           .split("\t").join("'")
                           .replace(/<#=(.+?)#>/g, "',$1,'")
                           .split("<#").join("');")
                           .split("#>").join("p.push('")
                           + "');}return p.join('');";

                        func = new Function("obj", strFunc);
                        this._tmplCache[str] = func;
                    }
                    return func(data);
                } catch (e) { return "< # ERROR: " + e.message + " # >"; }
            }
        },

    jQuery.serializeForm = function(form) {
        var formData = form.serializeArray();
        var postData = {};
        jQuery.map(formData, function(n, i) {
            if (postData[n.name]) {
                if (typeof postData[n.name] != 'Array')
                    postData[n.name] = [postData[n.name]];

                postData[n.name][postData[n.name].length] = n.value;
            }
            else
                postData[n.name] = n.value;
        });

        return postData;
    },
    
    jQuery.ajaxTable = {
        defaults: {
            pageTemplateUrl: '/scripts/pagingtemplate.htm',
            hideTableOnload: false,
            runOnLoad: false,
            pageSize: 10,
            maxPages: 10,
            sorterClass: 'sorter',
            sortDirectionDescClass: 'desc',
            sortDirectionAscClass: 'asc',
            sortInfo: null,
            autoHideFooter: true,
            formId: null, //need to specify either a formId or postUrl to get the url to post to (if a formid (this actually a selector) is provided
            postUrl: null, //then it MUST have an action attribute).
            noResultsMsg: '<div class="noresults">No results were found.</div>',
            rowTemplateId: null,
            pagingTarget: 'tfoot td:eq(0)',
            tableRefreshCallback: null,
            defaultSortBy: null,
            defaultSortDirection: false
        },
        sortDirection:
        {
            ascending: false,
            descending: true
        },
        cache:
        {
            pagingTemplateCache: {}
        },
        pageInfo:
        {
            PageSize: null,
            PageIndex: 0,
            TotalItems: null,
            SortBy: null,
            SortDirection: false, //ascending
            isSorting: function() { return this.SortBy != null; }
        }
    };

    jQuery.fn.extend({
        ajaxTable: function(settings) {
            switch (settings) {
                case 'refresh':
                    this.each(
                        function(i, item) { runQuery(pageInfo($(item)).PageIndex, $(item)); }
                    );
                    return this;
            }
            settings = jQuery.extend({}, jQuery.ajaxTable.defaults, settings);
            if (settings.hideTableOnload)
                this.hide();

            if (!jQuery.ajaxTable.cache.pagingTemplateCache[settings.pageTemplateUrl]) {
                jQuery.get(settings.pageTemplateUrl, null, function(data) {
                    jQuery.ajaxTable.cache.pagingTemplateCache[settings.pageTemplateUrl] = data;
                }, 'text');
            }

            //bind events
            if (settings.sortInfo)
                this.find('thead th.' + settings.sorterClass).click(sort);

            return this.each(function(i, item) {
                jQuery.data(item, 'pageInfo', jQuery.extend({}, jQuery.ajaxTable.pageInfo, { SortDirection: settings.defaultSortDirection, PageSize: settings.pageSize, SortBy: settings.defaultSortBy }));
                jQuery.data(item, 'settings', settings);
                if (settings.runOnLoad)
                    runQuery(0, $(item));
            });
        }
    });

    function settings(element) {
        return element.data('settings');
    }

    function pageInfo(element, pi) {
        if (pi == null)
            return element.data('pageInfo');

        element.data('pageInfo', pi);
    }

    function sort(ev) {
        var header = jQuery(ev.target);
        var table = header.parents('table');
        table.find('thead th.' + settings(table).sorterClass)
                                    .removeClass(settings(table).sortDirectionDescClass)
                                    .removeClass(settings(table).sortDirectionAscClass);
        var id = header.attr('id');
        var sortBy = settings(table).sortInfo[id];
        if (!sortBy)
            return; //invalid config

        var pi = pageInfo(table);
        if (pi.isSorting() && pi.SortBy == sortBy) {
            if (pi.SortDirection = !pi.SortDirection)
                header.addClass(settings(table).sortDirectionDescClass);
            else
                header.addClass(settings(table).sortDirectionAscClass);
        }
        pi.SortBy = sortBy;

        runQuery(0, table);
    };

    function runQuery(pageIndex, element) {
        var pi = pageInfo(element);
        pi.PageIndex = pageIndex;

        var formData = jQuery(settings(element).formId).serializeArray();
        var postData = {};
        jQuery.map(formData, function(n, i) {
            postData[n.name] = n.value;
        });

        jQuery.extend(postData, pi);
        var postPath = settings(element).postUrl ? settings(element).postUrl : jQuery(settings(element).formId).attr('action');
        jQuery.post(postPath, postData, jQuery.proxy(parseResults, element), 'json');
    }

    function parseResults(data) {
        var pi = data.PageState;
        var results = data.Data;
        var currentPI = pageInfo(this);
        pageInfo(this, jQuery.extend(currentPI, pi));
        this.show();

        try {
            if (pi.PageIndex != null && pi.PageIndex && !results.length) {
                runQuery(pi.PageIndex - 1, this);
                return;
            }
            else {
                if (!results.length) {
                    displayNoResults(this);
                    return;
                }
            }

            //insert rows
            var rowTemplate = jQuery('#' + settings(this).rowTemplateId).html();
            var rows = [];
            jQuery.each(results, function(i, item) {
                var row = jQuery(jQuery.templateParser.parseTemplate(rowTemplate, item));
                row.data('rowdata', item);
                rows[rows.length] = row;
            });

            //            this.find('tbody').html('');
            //            jQuery.each(rows, jQuery.proxy(function(i, item) {
            //                item.appendTo(this);
            //            }, this.find('tbody')));
            
            
            this.find(listTarget).html('');
            jQuery.each(rows, jQuery.proxy(function(i, item) {
                item.appendTo(this);
            }, this.find(listTarget)));

            //paging
            var pageCount = parseInt(pi.TotalItems / pi.PageSize) + (pi.TotalItems % pi.PageSize > 0 ? 1 : 0);
            if (pageCount > settings(this).maxPages)
                pageCount = settings(this).maxPages;

            var endIndex = (pi.PageSize * pi.PageIndex) + pi.PageSize;

            //if this is the last page then there may not be a full page of items so short it with the actual total items amount
            if (endIndex > pi.TotalItems)
                endIndex = pi.TotalItems;

            var pagerState = {
                pageIndex: pi.PageIndex,
                startIndex: (pi.PageSize * pi.PageIndex) + 1,
                endIndex: endIndex,
                pageCount: pageCount,
                totalCount: pi.TotalItems > (pageCount * pi.PageSize) ? (pageCount * pi.PageSize) : pi.TotalItems
            };

            this.find(settings(this).pagingTarget).html('');

            if (pageCount > 0) {
                var pagingSrc = jQuery.templateParser.parseTemplate(
                jQuery.ajaxTable.cache.pagingTemplateCache[settings(this).pageTemplateUrl], pagerState);
                jQuery(pagingSrc).appendTo(this.find(settings(this).pagingTarget));
                //bind page index links
                this.find(settings(this).pagingTarget).find('ul a').click(
                    jQuery.proxy(function(ev) {
                        var pageIndex = parseInt(jQuery(ev.target).html());
                        pageIndex--;
                        runQuery(pageIndex, this);
                        return false;
                    }, this)
                );

                //bind next/back links
                this.find(settings(this).pagingTarget).find('a.link').click(
                    jQuery.proxy(function(ev) {
                        var pi = pageInfo(this);
                        if (jQuery(ev.target).html().toLowerCase().indexOf('back') > -1)
                            runQuery(pi.PageIndex - 1, this);
                        if (jQuery(ev.target).html().toLowerCase().indexOf('next') > -1)
                            runQuery(pi.PageIndex + 1, this);

                        return false;
                    }, this)
                );
            }
        }
        finally {
            var table = this;
            table.find('col').each(function(i, item) {
                if ($(item).attr('align'))
                    table.find('tbody tr td:nth-child(' + (i + 1) + ')').add(
                        table.find('thead tr th:nth-child(' + (i + 1) + ')')
                    ).css('text-align', $(item).attr('align'));
            });

            if (settings(this).autoHideFooter && results.length) {
                if (pi.TotalItems > pi.PageSize) {
                    table.find('tfoot td:eq(0)').show();
                }
                else {
                    table.find('tfoot td:eq(0)').hide();
                }
            }

            if (settings(this).tableRefreshCallback != null)
                settings(this).tableRefreshCallback({ table: this, results: results, pageInfo: jQuery.extend({}, pi) });
        }
    }

    function displayNoResults(element) {
        element.find('tbody').html('');
        element.find(settings(element).pagingTarget).html(settings(element).noResultsMsg);
    }
});