/**
 * This file contains the make_pagination() function.
 *
 * READ THIS:
 * There are two versions of this function in this file.  One of them is
 * commented and the other one is not.  You should copy the uncommented one
 * to your own application's JavaScript file.
 *
 * 
 * INSTRUCTIONS --------------------------------=============================
 *
 *   1) You should know how to include JavaScript in your web page, and have
 *      already done that with the make_pagination() function below.
 *
 *   2) Create an empty <div> for the pagination.  Give it an id="" attribute
 *      with a unique name:
 *
 *			<div id="pagination"></div>
 *
 *   3) Put the following JavaScript somewhere:
 *
 *			make_pagination('pagination', '', 1, 300);
 *
 *      Tip: go ahead and put it inside the div block.  In PHP, I do this:
 *
 *			echo '<div id="pagination1">'.
 *				'<script type="text/javascript">'.
 *				make_pagination("pagination1", "", '.
 *				$page_number .', '.
 *				$max_page_number.
 *				');</script></div>';
 *
 * CAVEATS --------------------------------==================================
 *
 *    If JavaScript is disabled, nothing happens.  You could add something
 *    like this:
 *
 *		<noscript><a href="">No JavaScript?</a></noscript>
 *
 *    Hell, put it inside the pagination div.  Set the link to something that
 *    will set a "JavaScript disabled" cookie, and use the php alternative I
 *    have posted at http://zablocky.org/pagination.php instead.
 *
 *
 */




/**
 * Creates pagination links and dumps them to the indicated div
 *
 *
 * @author brian@zablocky.org
 * @version 1.3 
 */
function make_pagination_commented(target_div, url_base, page_number, total_pages)
{
	/**
	 * If the total pagers are smaller than this, show all links.
	 *
	 * Once the link count gets above this point, this function will switch
	 * to gapped pagination, where powers of 10 and extra links come into
	 * play.  You can set this value to something like 100,000 if you want
	 * to always show full links.
	 */
	var full_link_threshold = 20;
	

	/**
	 * How many extra links to surround key page numbers with
	 * 
	 * Key page numbers are the first page, last page, and current page.
	 * You can set this to the number of extra links you want to pad these
	 * key page numbers with.  Here are some examples with 20 pages:
	 *
	 *		0		 << ... 10 15 20 >> 
	 * 		1		 << 1 ... 10 ... 14 15 16 ... 20 ... 21 >> 
	 *		2		 << 1 2 ... 10 ... 13 14 15 16 17 ... 20 21 >>
	 *		3		 << 1 2 3 ... 10 ... 12 13 14 15 16 17 18 19 20 21 >> 
	 *
	 *
	 * I designed this paginator with two extra links in mind.
	 *
	 */
	var extra_links = 2;


	/**
	 * This is a very difficult to explain number.
	 *
	 * A number which is important to spreading out the links is the number of
	 * digits in the number.  We take this number, the place value of the total
	 * pages, and multiply it by the spread multiplier.  If the result is less
	 * than the total pages, we spread the links based on the previous place
	 * value.  
	 *
	 * Example:  With 300 pages, the place value is 100.  A spread multiplier
	 * of 1.6 means that at least 160 pages are needed to spread them by
	 * multiples of 100.  Otherwise, they are spread in 10s.  
	 *
	 * Better example:  Consider 150 pages with the same spread of 1.6.  We
	 * will see the following links:
	 *
	 *		 << 1 2 3 4 5 ... 10 20 30 40 50 60 70 80 90 100 110 120 130 140 ... 149 150 >>
	 *
	 * By reducing the spread multiplier to 1.4, the following happens:
	 *
	 *		 << 1 2 3 4 5 ... 100 ... 149 150 >>
	 *
	 * Note that even though the links generated are more compact, it is harder
	 * jump around when the spread_multiplier is higher.  Logically, setting a
	 * spread_multiplier to 1 will make it so the highest place value is
	 * always chosen.
	 *
	 * 
	 */
	var spread_multiplier = 1.8;


	/**
	 * Which CSS class to use for all the pagination stuff.
	 *
	 * There are three tags:  <div>, <span>, and <a> that will be
	 * given this class name.  You can define a css file to change
	 * the appearance of the pagination links this way.
	 */
	var css_class = 'pagination';


	/**
	 * What label to use for the previous page
	 */
	var previous_page_label = 'Prev';


	/**
	 * What label to use for the next page
	 */
	var next_page_label = 'Next';


	/**
	 * What valid css color to use for disabled page links
	 */
	var disabled_color = 'silver';


	/**
	 * What to use in place of ellipses in between gaps.
	 */
	var ellipses = '...';









	//
	// -----------------------------------------------------------------
	//
	//  Editing below this line is not recommended for beginners
	//
	// =================================================================
	// 





















	/**
	 * Whether or not we are using internet explorer
	 */
	var isIE = false;

	if (window.ActiveXObject)
	{
		// TODO: Opera supports window.ActiveXObject, so now what?
		isIE = true;
	}

	
	// We will now define all the variables used within this function.
	// Every one of them is defined here ahead of time before they are
	// used.  This is to facilitate converting this function to various
	// other languages.








	/**
	 * The left part of the url we are building
	 */
	var url_start = '';

	/**
	 * The right part of the url we are building
	 */
	var url_end = '';
	
	/**
	 * A (hopefully) unique number in case of multiple paginators
	 */
	var id_magic = Math.floor(Math.random() * 10000);

	/**
	 * The smallest link to pad from the left of the current page.
	 */
	var min_page_small = (parseInt(page_number) - extra_links);
	
	/**
	 * The largest link to pad from the right of the current page.
	 */
	var max_page_small = (parseInt(page_number) + extra_links);
	
	/**
	 * The number of zeroes in the expression, minimum 1
	 */	
	var number_of_zeroes = 1;
	
	/**
	 * The place value to use for determining spread
	 */
	var place_value = 10;
	
	/**
	 * Whether or not to show ellipses before the link
	 */
	var show_ellipses = false;
	
	/**
	 * Whether or not the link we want to print is an enabled link
	 */ 
	var is_link = false;
	
	/**
	 * Whether or not link we want to print is close to the page_number
	 */
	var was_close = false;
	
	/**
	 * Whether or not page number is multiple of place_value
	 */
	var was_power = false;
	
	/**
	 * Whether or not the last page number printed was the first or last page
	 */
	var was_tail = true;

	/**
	 * Whether or not we had to skip some page numbers
	 */
	var is_gap = false;
	
	/**
	 * How many times have we have iterated through a while loop
	 */
	var iteration_count = 0;
	
	/**
	 * A simple loop counter
	 *
	 * See the discussion in the while {} loop below.
	 */
	var i = 0;
	
	/**
	 * The output div object we will be appending all the other stuff to
	 */
	var output_dom = document.createElement('div');
	
	/**
	 * The next multiple of the place value we are looking for
	 */
	var next_power = 0;
	
	
	
	






	
	
	//
	// -----------------------------------------------------------------
	//
	//  The actual application starts here.
	//
	// =================================================================
	// 

	
	
	
	// Set up the url components for creating the links
	
	// We use a left component and a right component, then make a 
	// page_number sandwich when a url is needed.

	if ((null == url_base) || ("" == url_base))
	{
		// The dev did not supply a url_base
		
		// We are going to assume we are in "debug" mode and make a 
		// "loopback" to our own function.  This is how the code acts
		// at http://zablocky.org/pagination.php
		
		url_start = "JavaScript:make_pagination('" + target_div + "','','";
		url_end   = "', '" + total_pages + "');";
	}
	else
	{
		// The dev supplied a url base, so we use it
	
		// TODO: detect a javascript url base
	
		url_start = url_base;
		url_end   = ""; 
	}
	




	// We want to give ourselves some wiggling room if the current
	// page happens to be close to the tails (first or last page
	// numbers).  These next two if statements will make the padding
	// around the current page number bigger.
	
	// Note that even if these numbers are out of page range, the
	// application functions correctly.  No further error checking
	// is necessary at this point.
	
	if (max_page_small > total_pages)
	{
		// current_page is close to total_pages
		// give more left padding
		min_page_small = min_page_small - (max_page_small - total_pages);
	}
	
	if (min_page_small < 1)
	{
		// current_page is close to 1
		// give more right padding
		max_page_small = max_page_small + (1 - min_page_small);
	}

	



	// We need to find out the place value of the total
	// pages number.  To do this, we take the base 10 log
	// of the number and round it down.  This gives us the
	// number of digits after the first one (kind of).
	
	number_of_zeroes = Math.max(1, Math.floor(Math.log(total_pages) / Math.log(10)));
	place_value = Math.pow(10, number_of_zeroes);


	// The place value for 356 pages is 100; for 790 pages
	// it is also 100.  For 1284 pages, it is 1000.  Etc.

	if ((place_value * spread_multiplier) > total_pages)
	{
		// Reduce the number of zeroes and recalculate the place
		// value.  This gives us more page links in between with
		// smaller powers of ten.
		
		number_of_zeroes -= 1;
		place_value = Math.pow(10, number_of_zeroes);
	}
	













	// --------------------------------- FIRST STEP
	// Create the "previous page" link, which by
	// default looks like "<<"

	if (page_number > 1)
	{
		var a = document.createElement('a');
		a.setAttribute('href', url_start + (page_number - 1) + url_end);
		
		if (isIE) { a.style.textDecoration = 'none'; } else { a.setAttribute('style', 'text-decoration: none;'); }
	}
	else
	{
		var a = document.createElement('span');		
		if (isIE) { a.style.textDecoration = 'none'; a.style.color = disabled_color; } else { a.setAttribute('style', 'text-decoration: none; color: ' + disabled_color + ';'); }
	}
	
	a.className = css_class;
	a.appendChild(document.createTextNode(previous_page_label));
	
	output_dom.appendChild(document.createTextNode(" "));
	output_dom.appendChild(a);
	output_dom.appendChild(document.createTextNode(" "));
		
	
	
	
 	






















	// --------------------------------- NEXT STEP
	// Create the page links one at a time, jumping
	// around as needed to make them look good
	
	// I am specifically using a while loop to iterate instead
	// of a for loop.  The variable "i" changes dynamically
	// throughout the loop, and when you "continue" a "for",
	// the variable is automatically incremented.  We don't
	// want this behavior (even though it appears that we do).
	
	// Trust me, there is a weirdness involved with using for
	// here instead of while.
	
	
	while (true)
	{
		i += 1;
		if (i > total_pages) { break; }


		// Increment the iteration counter.  This is different than
		// the loop counter because the variable "i" can increment
		// more than once in a pass.  The iteration counter keeps
		// a running tally of full passes.  	
		iteration_count += 1;
		
	
		// The next complex if statement will determine what we need
		// to output to the dom.  We use a handful of flags and try
		// different steps one at a time.  If all of them fail, the
		// final catch will *alter the value of i*, causing the loop
		// to jump around a bit. 
	
		if (i == page_number)
		{
			// This is the current page.  We don't want to display
			// a link, but perhaps a bold number.
			
			is_link = false;
			was_close = true;
		}
		else if (total_pages <= full_link_threshold)
		{
			// Simply show a link.  Every time we loop we will
			// hit this same block (because total_pages doesn't
			// change), so there is no reason to set other
			// flags here
			 
			is_link = true;
		}
		else if ((i >= min_page_small) && (i <= max_page_small))
		{
			// We are close to the current page, but obviously not
			// the current page.  Woe is us!
		
			// This next monster says we will show the ellipses if we
			// are neither a tail or close to it, or if we gapped from the 
			// last page number link printed.
		
			show_ellipses = (!was_close && !was_tail) || is_gap;
		
			is_link = true;
			was_close = true;
			was_power = false;
			was_tail = false;
			is_gap = false;
		}
		else if (   ((i >= 1) && (i <= extra_links))
				||  ((i >= (total_pages - extra_links + 1)) && (i <= total_pages))
				)
		{
			// How you like me now?  This last elseif simply checks to
			// see if we are close to the tails, or if we are the tails
			// (remember: tails are the first and last page numbers).
		
			// Show ellipses if last number was a power of 10 (or a multiple
			// of one) or if we gapped from the last page number
			
			show_ellipses = was_power || is_gap;
		
			is_link = true;
			was_close = false;
			was_power = false;
			was_tail = true;
			is_gap = false;
		}
		else if (i % place_value == 0)
		{
			// This number is a multiple of place_value.  We just show the
			// ellipses if the last number was not a multiple of place value
			
			show_ellipses = !was_power;
			
			is_link = true;
			was_close = false;
			was_power = true;
			was_tail = false;
			is_gap = false;
		}
		else
		{
			// -------------------------------------------------------------
			// The number is not going to be printed.  We will take this
			// opportunity to predict the next number that will. With this 
			// step, we allow things like having a million total pages and
			// being on page 342,112 with no performance problems.
		
			// The general idea is to find the smallest number which fits
			// some of the previous tests.
		
			// Test 1:  The next multiple of place value greater than the
			// current number (this is a spiffy formula).
			next_power = i - (i % place_value) + place_value;
			
			// Tests 2 thru 4:
			i = Math.min(
				(min_page_small > i) ? (min_page_small - 1) : (total_pages - extra_links),
				(next_power     > i) ? (next_power     - 1) : (total_pages - extra_links)
			);
			
			is_gap = true;
			continue;
		}
		
		
		// If we made it to this point, we are appending something to the
		// output_dom object, so the following code is mostly related to
		// appending child objects.
		
		
		// The ellipses are the "..." in between page number gaps
		if (show_ellipses) { output_dom.appendChild(document.createTextNode(" " + ellipses)); show_ellipses = false; }
		
		
		if (is_link)
		{
			// Create an anchor and set the url
			var a = document.createElement('a');
			a.setAttribute('href', url_start + i + url_end);
		}
		else
		{
			// Create a span and style it according to the browser
			var a = document.createElement('span');			
			if (isIE) { a.style.fontWeight = 'bold'; a.id='page_'+i } else { a.setAttribute('style', 'font-weight: bold;');
			a.setAttribute('id', 'page_'+i); }
		}
		
		
		a.className = css_class;
		a.appendChild(document.createTextNode(i));
		
		output_dom.appendChild(document.createTextNode(" "));
		output_dom.appendChild(a);
		output_dom.appendChild(document.createTextNode(" "));
	}








	// --------------------------------- NEXT STEP
	// Create the "next page" link, which by
	// default looks like ">>"
	
	if ((parseInt(page_number) + 1) <= total_pages)
	{
		var a = document.createElement('a');
		a.setAttribute('href', url_start + (parseInt(page_number) + 1) + url_end);
		
		if (isIE) { a.style.textDecoration = 'none'; } else { a.setAttribute('style', 'text-decoration: none;'); }
	}
	else
	{
		var a = document.createElement('span');		
		if (isIE) { a.style.textDecoration = 'none'; a.style.color = disabled_color; } else { a.setAttribute('style', 'text-decoration: none; color: ' + disabled_color + ';'); }
	}
	
	
	a.className = css_class;
	a.appendChild(document.createTextNode(next_page_label));
	
	output_dom.appendChild(document.createTextNode(" "));
	output_dom.appendChild(a);
	output_dom.appendChild(document.createTextNode(" "));
	
	
	
	
	output_dom.setAttribute('id', 'inner_pagination_' + id_magic);
	output_dom.className = css_class;
	
	
	
	target_dom = document.getElementById(target_div);
	target_dom.innerHTML = '';
	target_dom.appendChild(output_dom);
}
	
	






























/**
 * Creates pagination links and dumps them to the indicated div
 *
 *
 * @author brian@zablocky.org
 * @version 1.3 
 */
function make_pagination(target_div, url_base, page_number, total_pages)
{
	var full_link_threshold = 20;
	var extra_links = 2;
	var spread_multiplier = 1.8;
	var css_class = 'pagination';
	var previous_page_label = 'Prev';
	var next_page_label = 'Next';
	var disabled_color = 'silver';
	var ellipses = '...';

	var isIE = false;
	if (window.ActiveXObject) { isIE = true; }

	var url_start = '';
	var url_end = '';
	var id_magic = Math.floor(Math.random() * 10000);
	var min_page_small = (parseInt(page_number) - extra_links);
	var max_page_small = (parseInt(page_number) + extra_links);
	var number_of_zeroes = 1;
	var place_value = 10;
	var show_ellipses = false;
	var is_link = false;
	var was_close = false;
	var was_power = false;
	var was_tail = true;
	var is_gap = false;
	var iteration_count = 0;
	var i = 0;
	var output_dom = document.createElement('div');
	var next_power = 0;
	
	if ((null == url_base) || ("" == url_base))
	{
		url_start = "JavaScript:make_pagination('" + target_div + "','','";
		url_end   = "', '" + total_pages + "');";
	}
	else
	{
		url_start = url_base;
		url_end   = ""; 
	}

	
	if (max_page_small > total_pages)
	{
		min_page_small = min_page_small - (max_page_small - total_pages);
	}
	
	if (min_page_small < 1)
	{
		max_page_small = max_page_small + (1 - min_page_small);
	}

	number_of_zeroes = Math.max(1, Math.floor(Math.log(total_pages) / Math.log(10)));
	place_value = Math.pow(10, number_of_zeroes);


	if ((place_value * spread_multiplier) > total_pages)
	{
		number_of_zeroes -= 1;
		place_value = Math.pow(10, number_of_zeroes);
	}
	

	if (page_number > 1)
	{
		var a = document.createElement('a');
		a.setAttribute('href', url_start + (page_number - 1) + url_end);
		
		if (isIE) { a.style.textDecoration = 'none'; } else { a.setAttribute('style', 'text-decoration: none;'); }
	}
	else
	{
		var a = document.createElement('span');		
		if (isIE) { a.style.textDecoration = 'none'; a.style.color = disabled_color; } else { a.setAttribute('style', 'text-decoration: none; color: ' + disabled_color + ';'); }
	}
	
	a.className = css_class;
	a.appendChild(document.createTextNode(previous_page_label));
	
	output_dom.appendChild(document.createTextNode(" "));
	output_dom.appendChild(a);
	output_dom.appendChild(document.createTextNode(" "));
		
	
	while (true)
	{
		i += 1;
		if (i > total_pages) { break; }

		iteration_count += 1;
		
		if (i == page_number)
		{
			is_link = false;
			was_close = true;
		}
		else if (total_pages <= full_link_threshold)
		{
			is_link = true;
		}
		else if ((i >= min_page_small) && (i <= max_page_small))
		{
			show_ellipses = (!was_close && !was_tail) || is_gap;
		
			is_link = true;
			was_close = true;
			was_power = false;
			was_tail = false;
			is_gap = false;
		}
		else if (   ((i >= 1) && (i <= extra_links))
				||  ((i >= (total_pages - extra_links + 1)) && (i <= total_pages))
				)
		{
			show_ellipses = was_power || is_gap;
		
			is_link = true;
			was_close = false;
			was_power = false;
			was_tail = true;
			is_gap = false;
		}
		else if (i % place_value == 0)
		{
			show_ellipses = !was_power;
			
			is_link = true;
			was_close = false;
			was_power = true;
			was_tail = false;
			is_gap = false;
		}
		else
		{
			next_power = i - (i % place_value) + place_value;
			
			i = Math.min(
				(min_page_small > i) ? (min_page_small - 1) : (total_pages - extra_links),
				(next_power     > i) ? (next_power     - 1) : (total_pages - extra_links)
			);
			
			is_gap = true;
			continue;
		}
		
		if (show_ellipses) { output_dom.appendChild(document.createTextNode(" " + ellipses)); show_ellipses = false; }
		
		
		if (is_link)
		{
			var a = document.createElement('a');
			a.setAttribute('href', url_start + i + url_end);
		}
		else
		{
			var a = document.createElement('span');			
				if (isIE) { a.style.fontWeight = 'bold'; a.id='page_'+i } else { a.setAttribute('style', 'font-weight: bold;');
			a.setAttribute('id', 'page_'+i); }
		}
		
		
		a.className = css_class;
		a.appendChild(document.createTextNode(i));
		
		output_dom.appendChild(document.createTextNode(" "));
		output_dom.appendChild(a);
		output_dom.appendChild(document.createTextNode(" "));
	}

	if ((parseInt(page_number) + 1) <= total_pages)
	{
		var a = document.createElement('a');
		a.setAttribute('href', url_start + (parseInt(page_number) + 1) + url_end);
		
		if (isIE) { a.style.textDecoration = 'none'; } else { a.setAttribute('style', 'text-decoration: none;'); }
	}
	else
	{
		var a = document.createElement('span');		
		if (isIE) { a.style.textDecoration = 'none'; a.style.color = disabled_color; } else { a.setAttribute('style', 'text-decoration: none; color: ' + disabled_color + ';'); }
	}
	
	a.className = css_class;
	a.appendChild(document.createTextNode(next_page_label));
	
	output_dom.appendChild(document.createTextNode(" "));
	output_dom.appendChild(a);
	output_dom.appendChild(document.createTextNode(" "));

	output_dom.setAttribute('id', 'inner_pagination_' + id_magic);
	output_dom.className = css_class;

	target_dom = document.getElementById(target_div);
	target_dom.innerHTML = '';
	target_dom.appendChild(output_dom);

}
	




