(function($) {
$.fn.tablepaginateQ = function(options) {

	// default options
	var defaults = {
		search_show: true,
		search_label: 'Filter',
		search_external: null, // external container id to serialize and send as search parm
		search_external_btn: null, // external search button id; to bind to Q search; will try to auto find
		nav_first_btn_label: 'First',
		nav_prev_btn_label: 'Prev',
		nav_next_btn_label: 'Next',
		nav_last_btn_label: 'Last',
		nav_show_rows: [5, 10, 25, 50],
		on_nav_rows_scroll_to_top: true,
		nav_nbr_page_nbrs_shown: 5, // floor #/2
		nav_nbr_page_spacer: '~~',
		css_even_row: 'even_row',
		css_odd_row: 'odd_row',
		simple_table: false, // false|true; true to hide all the Q (nav, search, pagination, ajax)
							 // can pass in as table attr data-simple_table="true"
		sort_cols: ['all'],
		
		id: null,	// unique id; in case multiple tables on page
		target_name: 't_',			
		page: 1,
		offset: 0,
		rows: 5,
		search: '', // if Q search, text; if external, json
		sort_col: 0,
		sort_order: 'asc',
		total: null,
		
		ajax: {
			url: null, // required
			type: 'POST',
			cache: true,
			timeout: 120000, // ms; thus 120s
			data: {
			},
			dataType: 'html'
		},
		
		initial_load: false, // false|true; false if table popuplated on page load; true to do ajax call on page load
		
		'ignore': null
	}; // end defaults
	var opts = {};
	
	
	$(this).each(function(table_nbr) {
		// console.log(table_nbr, this);
		
		defaults.id = 'tablepaginateQ_'+table_nbr;	


		// overlay user options over default options
		opts = $.extend(true, defaults, options);

		opts.ajax_running = false;	
		
		var tpQ_table = $(this);
		
		if (!tpQ_table.is('table')) {
			tpQ_table = tpQ_table.find('table:first');
		}
		if (tpQ_table.length == 0) {
			alert('error: unable to find a table to attach tablepaginateQ');
			return this;
		}
		tpQ_table.addClass('tablepaginateQ');

		if (opts.simple_table || tpQ_table.attr('data-simple_table')) {
			opts.simple_table = tpQ_table.attr('data-simple_table');
			apply_simple_table(tpQ_table);
			// console.log(tpQ_table);
			return this;
		}
		
		parse_data_attributes(tpQ_table);
		
		// wrap the table in a div to keep things clean; check for existing wrapper
		if ($('div#'+opts.id).length == 0) { 
			var tpQ_wrapper = $('<div id="'+opts.id+'" class="tablepaginateQ_wrapper" />');
		} else {
			var tpQ_wrapper = $('div#'+opts.id);
		}
		tpQ_table.wrapAll(tpQ_wrapper);
		tpQ_wrapper = $('div#'+opts.id); // re-get dom		
		//console.log(tpQ_wrapper);
		//calc nbr pages
		calc_nbr_pages();
		
		if (!opts.simple_table) {
			// build table header
			build_table_header();
		}
		
		// build search box and button
		if (opts.simple_table) {
			var search_box = null;
			var search_btn = null;		
		} else if (opts.search_show) {

			var search_box = $('<div id="search_wrap"><input id="search_input" type="text" value="'+opts.search+'" class="tablepaginateQ_search_box"/></div>');
			//var search_btn = $('<button type="button">'+opts.search_label+'</button>');
			var search_btn = $('<img src="/img/search_icon.gif" id="search_button">');
			bind_search(search_btn);

		} else if (opts.search_external != null) {
			if (opts.search_external_btn != null) {
				var search_btn = $(opts.search_external_btn);
				bind_search(search_btn);
			} else {
				// console.log($(opts.search_external).find('input,button'));
				$(opts.search_external).find('input,button').each(function(index) {
					if ($(this).attr('type') == 'submit' || $(this).attr('type') == 'button') {
						var search_btn = $(this);
						bind_search(search_btn);
						return false;
					}
				});
			}			
		} else {
			var search_box = null;
			var search_btn = null;
		}
			
		
		// build navigation buttons
		var nav_first_btn = $('<button type="button" class="tablepaginateQ_nav_first">'+opts.nav_first_btn_label+'</button>');
		bind_table_nav(nav_first_btn, 'first');
		var nav_prev_btn = $('<button type="button" class="tablepaginateQ_nav_prev">'+opts.nav_prev_btn_label+'</button>');
		bind_table_nav(nav_prev_btn, 'prev');
		var nav_next_btn = $('<button type="button" class="tablepaginateQ_nav_next">'+opts.nav_next_btn_label+'</button>');
		bind_table_nav(nav_next_btn, 'next');
		var nav_last_btn = $('<button type="button" class="tablepaginateQ_nav_last">'+opts.nav_last_btn_label+'</button>');
		bind_table_nav(nav_last_btn, 'last');
		
		// build page number navigation
		var span_nav_page_nbrs = build_nav_page_nbrs(false);
		
		// build show rows navigation
		var div_bottom_bar = $('<div class="tablepaginateQ_bottom_bar"/>');
		var span_rows = $('<span class="tablepaginateQ_rows"/>');
		for (index in opts.nav_show_rows) {
			var nbr_rows = opts.nav_show_rows[index];
			var show_rows_btn = $('<button type="button">'+nbr_rows+'</button>');
			bind_rows_nav(show_rows_btn, nbr_rows);
			span_rows.append(show_rows_btn);
		}
		var refresh_button = $('<img src="../../img/repeat.png" id="table_refresh">').bind('click', function(e) {e.preventDefault();goto_page(opts);});
		span_rows.append(refresh_button);
		//div_bottom_bar.append(span_rows);

		// ajax loading indicatior
		//var div_ajax = $('<div class="tablepaginateQ_ajax_loaded">ss<br/></div>');

		
		// put page navigation & search together
		var div_top_bar = $('<div class="tablepaginateQ_top_bar"/>');
		var span_nav = $('<span class="tablepaginateQ_nav"/>');
		if (opts.search_show) {
			var span_search = $('<span class="tablepaginateQ_search"/>');
			//var span_search_selector = $('<select size="1" name="search_selector"><option value= "1">par émission</option><option value= "2">par épisode</option><option value= "3">par animateur</option></select>');
			
			/*var span_search_selector = $('<select size="1" id="search_selector">');
			for (index in opts.search_sections) 
			{
				var current_row = $('<option value= "'+index+'">'+opts.search_sections[index]+'</option>');
				span_search_selector.append(current_row);
			}
			span_search_selector.append('</select>');*/

			span_search.append(search_box).append(search_btn).append("<div id='tiny_wrapper'><div id='tinyPlayer'></div></div>");//.append(span_search_selector);

		} else {
			var span_search = null;
		}
		span_nav.append(nav_first_btn).append(nav_prev_btn).append(span_nav_page_nbrs).append(nav_next_btn).append(nav_last_btn);
		//div_top_bar.append(span_search).append(span_nav);
		div_bottom_bar.append(span_nav);
		div_top_bar.append(span_search).append(span_rows).append('<br class="clear">');
		//$("#a_loader").html('<div class="tablepaginateQ_ajax_loaded"></div>');
		
		// extra div; maybe debug, ad, etc
		var div_extra = $('<div class="tablepaginateQ_extra"/>');

		if (opts.simple_table) {
			// do nothing .. since simple table
		} else {
			// prepare the Q in table paginate
			tpQ_wrapper.prepend(div_top_bar);
			tpQ_wrapper.append(div_bottom_bar);
			tpQ_wrapper.append(div_extra);
			
			// put the Q in table paginate
			bind_ajax();

			// mark active
			mark_active_page();
			mark_active_rows_nav();
		}
		apply_table_css();
		
	}); // end each table found
	
	// internal functions \\//

	$.fn.refresh = function()
	{
		goto_page();
	};

	function bind_ajax() {
		var ajax = {
            cache: false,
			beforeSend: function(request) {
				if (opts.ajax_running) {
					return false;
				}
				opts.ajax_running = true;
				$('div#'+opts.id).find('div.tablepaginateQ_ajax_loaded').addClass('tablepaginateQ_ajax_loading');
				$('div#'+opts.id).find('span.tablepaginateQ_nav_page_nbrs button').attr('disabled', true);
				$('div#'+opts.id).find('div.tablepaginateQ_top_bar').addClass('tablepaginateQ_ajaxing');		
			},
			success: function(result, status) {
				// console.log('bind_ajax success: ', 'result: ', result, 'status: ', status);
				// console.log(opts.id, $('div#'+opts.id));
				if (opts.ajax.dataType == 'html') {
					if (result == '' || result == null) {
						result = 'No results returned';
					}
					// update Q table, leaving the top and bottom nav alone
					var table = $(result).filter('table.tablepaginateQ');
					$('div#'+opts.id).find('table.tablepaginateQ:first').replaceWith(table);
					table = $('div#'+opts.id).find('table.tablepaginateQ');
					// console.log(table, $('div#'+opts.id), $('div#'+opts.id).find('table.tablepaginateQ'));
					
					// update extra, if any
					var extra = $(result).not('table.tablepaginateQ:first');
					$('div#'+opts.id).find('div.tablepaginateQ_extra').html(extra);
					// console.log(table, extra);					

				} else if (opts.ajax.dataType == 'json') {
					$('div#'+opts.id).html('json response not supported yet');
					return;
				}
				
				if (table.length == 0) {
					//$('div#'+opts.id).html('expected table not found');	
					return;					
				}
				// parse any options via data attributes
				parse_data_attributes(table);
				
				// calc nbr pages; which may be new based on filter
				calc_nbr_pages();
				// console.log(opts);
				
				// rebuild nav page nbrs
				build_nav_page_nbrs(true);
				
				// build table header
				build_table_header();
				
		
				// mark active
				mark_active_page();
				mark_active_rows_nav();
				apply_table_css();				
				
			},
			error: function(request, status, error) {
				// console.log('bind_ajax error: ', 'request: ', request, 'status: ', status, 'error: ', error);
				var msg = 'Unable to load table. ';
				if (status != undefined && status != 'error') {
					msg += ' ' + status + '.';
				}
				if (error != undefined && error != 'error') {
					msg += ' ' + error + '.';
				}
				msg += '<br/>';
				msg += '<a href="#" onClick="javascript:window.location.reload(); return false;">Reload page.</a>';
				$('div#'+opts.id).html(msg);
			},
			complete: function(request, status) {
				opts.ajax_running = false;
				$('div#'+opts.id).find('div.tablepaginateQ_top_bar').removeClass('tablepaginateQ_ajaxing');
				if (opts.nbr_pages > 1) {
					$('div#'+opts.id).find('span.tablepaginateQ_nav_page_nbrs button').removeAttr('disabled');
				} else {
					$('div#'+opts.id).find('span.tablepaginateQ_search button').removeAttr('disabled');
				}
				$('div#'+opts.id).find('div.tablepaginateQ_ajax_loaded').removeClass('tablepaginateQ_ajax_loading');
				//console.log(opts.ajax.data);
			}
		};
		opts.ajax = $.extend(true, opts.ajax, ajax);
	} // end bind_ajax()
	
	function parse_data_attributes(tbl) {
		if (tbl.attr('data-ajax_data')) {
			try {
				var ajax_data = tbl.attr('data-ajax_data'); // grab aja data from table attribute
				// check if attribute looks like could be json data
				if (ajax_data.indexOf('{') == 0 && // start of json object
					ajax_data.indexOf('}') == ajax_data.length - 1 && // end of json object
					ajax_data.indexOf(':') != -1) // at least one piece of data
				{
					// console.log('eval: ', ajax_data);
					// try to eval what appears to be json data to t in true json object
					ajax_data = window['eval']('('+ajax_data+')'); // derived from jquery
					// copy ajax data from attribute over any from js call
					opts.ajax.data = $.extend(true, opts.ajax.data, ajax_data);
				}
			} catch (e) {
				// unable to parse passed in data
			}
			// console.log(opts.ajax.data, ajax_data, tbl.attr('data-ajax_data'));
		}	
	} // end parse_data_attributes()
	
	function apply_simple_table(tbl) {
		tbl.find('tbody tr:odd').addClass(opts.css_even_row);
		tbl.find('tbody tr:even').addClass(opts.css_odd_row);
	}
	
	function apply_table_css() {
		$('div#'+opts.id).find('table.tablepaginateQ tr:even').addClass(opts.css_even_row);
		$('div#'+opts.id).find('table.tablepaginateQ tr:odd').addClass(opts.css_odd_row);
	}
	
	function mark_active_page() {
		$('div#'+opts.id).find('span.tablepaginateQ_nav button').removeClass('tablepaginateQ_nav_active');
	
		// no nav since only one page
		if (opts.nbr_pages == 1) {
			$('div#'+opts.id).find('span.tablepaginateQ_nav button').attr('disabled', true);
		}
		
		// at end of pages, so disable next/last
		if (opts.nbr_pages == opts.page) {
			$('div#'+opts.id).find('button.tablepaginateQ_nav_next').attr('disabled', true);
			$('div#'+opts.id).find('button.tablepaginateQ_nav_last').attr('disabled', true);
		} else {
			$('div#'+opts.id).find('button.tablepaginateQ_nav_next').removeAttr('disabled');
			$('div#'+opts.id).find('button.tablepaginateQ_nav_last').removeAttr('disabled');		
		}
		
		// at start of pages, so disable prev/first
		if (1 == opts.page) {
			$('div#'+opts.id).find('button.tablepaginateQ_nav_prev').attr('disabled', true);
			$('div#'+opts.id).find('button.tablepaginateQ_nav_first').attr('disabled', true);
		} else {
			$('div#'+opts.id).find('button.tablepaginateQ_nav_prev').removeAttr('disabled');
			$('div#'+opts.id).find('button.tablepaginateQ_nav_first').removeAttr('disabled');		
		}		
		
		$('div#'+opts.id).find('span.tablepaginateQ_nav_page_nbrs button').each( function(index) {
			// console.log($(this).html(), opts.page);
			if ($(this).html() == opts.page) {
				$(this).addClass('tablepaginateQ_nav_active');
				return true;
			}
		});
	} // end mark_active_page()
	
	function bind_search(search_btn) {
/*
          $('#search_input').keyup(function(e)
            {
                e.preventDefault();
	            console.log(e.keyCode);
	            if(e.keyCode == 13) { search_btn.click(); }
             });
*/
		search_btn.bind('click', function(e) {
			if (opts.search_show) {
				var search = $('div#'+opts.id).find('input.tablepaginateQ_search_box');
				//var span_search = $('span.tablepaginateQ_search');
				var span_search = $('div#search_wrap');
				//search += ',"section":"'+$('#search_selector').val()+'"';
				//opts.search = $('div#'+opts.id).find('input.tablepaginateQ_search_box').val();
				//search = '{'+search+'}';
				//console.log(search);
				opts.search = search.val();
				//opts.section = $('#search_selector').val();
				var close_button = $('<img src="../../img/window-close.png" style="position:absolute;right:7px;top:2px;cursor: pointer;">').bind('click', function(e) {e.preventDefault(); search.val('');opts.search = '';opts.page = 1; goto_page(opts); $(this).remove();});
				if (search.length >0) span_search.append(close_button);
				e.preventDefault();

			} else if (opts.search_external != null) {
				var search = '';
				$(opts.search_external).find('input,select').each(function(index) {
					if ($(this).attr('type') == 'checkbox' && !this.checked) {
						return true;
					}
					if ($(this).attr('type') == 'radiobutton' && !this.checked) {
						return true;
					}
					search += ',"'+encodeURIComponent($(this).attr('name'))+'":'+
							  '"'+encodeURIComponent($(this).attr('value'))+'"';
				});
				search = search.substr(1);
				search = '{'+search+'}';
				//console.log(search);
				opts.search = search;
				e.preventDefault(); // stop external submit, if any
			}

			opts.page = 1;
			goto_page(opts);
		});	
	} // end bind_search()
	

	function bind_table_nav(obj, page) {			
		obj.bind('click', function(e) {

			if (page == 'first') {
				page_nbr = 1;
			} else if (page == 'prev') {
				page_nbr = opts.page - 1;
			} else if (page == 'next') {
				page_nbr = opts.page + 1;
			} else if (page == 'last') {
				page_nbr = opts.nbr_pages;
			} else {
				page_nbr = page;
			}
			page_nbr = parseInt(page_nbr);
			if (page_nbr < 1) {
				page_nbr = 1;
			} else if (page_nbr > opts.nbr_pages) {
				page_nbr = opts.nbr_pages;
			}
			opts.page = page_nbr;

			// calculate offset
			opts.offset = (opts.page - 1) * opts.rows;
			
			mark_active_page();
			
			goto_page(opts);
		});	
	} // end bind_table_nav()
	

	function mark_active_rows_nav() {
		$('div#'+opts.id).find('span.tablepaginateQ_rows button').removeClass('tablepaginateQ_rows_active');
	
		$('div#'+opts.id).find('span.tablepaginateQ_rows button').each( function(index) {
			// console.log($(this).html(), opts.page);
			if ($(this).html() == opts.rows) {
				$(this).addClass('tablepaginateQ_rows_active');
				return true;
			}
		});
	} // end mark_active_rows_nav()
	

	function bind_rows_nav(obj, rows) {
		obj.bind('click', function(e) {
			opts.rows = rows;
			opts.page = 1;
			
			goto_page(opts);
			
			if (opts.on_nav_rows_scroll_to_top) {
				var offset = $('div#'+opts.id).offset();
				$('html').animate({scrollTop: offset.top}, 777);
			}
		});	
	} // end bind_rows_nav()
	
	
	
	function build_table_header() {
		// get table header; assume first row of thead
		var table_header = $('div#'+opts.id).find('table.tablepaginateQ:first').find('thead tr:first');
		
		// bind header for sorting
		table_header.children().each( function(index) {
			bind_col_sort($(this), index);
		});
	}
	
	function build_col_sort(obj, col) {
	
		// console.log(obj, col, opts);
		sorting = false;
		for (key in opts.sort_cols) {
	//		alert(opts.sort_cols[key]);
			if (opts.sort_cols[key] == 'all') {
				sorting = true;
				
				break;
			} else if (opts.sort_cols[key] == col) {
			
				sorting = true;
				break;
			}
		}
	//	alert(opts.sort_col+":"+col+":"+opts.sort_order+":"+sorting);
		if (!sorting) {
			return false;
		}
		
		if (opts.sort_col == col && opts.sort_order == 'asc') {
			obj.attr('class', 'tablepaginateQ_sort_asc');
		} else if (opts.sort_col == col && opts.sort_order == 'desc') {
			obj.attr('class', 'tablepaginateQ_sort_desc');
		} else {
			obj.attr('class', 'tablepaginateQ_sort_none');
		}
		
		return true;		
	} // end build_col_sort()
	

	function bind_col_sort(obj, col) {
	
		if(build_col_sort(obj, col))
		{
		
		obj.bind('click', function(e) {
			opts.sort_col = col;
			
			build_col_sort(obj, col);		
			
			if (opts.sort_col == col) {
				if (opts.sort_order == 'asc') {
					opts.sort_order = 'desc';
					obj.attr('class', 'tablepaginateQ_sort_desc');
				} else {
					opts.sort_order = 'asc';
					obj.attr('class', 'tablepaginateQ_sort_asc');
				}
			}			
			
			
			goto_page(opts);
		});	
		}
	} // end bind_col_sort()
	
	function bind_nav_page_nbrs(target, page) {
		
		if (!isNaN(page)) {
			var nav_page_nbr = $('<button type="button">'+page+'</button>');
			bind_table_nav(nav_page_nbr, page);
		} else {
			var nav_page_nbr = $('<span>'+page+'</span>');
		}
		target.append(nav_page_nbr);	
	}
	
	function build_nav_page_nbrs(replace) {
		// build page number navigation

		var span_nav_page_nbrs =  null;
		if (replace) {
			span_nav_page_nbrs = $('div#'+opts.id).find('span.tablepaginateQ_nav_page_nbrs');
			span_nav_page_nbrs.find('button').unbind('click');
			span_nav_page_nbrs.html('');
		} else {
			span_nav_page_nbrs = $('<span class="tablepaginateQ_nav_page_nbrs"/>');			
		}
			
		// define counters
		var edge = Math.floor(opts.nav_nbr_page_nbrs_shown / 2);
		var start = opts.page - edge;
		var start_mark = '';
		var end = opts.page + edge;
		var end_mark = '';
		
		if (start < 1) {
			end -= start;
			start = 1;
		} else if (start > 1) {
			start_mark = opts.nav_nbr_page_spacer;
		}
		if (start == 1) {
			if (opts.nbr_pages > opts.nav_nbr_page_nbrs_shown) {
				end = opts.nav_nbr_page_nbrs_shown;
			} else {
				end = opts.nbr_pages;
			}
		}

		if (end > opts.nbr_pages && opts.nbr_pages > edge) {
			start -= end - opts.nbr_pages;
			end = opts.nbr_pages;
		} else if (end < opts.nbr_pages) {
			end_mark = opts.nav_nbr_page_spacer;
		}
		if (end == opts.nbr_pages) {
			start = opts.nbr_pages - opts.nav_nbr_page_nbrs_shown + 1;
		}
		
		if (opts.nbr_pages < edge) {
			end = opts.nbr_pages;
		}
		
		if (start <= 1) {
			start = 1;
			start_mark = '';
		}		
		
		// console.log(start, end, edge);
		
		// build interval links
		span_nav_page_nbrs.append($('<span>'+start_mark+'</span>'));
		for(var index = start; index <= end; index++) {
			bind_nav_page_nbrs(span_nav_page_nbrs, index);
		}
		span_nav_page_nbrs.append($('<span>'+end_mark+'</span>'));
			
		return span_nav_page_nbrs;
	} // end build_nav_page_nbrs()
	
	function calc_nbr_pages() {
	
		opts.total = $('div#'+opts.id).find('table.tablepaginateQ').attr('data-total');
		if (opts.total == 'undefined') {
			opts.total = 0;
		}
		opts.total = parseInt(opts.total);	
		
		// get number of pages
		if (opts.total > 0 && opts.rows > 0) {
			opts.nbr_pages = Math.ceil(opts.total / opts.rows);
		} else {
			opts.nbr_pages = 1;
		}		
	} // end calc_nbr_pages()
	
	// do ajax call and go to page
	// most likely pass in {page:#}
	var goto_page = function(options) {
		// overlay passed in options over current table options
		opts = $.extend(true, opts, options);	

		// calculate offset
		opts.offset = (opts.page - 1) * opts.rows;
				
		// build tablepaginateQ navigation parms
		var nav_data = {};
		nav_data[opts.target_name+'id'] = opts.id;
		nav_data[opts.target_name+'page'] = opts.page;
		nav_data[opts.target_name+'offset'] = opts.offset;
		nav_data[opts.target_name+'rows'] = opts.rows;
		nav_data[opts.target_name+'search'] = opts.search;
		//nav_data[opts.target_name+'section'] = opts.section;
		nav_data[opts.target_name+'sort_col'] = opts.sort_col;
		nav_data[opts.target_name+'sort_order'] = opts.sort_order;
		
		// extend with any user data
		opts.ajax.data = $.extend(true, opts.ajax.data, nav_data);

		// console.log(opts);
		// console.log(opts.ajax.data);
		
		// goto page
		$.ajax(opts.ajax);
	}; // end goto_page()	
	
	if (opts.initial_load) {
		goto_page(opts.page);
	}
	
	return this;
	
}; // end tablepaginateQ()

})(jQuery);

