/* Pagination 5.7.0 */

// awpPagingItems[] : external
var awpPagingT;
var awpPagingItemsInactive = [];
var awpPagingFilterQuery = null;

(function($) {

	$.awpPaging = function(opts) {

		var defaults = {
			'isUseCallback'							: null,
			'useSel'								: 'body.pagination',
			'defaultItemsSel'						: '#contents .default-contents',
			'tableSel'								: '#contents-table',
			'cellFirstSel'							: '.first',
			'cellLastSel'							: '.last',
			'cellDummyClass'						: 'dummy',
			'itemsPerPage'							: 12, 		// default value
			'numPageControls'						: 6, 		// default value
			'showAllPagesControls'					: false,
			'viewallLimit'							: 0,		// 0 : always confirm
																// > 0 : confirm only when num items exceeds value
																// else no confirm
			'progressTimeout'						: 400,
			'defaultSortSel'						: null, 	// not completed
			'onDone'								: null,
			'onPreSort'								: null,
			'controlsSel'							: '.paging-controls',
			'controlsFilterDescContainerSel'		: '.filter-description-container',
			'controlsFilterDescSel'					: '.filter-description',
			'controlsFilterDescNoSelectionSel'		: '.filter-description-no-selection',
			'controlsFilterDescShowNoSelection'		: true,
			'controlsContainerSel'					: '.controls',
			'controlsCommonSel'						: '.control',
			'controlsPrevSel'						: '.prev',
			'controlsNextSel'						: '.next',
			'controlsPrevxSel'						: '.prevx',
			'controlsNextxSel'						: '.nextx',
			'controlsFirstSel'						: '.first',
			'controlsLastSel'						: '.last',
			'controlsPageSel'						: '.page',
			'controlsPageNumberSel'					: '.value',
			'controlsGotoContainerSel'				: '.goto-container',
			'controlsGotoSel'						: '.goto',
			'controlsGotoPageNumberSel'				: '.goto-value',
			'controlsPageInfoSel'					: '.info',
			'controlsInfoNoItemsSel'				: '.no-items',
			'controlsViewAllSel'					: '.viewall',
			'controlsViewPagesSel'					: '.viewpages',
			'controlsProgressSel'					: '.progress',
			'controlsSortContainerSel'				: '.sortby-container',
			'controlsSortSel'						: '.sortby',
			'controlsItemsPerPageContainerSel'		: '.items-per-page-container',
			'controlsItemsPerPage'					: '.items-per-page',
			'controlsViewAllValue'					: 'viewall',
			'controlsInfoHtml'						:  null,
			'filterContentsPageUrl'					: 'http://www.storedomain.com/filter-items.html',
			'filterContentsPageSel'					: '#filter-items-page',
			'filterFormSel'							: '#filter-container',
			'noSelectionValue'						: '',

			'dataDef' : [
				// id
				{	'sel'		: '.vwitem',
					'kind'		: 'value-attr'},
				// name
				{	'sel'		: '.name-link',
					'kind'		: 'html',
					'sort'		: 'alpha',
					'name'		: 'name'},
				// abstract
				{	'sel'		: '.detail',
					'kind'		: 'html'},
				// price
				{	'sel'		: '.price',
					'kind'		: 'html'},
				// url
				{	'sel'		: '.name-link, .image-link',
					'kind'		: 'href-attr'},
				// image url
				{	'sel'		: '.image img',
					'kind'		: 'src-attr'},
				// code
				{	'sel'		: '.code .value',
					'kind'		: 'text'},
				// availability
				{	'sel'		: '.availability',
					'kind'		: 'html'},
				// outofstock
				{	'sel'		: '.outofstock',
					'kind'		: 'html'},
				// price sort
				{	'sel'		: null,
					'kind'		: 'none',
					'sort'		: 'numeric',
					'name'		: 'price'},
				// size filter
				{	'sel'		: null,
					'kind'		: 'filter',
					'sort'		: 'alpha',
					'name'		: 'size'},
				// style filter
				{	'sel'		: null,
					'kind'		: 'filter',
					'sort'		: 'alpha',
					'name'		: 'style'},
				// color filter
				{	'sel'		: null,
					'kind'		: 'filter',
					'sort'		: 'alpha',
					'name'		: 'color',
					'multi'		: true},
				// filter active
				{	'sel'		: null,
					'kind'		: 'active',
					'sort'		: 'boolean',
					'name'		: 'active'},
				// natural order sort 
				{	'sel'		: '',
					'kind'		: 'none',
					'sort'		: 'numeric',
					'name'		: 'natural'}
			]
			
			//'controlsInfoHtml'					: 'Page number of total'
		};

		//window.status=('Connecting to search page...');
		//window.location.href = settings.allContentsPageUrl + query;

		var settings = $.extend({}, defaults, opts);

		// CONSTANTS

		var	DIR_ASC  =  1,
			DIR_DESC = -1;

		// variables

		var	i,
			jTable,
			jFilterForm,
			gViewAll,
			gItems,
			gNumItems,
			gNumPages = null,
			gItemsPerPage,
			gItemsPerPageWas,
			gNumPageControls,
			gNumColumns,
			gIsFilterItemsPage	= false,
			gCurrentPageIndex	= 0,
			gWasPageIndex		= null,
			gUpdatePage			= {},
			gActiveFieldIndex	= null,
			gPreSortDone		= false,
			gSetupIsDone		= true;

		/*var isie6or7 = 	$.browser.msie &&
        				( /MSIE 6\.0/i.test(window.navigator.userAgent) 
						|| /MSIE 7\.0/i.test(window.navigator.userAgent) );*/

		//--------------------------------------------------------------------------------
		// begin private functions

		//--------------------------------------------------------------------------------
		function isUse () {
			if (settings.isUseCallback) {
				return settings.isUseCallback.call();
			} else {
				return $(settings.useSel).size() > 0;
			}
		}

		//--------------------------------------------------------------------------------
		function setup () {
			var i;
			// find the 'active' field in data definition
			for (i=0;i<settings.dataDef.length;i++) {
				if (settings.dataDef['kind'] == 'active') {
					gActiveFieldIndex = i;
					break;
				}
			}
			gNumItems = getNumItems();
			gNumPages = getNumPages();
			gItemsPerPage = getItemsPerPage();
			gNumPageControls = getNumPageControls();
			gNumColumns = jTable.find('> tbody tr:first td').size();
			setupControls();
			setupControlSort();
			setupControlItemsPerPage();
			updateControlsRows();

			// clone for footer controls
			//jTable.find('tfoot').append(jControls.clone(true));
			/*jTable.find('thead').contents()
				.clone(true)
					.appendTo(jTable.find('tfoot'))
						.show();*/
						
			gSetupIsDone = true;

		}

		//--------------------------------------------------------------------------------
		// setup filter info display
		function setupFilterInfoDisplay () {
			var w = null;
			// make display text
			if (awpPagingFilterQuery) {
				w = [];
				$(awpPagingFilterQuery).each(function(i, elem){
					//w += elem.name + ': ' + elem.value + '<br/>';
					w.push(elem.value);
				});
				w = w.join(', ');
			}
			// set display text, else show no-selection text, else show nothing
			if (w) {
				$(settings.controlsFilterDescContainerSel)
					.show()
					.find(settings.controlsFilterDescNoSelectionSel)
						.hide()
						.end()
					.find(settings.controlsFilterDescSel)
						.text(w);
			} else if (settings.controlsFilterDescShowNoSelection) {
				$(settings.controlsFilterDescContainerSel)
					.show()
					.find(settings.controlsFilterDescSel)
						.hide()
						.end()
					.find(settings.controlsFilterDescNoSelectionSel)
						.show();
			} else {
				$(settings.controlsFilterDescContainerSel)
					.hide()
					.find(settings.controlsFilterDescSel)
						.text('');
			}
		}

		//--------------------------------------------------------------------------------
		function setupDOM () {
			var i, name;
			// is this the filter page
			gIsFilterItemsPage = $(settings.filterContentsPageSel).size() > 0 ? true : false;
			// hide default items
			$(settings.defaultItemsSel).hide();
			/*// find contents table
			jTable = $(settings.tableSel).eq(0);
			// exit if paging items array is not set
			if (!(typeof awpPagingItems == 'object')) {
				jTable.hide();
				$(settings.defaultItemsSel).show();
				return $(this);
			}*/
			// filter form
			jFilterForm = $(settings.filterFormSel).eq(0);
			// setup select change behaviors
			//jFilterForm.find('select').change(function(){});
			// for all other pages set SELECTs to default
			if (gIsFilterItemsPage && awpPagingFilterQuery) {
				// set filter selects to query input values
				for (var j=0;j<awpPagingFilterQuery.length;j++) {
					name = awpPagingFilterQuery[j]['name'];
					jFilterForm.find('[name="' + name + '"]').val(awpPagingFilterQuery[j]['value']);
				}
			} else {
				// set to default values
				jFilterForm.find('select').each(function(){
					$(this).val($(this).find('option:first').val());
				});
				// preset filter values if they exist
				if (typeof awpPaging5PageFilterValues == 'object') {
					for (i=0;i<settings.dataDef.length;i++) {
						// if this data defintion field is a filter
						if ((settings.dataDef[i]['kind']) && (settings.dataDef[i]['kind'] == 'filter')) {
							// name of this data definition field
							name = settings.dataDef[i]['name'];
							// if there's a value, set the corresponding name element
							if (awpPaging5PageFilterValues[name]) {
								jFilterForm.find('[name="' + name + '"]').val(awpPaging5PageFilterValues[name]);
							}
						}
					}
				}
			}
			setupFilterInfoDisplay();
			// show table, jic
			jTable.show();
		}

		//--------------------------------------------------------------------------------
		// this is not in setupControls() because it only needs done the first time.
		function setupControlItemsPerPage () {
			// items per page SELECT behaviour
			jTable.find(settings.controlsItemsPerPage, settings.controlsSel).change(function(){
				var val = $(this).val();
				gViewAll = false;
				if (val == 'viewall') {
					if (confirmViewAll()) {
						gViewAll = true;
					} else {
						gViewAll = false;
						gItemsPerPageWas = val;
					}
				}
				updateControlsRows();
				changePageCmd(0);
			});
		}

		//--------------------------------------------------------------------------------
		// this is not in setupControls() because it only needs done the first time.
		function setupControlSort () {
			// sortby SELECT behaviour
			jTable.find(settings.controlsSortSel, settings.controlsSel).change(function(){
				// value of SELECT control
				var val = $(this).val();
				val = val.split(' ');
				var name = val[0];
				var direction = val[1];
				// find data field definition according to name
				var colIndex = findDataDefColIndexByName(name);
				// do sort
				if (colIndex !== null) {
					var kind = settings.dataDef[colIndex].sort;
					sortPageCmd(colIndex, kind, direction);
				}
			});
		}

		//--------------------------------------------------------------------------------
		function setupControls () {
			var i;
			// controls container, head and foot
			var jControls = jTable.find(settings.controlsSel);
			// each control set, head and foot
			jControls.each(function(){
				var jControl = $(this);
				// page number control
				var jPage = jControl.find(settings.controlsPageSel).eq(0);
				// clone page number controls
				for (i=1;i <= gNumPageControls-1;i++) {
					jPage.after(jPage.clone());
				}
				jControl
					.find(settings.controlsPageSel).each(function(i){
						$(this)
							.removeClass('first-page-control')
							.removeClass('last-page-control')
							.removeClass('current');
						if (i == 0) {
							$(this).addClass('first-page-control');
						} else if (i == (gNumPageControls - 1)) {
							$(this).addClass('last-page-control');
						}
					});
				jControl
					.find(settings.controlsCommonSel)
						.click(function(){
							changePageCmd(this);
							if (!$(this).hasClass('foot')) {
								return false;
							}
						})
						.hover(
							function(){$(this).addClass('hover')},
							function(){$(this).removeClass('hover')}
						)
						.end()
					.find(settings.controlsFirstSel)
						.data('command', 'first')
						.end()
					.find(settings.controlsLastSel)
						.data('command', 'last')
						.end()
					.find(settings.controlsPrevSel)
						.data('command', 'prev')
						.end()
					.find(settings.controlsNextSel)
						.data('command', 'next')
						.end()
					.find(settings.controlsPrevxSel)
						.data('command', 'prevx')
						.end()
					.find(settings.controlsNextxSel)
						.data('command', 'nextx')
						.end()
					.find(settings.controlsPageSel)
						.data('command', 'page')
						.end()
					.find(settings.controlsGotoSel)
						.data('command', 'goto')
						.end()
					.find(settings.controlsViewAllSel)
						.data('command', 'viewall')
						.end()
					.find(settings.controlsViewPagesSel)
						.data('command', 'viewpages')
						.end()
					.find(settings.controlsGotoPageNumberSel)
						.keyup(function(){
							var elem = this;
							$(elem)
								.parents(settings.controlsSel)
									.find(settings.controlsGotoSel)
										.data('pageIndex', $(elem).val() - 1);
						});
						
			}); // end jControls.each()
		}

		//--------------------------------------------------------------------------------
		function changePageCmd (controlElem) {
			progress('start');
			gUpdatePage.controlElem = controlElem;
			awpPagingT = changePageDo;
			setTimeout( "awpPagingT()", 400);
		}

		//--------------------------------------------------------------------------------
		function changePageDo () {
			updatePage(gUpdatePage.controlElem);
			progress();
			gUpdatePage = {};
		}

		//--------------------------------------------------------------------------------
		function progress (mode) {
			if (mode == 'start') {
				jTable.find(settings.controlsPageInfoSel).addClass('progress');
			} else {
				// stop
				jTable.find(settings.controlsPageInfoSel).removeClass('progress');
			}
		}

		//--------------------------------------------------------------------------------
		function getNumItems () {
			return awpPagingItems.length;
		}

		//--------------------------------------------------------------------------------
		function getItemsPerPage () {
			var x;
			// get value from control or settings
			if (gViewAll) {
				x = gNumItems;
			} else {
				x = jTable.find(settings.controlsItemsPerPage, settings.controlsSel).val();
				x = x * 1;
				if ((typeof x != 'number') || isNaN(x)) {
					x = settings.itemsPerPage;
				}
				// trap to number of items
				x = Math.min(gNumItems, x);
			}
			return x;
		}

		//--------------------------------------------------------------------------------
		function getNumPages () {
			if (gViewAll) {
				return 1;
			} else {
				return Math.ceil(gNumItems / getItemsPerPage());
			}
		}

		//--------------------------------------------------------------------------------
		function setIdentifier (elem, selector) {
			var jElem = $(elem);
			if (selector.indexOf('.') === 0) {
				jElem.addClass(selector.substr(1));
			} else if (selector.indexOf('#') === 0) {
				jElem.attr('id', selector.substr(1));
			}
			return jElem;
		}

		//--------------------------------------------------------------------------------
		function hasIdentifier (elem, selector) {
			var jElem = $(elem);
			if (selector.indexOf('.') === 0) {
				return jElem.hasClass(selector.substr(1));
			} else if (selector.indexOf('#') === 0) {
				return (jElem.attr('id') === selector.substr(1));
			}
			// else
			return false;
		}

		//--------------------------------------------------------------------------------
		function updatePage (controlElem) {
			// update controls
			updateControls(controlElem);
			if (hasItems()) {
				// new page
				pager();
				// reset
				gWasPageIndex = gCurrentPageIndex;
				// show tbody
				jTable.find('tbody').show();
			} else {
				gWasPageIndex = null;
				// hide tbody
				jTable.find('tbody').hide();
			}
			// on done
			if (settings.onDone) {
				// params: page index, jTable
				settings.onDone.call(gCurrentPageIndex, jTable);
			}
		}

		//--------------------------------------------------------------------------------
		function updateControls (controlElem) {
			// IN: controlElem : page index (number) or command (string)
			// adjust controls for has/not items
			// show/hide .info-container .info
			// hide/show                 .no-items
			// visi/hide                 .controls
			// visi/hide                 .sortby-container
			// visi/hide                 .items-per-page-container
			if (hasItems()) {
				jTable.find(settings.controlsSel)
					.find(settings.controlsPageInfoSel)
						.show()
						.end()
					.find(settings.controlsInfoNoItemsSel)
						.hide()
						.end()
					.find([	settings.controlsContainerSel,
						   	settings.controlsSortContainerSel,
						   	settings.controlsItemsPerPageContainerSel].join(','))
						.css('visibility', 'visible');
			} else {
				jTable.find(settings.controlsSel)
					.find(settings.controlsPageInfoSel)
						.hide()
						.end()
					.find(settings.controlsInfoNoItemsSel)
						.show()
						.end()
				.find([	settings.controlsContainerSel,
						   	settings.controlsSortContainerSel,
						   	settings.controlsItemsPerPageContainerSel].join(','))
						.css('visibility', 'hidden');
			}
			// exit if no items
			if (!hasItems()) { return; }
			// get new page index, calc first index for proper shift of page links
			var pageIndex;
			var firstIndex = jTable.find('.first-page-control', settings.controlsSel).eq(0).data('pageIndex');
			var lastIndex = jTable.find('.last-page-control', settings.controlsSel).eq(0).data('pageIndex');
			if (typeof controlElem == 'number') {
				pageIndex = firstIndex = controlElem;
			} else {
				switch ($(controlElem).data('command')) {
					case 'viewall' :
						if (!confirmViewAll()) { return; }
						pageIndex = 0;
						firstIndex = 0;
						gViewAll = true;
						jTable.find(settings.controlsItemsPerPage).val(settings.controlsViewAllValue);
						gNumPages = 1;
						updateControlsRows();
						break;
					case 'viewpages' :
						pageIndex = 0;
						firstIndex = 0;
						gViewAll = false;
						//jTable.find(settings.controlsItemsPerPage).val(gItemsPerPageWas);
						jTable.find(settings.controlsItemsPerPage).val(getItemsPerPage());
						gNumPages = getNumPages();
						updateControlsRows();
						break;
					case 'first' :
						pageIndex = 0;
						firstIndex = 0;
						break;
					case 'last' :
						pageIndex = gNumPages - 1;
						firstIndex = gNumPages - 1 - gNumPageControls + 1;
						break;
					case 'page' :
						pageIndex = $(controlElem).data('pageIndex');
						if ($(controlElem).hasClass('first-page-control')) {
							firstIndex = Math.max(pageIndex - gNumPageControls + 1, 0);
						} else if ($(controlElem).hasClass('last-page-control')) {
							firstIndex = pageIndex;
						}
						break;
					case 'prev' :
						pageIndex = Math.max(gCurrentPageIndex - 1, 0);
						if (jTable.find('.first-page-control', settings.controlsSel).is('.current')) {
							firstIndex = Math.max(pageIndex - gNumPageControls + 1, 0);
						}
						break;
					case 'next' :
						pageIndex = Math.min(gCurrentPageIndex + 1, gNumPages - 1)
						if (jTable.find('.last-page-control', settings.controlsSel).is('.current')) {
							firstIndex = pageIndex;
						}
						break;
					case 'prevx' :
						firstIndex = Math.max(firstIndex - gNumPageControls, 0);
						pageIndex = firstIndex + gNumPageControls - 1;
						if (firstIndex == 0) {
							pageIndex = 0;
						}
						break;
					case 'nextx' :
						firstIndex = Math.min(lastIndex + 1, gNumPages - 1);
						pageIndex = firstIndex;
						break;
					case 'goto' :
						pageIndex = $(controlElem).data('pageIndex');
						if (isNaN(pageIndex)) { return; }
						pageIndex = Math.min(Math.max(pageIndex, 0), gNumPages - 1);
						firstIndex = pageIndex;
						break;
					default:
						// jic
						return;
				}
			}

			// new current page
			gCurrentPageIndex = pageIndex;

			//if (!gViewAll) {
			if (gNumPages > 1) {

				// trap end of pages
				firstIndex = Math.min(firstIndex, gNumPages - gNumPageControls);
				// trap beginning of pages
				firstIndex = Math.max(firstIndex, 0);

				// set page number controls if firstIndex is set
				if (firstIndex != null) {
					jTable.find(settings.controlsSel).each(function(){
						$(this).find(settings.controlsPageSel).each(function(i){
							$(this).data('pageIndex', firstIndex + i);
							$(settings.controlsPageNumberSel, this).text(firstIndex + 1 + i);
						});
					});
				}

				// set current page number control
				jTable.find(settings.controlsSel).each(function(){
					jTable.find(settings.controlsPageSel).each(function(){
						var pageNum = $(settings.controlsPageNumberSel, this).text();
						if (pageNum == (gCurrentPageIndex + 1)) {
							$(this).addClass('current');
						} else {
							$(this).removeClass('current');
						}
					});
				});

			}
		
			/*// first ellipses
			jTable
				.find(settings.controlsSel)
					.find(settings.controlsEllipsesFirst)
			if (firstIndex > 0) {
				// show
			} else {
				// hide
			}*/

			/*// last ellipses
			jTable
				.find(settings.controlsSel)
					.find(settings.controlsEllipsesFirst)
			if (lastIndex < (gNumPages - 1)) {
				// show
			} else {
				// hide
			}*/

			// set disabled controls
			if (!(gNumPages > 1)) {
				jTable.find(		  settings.controlsCommonSel
							    +','+ settings.controlsGotoContainerSel).css('visibility', 'hidden');
				if (gViewAll) {
					jTable.find(settings.controlsViewPagesSel).css({'display':'block','visibility':'visible'});
				}
			} else {
				jTable.find(		  settings.controlsCommonSel
							    +','+ settings.controlsGotoContainerSel).css('visibility', 'visible');
				if (gViewAll) {
					jTable.find(settings.controlsViewAllSel).hide();
					jTable.find(settings.controlsViewPagesSel).show();
				} else {
					jTable.find(settings.controlsViewAllSel).show();
					jTable.find(settings.controlsViewPagesSel).hide();
				}
				if (gCurrentPageIndex == 0) {
					// first page
					jTable.find(		  settings.controlsFirstSel 
									+','+ settings.controlsPrevSel
									+','+ settings.controlsPrevxSel).addClass('disabled');
					jTable.find(		  settings.controlsLastSel
									+','+ settings.controlsNextSel
									+','+ settings.controlsNextxSel).removeClass('disabled');
				} else if (gCurrentPageIndex == (gNumPages - 1)) {
					// last page
					jTable.find(		  settings.controlsLastSel
									+','+ settings.controlsNextSel
									+','+ settings.controlsNextxSel).addClass('disabled');
					jTable.find(		  settings.controlsFirstSel
									+','+ settings.controlsPrevSel
									+','+ settings.controlsPrevxSel).removeClass('disabled');
				} else {
					// not first or last page
					jTable.find(		  settings.controlsLastSel 
									+','+ settings.controlsFirstSel
									+','+ settings.controlsNextSel
									+','+ settings.controlsNextxSel
									+','+ settings.controlsPrevSel
									+','+ settings.controlsPrevxSel).removeClass('disabled');
				}
			}

			// set info
			if (settings.controlsInfoHtml) {
				jTable.find(settings.controlsPageInfoSel)
					.html(settings.controlsInfoHtml.replace('number', gCurrentPageIndex + 1).replace('total', gNumPages));
			} else {
				var first = (gCurrentPageIndex * gItemsPerPage) + 1;
				var last = Math.min(gNumItems, (gCurrentPageIndex + 1) * gItemsPerPage);
				jTable
					.find(settings.controlsPageInfoSel)
						.find('.item-first')
							.text(first)
							.end()
						.find('.item-last')
							.text(last)
							.end()
						.find('.item-total')
							.text(gNumItems)
							.end()
						.find('.page-current')
							.text(gCurrentPageIndex + 1)
							.end()
						.find('.page-total')
							.text(gNumPages);
			}

			// clear goto number
			jTable.find(settings.controlsGotoPageNumberSel).val('');
			
		}

		//--------------------------------------------------------------------------------
		function confirmViewAll () {
			if (	(settings.viewallLimit === 0) 
					||	((settings.viewallLimit > 0)
						&& (gNumItems > settings.viewallLimit)))
			{
				return confirm('Show all ' + gNumItems + ' items?');
			} else {
				// no limit
				return true;
			}
		}

		//--------------------------------------------------------------------------------
		// show current page
		function pager () {
			// setup first and last item indexes
			var indexFirst, indexLast;
			if (gNumPages > 1) {
				// multiple pages
				indexFirst = gCurrentPageIndex * gItemsPerPage;
				indexLast = indexFirst + gItemsPerPage - 1;
				indexLast = Math.min(indexLast, gNumItems - 1);
			} else {
				// only one page
				indexFirst = 0;
				indexLast = gNumItems - 1;
			}
			// number of items on this page
			var numPageItems = indexLast - indexFirst + 1;
			// number of table rows needed for this page
			var numPageRows = Math.ceil(numPageItems / gNumColumns);
			// current number of table rows
			var currentNumRows = jTable.find('tbody tr').size();
			// add rows/columns as needed for current page.
			// assumes there is at least one row.
			// this will only be executed intially,
			// and when the number of rows per page is changed
			// to a value larger than current.
			if (currentNumRows < numPageRows) {
				// get first row for cloning
				var jRow = jTable.find('tbody tr:first');
				// get tbody
				var jTbody = jTable.find('tbody');
				// each new row
				for (var rowIndex=currentNumRows;rowIndex<numPageRows;rowIndex++) {
					jRow.clone().appendTo(jTbody);
				}
			}
			// able rows for current page.
			// each row
			jTable.find('tbody tr').each(function(rowIndex){
				if (rowIndex >= numPageRows) {
					$(this).hide();
				} else {
					$(this).show();
				}
			});
			// SETUP DUMMY CELLS needed for number of items on this page.
			// each cell
			jTable.find('tbody td').each(function(cellIndex){
				if (cellIndex >= numPageItems) {
					$(this).addClass(settings.cellDummyClass);
				} else {
					$(this).removeClass(settings.cellDummyClass);
				}
			});
			// SET ITEM DATA
			var itemIndex = indexFirst;
			// each table cell
			jTable.find('tbody td').each(function(){
				var jCell = $(this);
				// put item data into cell
				var jItemData, itemData;
				// each data definition
				for (var d=0;d<settings.dataDef.length;d++) {
					if (settings.dataDef[d].sel) {
						jItemData = jCell.find(settings.dataDef[d].sel);
						// set data if element is found
						if (jItemData.size() > 0) {
							itemData = awpPagingItems[itemIndex][d];
							// set data according to kind of data
							switch (settings.dataDef[d].kind) {
								case 'html':
									jItemData.html(itemData);
									break;
								case 'href-attr':
									jItemData.attr('href', itemData);
									break;
								case 'value-attr':
									jItemData.attr('value', itemData);
									break;
								case 'src-attr':
									jItemData.attr('src', itemData);
									break;
								case 'action-attr':
									jItemData.attr('action', itemData);
									break;
								case 'text':
									jItemData.text(itemData);
									break;
								case 'none':
									; // no display
									break;
								default:
									; // no display
							}
						}
					}
				} // end each data definition
				// exit if done
				itemIndex++;
				if (itemIndex > indexLast) { return false; } // break each()
			}); // end each() table cell
		}

		//--------------------------------------------------------------------------------
		function updateControlsRows () {
			/*// no need to update if items-per-page haven't changed.
			if (gItemsPerPage === getItemsPerPage()) { return; }*/
			// current number of pages and number of page number controls
			gNumPages = getNumPages();
			gItemsPerPage = getItemsPerPage();
			gNumPageControls = getNumPageControls();
			// reduce page controls to one
			// each control row
			jTable.find(settings.controlsSel).each(function(){
				// delete page number controls except first one
				$(this).find(settings.controlsPageSel).each(function(i){
					if (i > 0) {
						$(this).remove();
					}
				}); // end each() control
			}); // end each() control row
			// finish
			setupControls();
		}

		//--------------------------------------------------------------------------------
		function getNumPageControls () {
			if (settings.showAllPagesControls) {
				return gNumPages;
			} else {
				return Math.min(gNumPages, settings.numPageControls);
			}
		}

		//--------------------------------------------------------------------------------
		function sortPageCmd (colIndex, kind, direction) {
			progress('start');
			gUpdatePage.colIndex = colIndex;
			gUpdatePage.kind = kind;
			gUpdatePage.direction = direction;
			awpPagingT = sortPageDo;
			setTimeout( "awpPagingT()", settings.progressTimeout);
		}

		//--------------------------------------------------------------------------------
		function doOnPreSort () {
			var i;
			if (settings.onPreSort && !gPreSortDone) {
				// params: active items array, active field index
				settings.onPreSort.call(awpPagingItems, gActiveFieldIndex);
				// pre sort has been done
				gPreSortDone = true;
				// pre sort may have set some items inactive
				// sort by the active field. descending puts the true values at beginning of sorted list.
				doSort(gActiveFieldIndex, 'boolean', 'desc');
				// find first inactive element index, splice array, ADD to inactive items array
				//   because it may already contain filtered-out items.
				for (i=0;i<awpPagingItems.length;i++) {
					if (awpPagingItems[i][gActiveFieldIndex] != true) {
						awpPagingItemsInactive =
							awpPagingItemsInactive.concat(awpPagingItems.splice(i, awpPagingItems.length - i));
						break;
					}
				}
				// update number of items, affects most everything
				gNumItems = getNumItems();
			}		
		}
		
		//--------------------------------------------------------------------------------
		function sortPageDo () {
			doOnPreSort();
			doSort(gUpdatePage.colIndex, gUpdatePage.kind, gUpdatePage.direction);
			updatePage(0);
			progress();
			gUpdatePage = {};
		}

		//--------------------------------------------------------------------------------
		function hasItems () {
			return (awpPagingItems.length > 0);
		}

		//--------------------------------------------------------------------------------
		function doSort (colIndex, kind, direction) {
			if (!hasItems()) { return; }
			var newDirection = (direction == 'desc') ? DIR_DESC : DIR_ASC;
			awpPagingItems.sort(function(a, b) {
				if (kind == 'price') {
					var valA = sortKeyPrice(a[colIndex]);
					var valB = sortKeyPrice(b[colIndex]);
				} else if (kind == 'numeric') {
					var valA = sortKeyNumeric(a[colIndex]);
					var valB = sortKeyNumeric(b[colIndex]);					
				} else if (kind == 'boolean') {
					var valA = sortKeyBoolean(a[colIndex]);
					var valB = sortKeyBoolean(b[colIndex]);					
				} else { // alpha
					var valA = sortKeyAlpha(a[colIndex]);
					var valB = sortKeyAlpha(b[colIndex]);
				}
				if (valA < valB) { return -newDirection }
				if (valA > valB) { return newDirection }
				return 0;
			});
		}

		//--------------------------------------------------------------------------------
		function sortKeyAlpha (key) {
			if (key) {
				return key.toLowerCase();
			} else {
				return ' ';
			}
		}

		//--------------------------------------------------------------------------------
		function sortKeyBoolean (key) {
			return (key) ? 1 : 0;
		}
		
		//--------------------------------------------------------------------------------
		function sortKeyNumeric (key) {
			//key = parseFloat(key.replace(/^[^d.]*/, '')); // this didn't work correctly (for decimal?)
			key = parseFloat(key);
			return isNaN(key) ? 0 : key;
		}

		//--------------------------------------------------------------------------------
		function sortKeyPrice (key) {
			var currencyIndex = key.lastIndexOf('$');
			if (currencyIndex != -1) {
				var spaceIndex = key.indexOf(' ', currencyIndex + 1);
				if (spaceIndex != -1) {
					key = key.substring(currencyIndex + 1, spaceIndex);
				} else {
					key = key.substr(currencyIndex + 1);
				}
				key = key.replace(',', '');
			}
			key = parseFloat(key);
			return isNaN(key) ? 0 : key;
		}

		//--------------------------------------------------------------------------------
		// get sort info from controls
		function getSort () {
			var	kind = null,
				val,
				name,
				direction,
				colIndex;
			val =	jTable
						.find(settings.controlsSortSel, settings.controlsSel)
							.val();
			do { // control
				if (!val) {break;}
				val = val.split(' ');
				name = val[0];
				if (val.length > 1) {
					direction = val[1];
				} else {
					direction = 'asc';
				}
				colIndex = findDataDefColIndexByName(name);
				if (colIndex !== null) {
					kind = settings.dataDef[colIndex].sort;
				}
			} while (0); // control
			return	{	'colIndex'	: colIndex,
						'kind'		: kind,
						'direction'	: direction};
		}

		//--------------------------------------------------------------------------------
		function filterPageCmd () {
			progress('start');
			awpPagingT = filterPageDo;
			setTimeout( "awpPagingT()", settings.progressTimeout);
		}

		//--------------------------------------------------------------------------------
		function filterPageDo () {
			doFilter();
			doOnPreSort();
			var s = getSort();
			doSort(s.colIndex, s.kind, s.direction);
			updateControlsRows();
			updatePage(0);
			progress();
			gUpdatePage = {};
		}

		//--------------------------------------------------------------------------------
		function doFilter () {
			var i, j;
			// restore original list of items
			awpPagingItems = awpPagingItems.concat(awpPagingItemsInactive); 
			awpPagingItemsInactive = [];
			// each item, adjust adjust active according to matching filter values.
			var okCount, propertyValues;
			for (i=0;i<awpPagingItems.length;i++) {
				// each filter query item
				okCount = 0;
				for (j=0;j<awpPagingFilterQuery.length;j++) {
					if (awpPagingFilterQuery[j]['multi']) {
						propertyValues = awpPagingItems[i][awpPagingFilterQuery[j]['index']].split(' ');					
						for (var x=0;x<propertyValues.length;x++) {
							if (propertyValues[x] == awpPagingFilterQuery[j]['value']) {
								okCount++;
								break;
							}
						}
					} else {
						if (awpPagingItems[i][awpPagingFilterQuery[j]['index']] == awpPagingFilterQuery[j]['value']) {
							okCount++;
						}
					}
				}
				awpPagingItems[i][gActiveFieldIndex] = (okCount == awpPagingFilterQuery.length);
			}
			// sort by the active field. descending puts the true values at beginning of sorted list.
			doSort(gActiveFieldIndex, 'boolean', 'desc');
			// find first inactive element index, splice array
			for (i=0;i<awpPagingItems.length;i++) {
				if (awpPagingItems[i][gActiveFieldIndex] != true) {
					awpPagingItemsInactive = awpPagingItems.splice(i, awpPagingItems.length - i);
					break;
				}
			}
			// update number of items, affects most everything
			gNumItems = getNumItems();
			// need to call presort
			gPreSortDone = false;
		}

		//--------------------------------------------------------------------------------
		function findDataDefColIndexByName (fieldName) {
			var i;
			for (i=0;i<settings.dataDef.length;i++) {
				if ((settings.dataDef[i].name) && (settings.dataDef[i].name == fieldName)) {
					return i;
				}
			}
			return null;
		}

		//--------------------------------------------------------------------------------
		// get filter query
		function getFilterQuery () {
			var i;
			// return if already set
			if (awpPagingFilterQuery) { return; }
			var fieldname;
			// get query data
			var data = getQuery();
			//var data = settings.query;
			//var data = awpPaging5GetQuery();
			// for each data definition field
			for (i=0;i<settings.dataDef.length;i++) {
				// data defintion field is a filter
				if ((settings.dataDef[i]['kind']) && (settings.dataDef[i]['kind'] == 'filter')) {
					// name of this data definition field
					fieldname = settings.dataDef[i]['name'];
					// check if this field name is in the query
					if (data[fieldname] && data[fieldname] != settings.noSelectionValue) {
						// add to filter query
						if (!awpPagingFilterQuery) { awpPagingFilterQuery = []; }
						awpPagingFilterQuery.push({
							'index'	: i,
							'name'	: fieldname,
							'value'	: data[fieldname],
							'multi'	: (settings.dataDef[i]['multi']) ? true : false
						});
					}
				}
			}
		}

		//--------------------------------------------------------------------------------
		// get window url query values
		function getQuery () {
			//var query = window.location.href.replace(/^[^\?]+\??/,'');
			var i;
			var query = window.location.search.substring(1);
			var data = {};
			// exit if no query string
			if (!query) { return data; }
			// split query into key/value pairs
			var pairs = query.split(/[;&]/);
			// for each pair
			for (i = 0; i < pairs.length; i++) {
				var keyval = pairs[i].split('=');
				// jump to next iteration if no result or not 2 elements
				if ( !keyval || keyval.length != 2 ) { continue; }
				// get key, value
				var key = unescape(keyval[0]);
				var val = unescape(keyval[1]);
				// replace plus sign with a space;
				val = val.replace(/\+/g, ' ');
				// set key/value into data
				data[key] = val;
			}
			return data;
		}

		//--------------------------------------------------------------------------------
		// end private functions

		//--------------------------------------------------------------------------------
		// IN: THEAD (and optionall TFOOT) with TR will exist, rowspan will be set,
		// controls html is set.

		if (isUse()) {
			// find contents table
			jTable = $(settings.tableSel).eq(0);
			// exit if paging items array is not set
			if (!(typeof awpPagingItems == 'object' && awpPagingItems !== null)) {
				jTable.hide();
				$(settings.defaultItemsSel).show();
			} else {
				getFilterQuery();
				setupDOM();
				setup();
				// init page via filter cmd or sort cmd
				if (awpPagingFilterQuery) {
					filterPageCmd();
				} else if (getSort().kind !== null) {
					// trigger sort command
					jTable
						.find(settings.controlsSortSel, settings.controlsSel)
							.trigger('change');
				} else {
					changePageCmd(0);
				}
			}
		}

		return this;

	};

})(jQuery);

