/**
 * jquery.rowRepeater.js 
 * 
 * v2.0.2
 * callback support is added
 * 
 * v2.0.1
 * @author Yasar Bayar <yasar@navigatormm.com>
 */
(function ($) {
    $.fn.rowRepeater = function (options, callback) {
        options = $.extend({}, {
            data                : [],
            url                 : '',
            per_page            : 5,
            initial_page        : 1,
            enable_pagination   : true,
            template            : {
                layout          : '',
                row             : ''
            },
            beforeShow    : null

        }, options);

        var 
        self = this,
        rows = null,
        vars = {
            total_records       : null,
            total_pages         : null,
            page                : null
        },
        $OBJ = {
            Holder: null,
            Listing: null
        },
        Load = {
            PageData: function (start, limit, callback) {
                $.getJSON(options.url, {action: 'listing', start: start, limit: limit}, function (AR) {
                    if (AR.success) {
                        for (var i = start, j = 0; j < limit; i++, j++) {
                            rows[i] = AR.data[j];
                        }

                        if (typeof callback === 'function') {
                            callback();
                        }
                    }
                });
            },

            SummaryData: function (callback) {
                $.getJSON(options.url, {action: 'total_records'}, function (AR) {
                    if (AR.success) {
                        vars.total_records = AR.data;
                        vars.total_pages = Math.ceil(AR.data / options.per_page);

                        if (vars.page > vars.total_pages) {
                            vars.page = vars.total_pages;
                        }

                        if (typeof callback === 'function') {
                            callback();
                        }
                    }
                });
            }
        },
        Get = {
            PageData: function (page_nr, callback) {
                var
                data_arr = [], 
                i, j,
                
                /**
                 * find the starting record number
                 */
                idx = (page_nr - 1) * options.per_page,

                /**
                 * the last page may have less records than what required
                 * so make sure that we only evaluate the whatever available records for the last page
                 */
                per_page = (vars.page < vars.total_pages) ? options.per_page : vars.total_records - ((vars.total_pages - 1) * options.per_page)

                ;

                /**
                 * if no any data is available in the global data array, then exit
                 * or if requested page data is not loaded in the global data array. then exit
                 */
                if (rows.length === 0 || rows[idx] === undefined) {
                    Load.PageData(idx, per_page, function () {
                        Get.PageData(page_nr, callback);
                    });
                }
                else {
                    for (i = idx, j = 0; j < per_page; i++, j++) {
                        /**
                         * if there is not enought data to load, then break the loop
                         */
                        if (rows[i] === undefined) {
                            break;
                        }
                        
                        data_arr.push(rows[i]);
                    }

                    if (data_arr.length < per_page) {
                        Load.PageData(data_arr.length, options.per_page - data_arr.length, function () {
                            Get.PageData(page_nr, callback);
                        });
                    }
                    else {
                        if (typeof callback === 'function') {
                            callback(data_arr);
                        }
                    }
                }
            },
            Listing: function (data, tpl) {
                var html = '', tmp, field;
                $(data).each(function (i, rowdata) {
                    if (rowdata === undefined) {
                        return;
                    }

                    tmp = tpl;
                    for (field in rowdata) {
                        if (rowdata.hasOwnProperty(field)) {
                            if (rowdata[field] === null) {
                                rowdata[field] = 'null';
                            }

                            var re = new RegExp('\\$(?:\\{|%7B)' + field + '(?:\\}|%7D)', 'gi');
                            tmp = tmp.replace(re, rowdata[field].toString().replace('$', '$$$'));
                        }
                    }
                    html += tmp;
                });
                return html;
            }
        },

        Parse = {
            Paging: function () {
                var keys = {
                    page_nr: vars.page,
                    total_pages: vars.total_pages
                };
                Parse.Template(keys);
            },
            
            Template: function (keys) {
                for (var key in keys) {
                    if (keys.hasOwnProperty(key)) {
                        $OBJ.Holder.find('.' + key).html(keys[key]);
                    }
                }
            }
        },
        
        Show = {
            Page: function () {
                Get.PageData(vars.page, function (data) {
                    var html=Get.Listing(data, options.template.row);

                    if(typeof(options.beforeShow)=='function')
                        html = options.beforeShow(html);

                    Animate.Fade($OBJ.Listing, html);
                });
            }
        },

        Animate = {
            Fade: function ($el, html) {
                $el.fadeOut(function () {
                    $el.html(html).fadeIn();
                });
            },

            SlideLeft: function ($el, html) {
                $el.animate({
                    left: parseInt($el.css('left'),10) == 0 ? -$el.outerWidth() : 0
                }, function () {
                    if (html !== null) {
                        $el.html(html);
                        //Animate.SlideLeft($el, null);
                    }
                });
            }
        };

        $(this).each(function () {
            $OBJ.Holder = $(this);
            $OBJ.Holder.html(options.template.layout);
            $OBJ.Listing = $OBJ.Holder.find('.listing');

            /**
             * initialize the assignments
             */
            vars.page = options.initial_page;
            rows = options.data;

            /**
             * load the paging summary
             */
            Load.SummaryData(function () {
                /**
                 * parse the paging section
                 */
                Parse.Paging();
                
                /**
                 * show the initial page
                 */
                Show.Page();
            });

            /**
             * assign the click event for next button
             */
            $OBJ.Holder.find('[class^=btn-]').click(function () {
                var page = vars.page;
                
                switch (this.className) 
                {
                case 'btn-next':
                    if (page < vars.total_pages) {
                        vars.page++;
                    }
                    break;
                case 'btn-prev':
                    if (page > 1) {
                        vars.page--;
                    }
                    break;
                }
                
                if (page !== vars.page) {
                    Parse.Paging();
                    Show.Page();
                }
            });
            
            if(typeof(callback)=='function') callback.apply(self);            
        });

    };
})(jQuery);
