// general purpose tools

"use strict";

Function.prototype.method = function (name, func) {
	if (!this.prototype[name]) {
		this.prototype[name] = func;
		return this;
	}
};

String.method('startsWith', function (text) {
	return !this.indexOf(text);
});

Array.method('reduce', function (func, value) {
	var i;
	for (i = 0; i < this.length; i++) {
		value = func(this[i], value);
	}
	return value;
});

Number.implement({

	/*
	Property: numberFormat
		Format a number with grouped thousands.

	Arguments:
		decimals, optional - integer, number of decimal percision; default, 2
		dec_point, optional - string, decimal point notation; default, '.'
		thousands_sep, optional - string, grouped thousands notation; default, ','

	Returns:
		a formatted version of number.

	Example:
		>(36432.556).numberFormat()  // returns 36,432.56
		>(36432.556).numberFormat(2, '.', ',')  // returns 36,432.56
	*/

	numberFormat : function (decimals, dec_point, thousands_sep) {
		decimals = Math.abs(decimals) + 1 ? decimals : 2;
		dec_point = dec_point || '.';
		thousands_sep = thousands_sep || ',';

		var matches = /(-)?(\d+)(\.\d+)?/.exec((isNaN(this) ? 0 : this) + ''), // returns matches[1] as sign, matches[2] as numbers and matches[3] as decimals
			remainder = matches[2].length > 3 ? matches[2].length % 3 : 0;
		return (matches[1] ? matches[1] : '') + (remainder ? matches[2].substr(0, remainder) + thousands_sep : '') + matches[2].substr(remainder).replace(/(\d{3})(?=\d)/g, "$1" + thousands_sep) +
				(decimals ? dec_point + (+matches[3] || 0).toFixed(decimals).substr(2) : '');
	}

}); // Number.implement

var firstAmazonSearchShow = true,
	previousAmazonSearch = {
		keywords: null,
		type: null
	}; //previousAmazonSearch

function getSearchType() {
	var value = null,
		options = $$('#amazon_search_options input');
	options.each(function (option) {
		if (option.checked) {
			value = option.value;
		}
	});
	return value;
} // getSearchType

function setSearchType(type) {
	var options = $$('#amazon_search_options input');
	options.each(function (option) {
		if (option.value === type) {
			option.checked = true;
		}
	});
} // setSearchType

function execAmazonSearch(type, keywords) {
	var textbox, parameters, submitting, results;
	if (type) {
		setSearchType(type);
	}
	else {
		type = getSearchType();
	}
	if (!keywords) {
		textbox = $("amazon_search_keywords");
		keywords = textbox.value;
	}
	if (keywords
		&& (keywords !== previousAmazonSearch.keywords
			|| type !== previousAmazonSearch.type)) {
		$("amazon_search_results_container_result").setStyles({display: "none"});
		$("amazon_search_results_container_searching").setStyles({display: "block"});
		$("amazon_search_keywords").value = keywords;
		previousAmazonSearch.keywords = keywords;
		previousAmazonSearch.type = type;
		parameters = "keywords=" + keywords + "&type=" + type;
		submitting = true;
		new Request({
				method: 'get',
				link: "cancel",
				url: "/search/searchamazon.php",
				onComplete: function (response) {
						submitting = false;
						$("amazon_search_results_container_searching").setStyles({display: "none"});
						$("amazon_search_results_container_result").setStyles({display: "block"});
						results = $("amazon_search_results_container_result");
						if (response.indexOf("<tr ") > -1) {
							results.innerHTML = response;
						}
						else {
							results.innerHTML = "No matching items.";
						}
					}
			}).send(parameters); // Request
	}
	else {
		$("amazon_search_results_container_searching").setStyles({display: "none"});
		$("amazon_search_results_container_result").setStyles({display: "block"});
	}
} // execAmazonSearch

function getKeywords() {
	var keywords = getTextareaSelection();
	if (!keywords) {
		keywords = previousAmazonSearch.keywords;
	}
	return keywords;
} // getKeywords

function showContainer() {
	var container = $("amazon_search_window");
	container.fade('in');
} // showContainer

function initAmazonSearch(type) {
	var keywords = getKeywords();
	showContainer();
	execAmazonSearch(type, keywords);
} // initAmazonSearch

function MakeAmazonLink(asin, title) {
	$('amazon_search_window').fade('hide');
	var text, caption = getTextareaSelection();
	if (!caption) {
		caption = title;
	}
	text = "[url=http://www.amazon.com/dp/" + asin + "/]" + caption + "[/url]";
	postWrite(text);
} // MakeAmazonLink

function DoReply(id) {
	var message, quote = getTextareaSelection();
	if (!quote && id) {
		message = $('fb_message_' + id);
		if (message) {
			quote = $(message).getElement('.fb_text');
			quote = quote.innerText || quote.textContent || '';
			quote = quote.trim();
		}
	}
	postWrite("[quote]" + quote + "[/quote]\n\n");
} // DoReply

/*
 * AUTOGROW TEXTAREA
 * Version 1.0
 * A mooTools plugin
 * by Gary Glass (www.bookballoon.com)
 * mailto:bookballoon -at- bookballoon.com
 *
 * Based on a jQuery plugin by Chrys Bader (www.chrysbader.com).
 * Thanks to Aaron Newton for reviews and improvements.
 *
 * Copyright (c) 2009 Gary Glass (www.bookballoon.com)
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 * NOTE: This script requires mooTools. Download mooTools at mootools.net.
 *
 * USAGE:
 *		new AutoGrow(element);
 * where 'element' is a textarea element. For example:
 *		new AutoGrow($('myTextarea'));
 */
var AutoGrow = new Class({

	Implements : [Options, Events],

	options : {
		interval: 333, // update interval in milliseconds
		margin: 30, // gap (in px) to maintain between last line of text and bottom of textarea
		minHeight: 0 // minimum height of textarea
	}, // options

	initialize : function (textarea, options) {
		this.textarea = $(textarea);
		this.options.minHeight = textarea.clientHeight;
		this.setOptions(options);
		this.dummy =  new Element("div", {
			styles: {
				"overflow-x" : "hidden",
				"position"   : "absolute",
				"top"        : 0,
				"left"       : "-9999px"
			}
		})
		.setStyles(this.textarea.getStyles("font-size", "font-family", "width", "line-height", "padding"))
		.inject(document.body);
		this.resize.periodical(this.options.interval, this);
	}, // initialize

	resize : function () {
		var newHeight, triggerHeight, html = this.textarea.get('value').replace(/\n|\r\n/g, '<br>X');
		if (this.dummy.get("html").toLowerCase() !== html.toLowerCase()) {
			this.dummy.set("html", html);
			triggerHeight = this.dummy.getSize().y + this.options.margin;
			if (this.textarea.clientHeight !== triggerHeight) {
				newHeight = Math.max(this.options.minHeight, triggerHeight);
				this.textarea.tween("height", newHeight);
			}
		}
	} // resize

}); //AutoGrow

/*
	on page load, register href processors with a element handler manager.
	then manager will search posts for <a> tags with href attribs.
	manager invokes each registered callback passing it:
		the <a> element to process,
		and any other important ambient data.
	a processor will request a popout from a popout manager.
	request must include the size of the thumbnail required.
	popout manager tracks the tops of the popouts, so each one gets
	its own position.
	popout manager returns a popout object containing the element(s)
	and other data about the popout.
	processor fills in the popout's thumbnail image and content well.
	*/

var bookBalloon = (function () {

	// TODO: evaluate whether all the public members of bb need to be public

	return {

		tools : {

			getSelectedRange : function () {
				var range;
				if (document.selection) {
					range = document.selection.createRange().text;
				}
				else
				{
					range = window.getSelection();
				}
				return range;
			}, // getSelectedRange

			getSelectedText : function () {
				var text;
				if (document.getSelection) {
					text = document.getSelection();
				} else {
					text = bookBalloon.tools.getSelectedRange();
				}
				if (text.toString) {
					text = text.toString();
				}
				if (text === null || text === undefined) {
					text = "";
				}
				return text;
			} // getSelectedText

		}, // tools

		linkProcessors : {
			processors : [],
			add        : function (processor) {
				this.processors[this.processors.length] = processor;
			},
			execute    : function (link) {
				for (var i = 0; i < this.processors.length; i++) {
					this.processors[i](link);
				}
			}
		}, // linkProcessors

		linkFinder : {
			onCompleteCallbacks : [],
			handleComplete      : function (callback) {
				this.onCompleteCallbacks[this.onCompleteCallbacks.length] = callback;
			}, // handleComplete
			raiseComplete       : function () {
				for (var i = 0; i < this.onCompleteCallbacks.length; i++) {
					this.onCompleteCallbacks[i]();
				}
			}, // raiseComplete
			execute             : function () {
				$$('div[id^=fb_message_]').each(function (post) {
					// loop over links in post
					post.getElements('div.fb_text a[href]').each(function (link) {
						bookBalloon.linkProcessors.execute(link);
					});
				});
				this.raiseComplete();
			} // execute
		}, // linkFinder

		/**
		 * Defines a popout window.
		 * @param parameters  .left = absolute x position of thumbnail,
		 *                   .top = absolute y position of thumbnail,
		 *                   .height = height of thumbnail
		 *                   .id = unique identifier
		 *                   .image = popoutImages value for default thumbnail image
		 */
		Popout : function (parameters) {

			/*
				----------------------------------------
					methods
				----------------------------------------
			 */

			function makeDetails() {
				var details = new PopoutElement({
					'id'         : 'popout_details_' + that.id,
					'height'     : 0,
					'width'      : 0,
					'left'       : that.closedLeft,
					'top'        : that.top - bookBalloon.Popout.prototype.constants.detailsMargin,
					'cssClass'   : 'popout_details',
					'styles'     : {
						'opacity'   : 0,
						'padding'    : bookBalloon.Popout.prototype.constants.detailsMargin
					}
				}); // details
				makeCloser().inject(details.element);
				details.content = makeContent();
				details.content.element.inject(details.element);
				details.sidebar = makeSidebar();
				details.sidebar.element.inject(details.element);
				return details;
			} // makeDetails

			function makeCloser() {
				return new Element('div', {
					'class'   : 'popout_closer',
					'events'  : {
						'click' : that.open
					},
					'styles'  : {
						'margin-top'   : '-' + bookBalloon.Popout.prototype.constants.detailsMargin * 2 + 'px',
						'margin-right' : '-' + bookBalloon.Popout.prototype.constants.detailsMargin * 2 + 'px',
						'cursor'       : 'pointer',
						'text-align'   : 'right',
						'float'        : 'right'
					},
					'html'    : '<img src="/templates/bookballoon/images/close.png" />'
				});
			} // makeCloser

			function makeContent() {
				return new PopoutElement({
					'id'         : 'popout_content_' + that.id,
					'height'     : bookBalloon.Popout.prototype.constants.contentHeight,
					'width'      : bookBalloon.Popout.prototype.constants.contentWidth,
					'cssClass'   : 'popout_content',
					'top'        : 'auto',
					'left'       : bookBalloon.Popout.prototype.constants.detailsMargin,
					'styles'     : {
						'position'     : 'static',
						'float'        : 'left',
						'display'      : 'none'
					}
				});
			} // makeContent

			function makeSidebar() {
				return new PopoutElement({
					'id'         : 'popout_sidebar_' + that.id,
					'height'     : bookBalloon.Popout.prototype.constants.detailsHeight - parameters.height - bookBalloon.Popout.prototype.constants.detailsMargin,
					'width'      : bookBalloon.Popout.prototype.constants.sidebarWidth,
					'cssClass'   : 'popout_sidebar',
					'top'        : 'auto',
					'styles'     : {
						'position'     : 'static',
						'float'        : 'right',
						'margin-top'   : parameters.height + bookBalloon.Popout.prototype.constants.detailsMargin + 'px'
					}
				});
			} // makeSidebar

			function makeThumb() {
				return new PopoutElement({
					'id'         : 'popout_thumb_' + that.id,
					'height'     : that.height,
					'width'      : bookBalloon.Popout.prototype.constants.thumbWidth,
					'left'       : that.left,
					'top'        : that.top,
					'cssClass'   : 'popout_thumb',
					'events'     : {
						'click' : that.open
					}
				});
			} // makeThumb

			/*
				----------------------------------------
					classes
				----------------------------------------
			 */

			/**
			 * Defines an element container of a Popout.
			 * @param parameters id, left, top, height, width, cssClass, styles
			 */
			function PopoutElement(parameters) {
				this.id = parameters.id;
				this.left = parameters.left;
				this.top = parameters.top;
				this.height = parameters.height;
				this.width = parameters.width;
				this.cssClass = parameters.cssClass;
				this.element = new Element('div', {
					'id'       : this.id,
					'class'    : this.cssClass,
					'events'   : parameters.events,
					'styles'   : {
						'left'      : this.left,
						'top'       : this.top,
						'position'  : 'absolute',
						'height'    : this.height,
						'width'     : this.width
					},
					'html'     : parameters.html
				});
				this.element.set({
					'styles' : parameters.styles
				});
			} // PopoutElement

			/*
				----------------------------------------
					initialization
				----------------------------------------
			 */

			// init shared static members
			if (bookBalloon.Popout.prototype.openPopout === undefined) {
				bookBalloon.Popout.prototype.openPopout = null;
				bookBalloon.Popout.prototype.constants = {
					detailsMargin  : 15,
					thumbWidth     : 160,
					contentHeight  : '100%',
					contentWidth   : 555,
					detailsWidth   : 700,
					detailsHeight  : 450,
					sidebarWidth   : 120
				}; // bookBalloon.Popout.prototype.constants
				bookBalloon.Popout.prototype.close = function () {
					var popout = bookBalloon.Popout.prototype.openPopout;
					if (popout !== null) {
						bookBalloon.Popout.prototype.openPopout = null;
						popout.isOpen = false;
						if (typeof(popout.onClose) === 'function') {
							popout.onClose(popout);
						}
						new Chain()
							.chain(function () {
								popout.details.sidebar.element.set('styles', {
									'display' : 'none'
								});
								popout.details.content.element.set('styles', {
									'display' : 'none'
								});
								this.callChain();
							})
							.chain(function () {
								popout.thumb.element.setStyles({
										'z-index' : 0
									});
								this.callChain();
							})
							.chain(function () {
								new Fx.Morph(popout.details.element, {
										'duration': 'short'
								})
								.start({
										'left'   : that.closedLeft,
										'width'  : 0,
										'height' : 0
								})
								.chain(function () {
										popout.details.element.setStyles({
											'opacity' : 0,
											'z-index' : 0
										});
								});
							})
							.callChain();
					}
				}; // bookBalloon.Popout.prototype.close
			}
			var that = this;
			this.id = parameters.id;
			this.top = parameters.top;
			this.onClose = parameters.onClose;
			this.onOpen = parameters.onOpen;
			this.closedLeft = parameters.left + bookBalloon.Popout.prototype.constants.thumbWidth - bookBalloon.Popout.prototype.constants.detailsMargin * 3;
			this.openLeft = this.closedLeft - bookBalloon.Popout.prototype.constants.detailsWidth;
			this.isOpen = false;
			this.open = function () {
				var isOpen = that.isOpen;
				bookBalloon.Popout.prototype.close();
				if (isOpen === false) {
					that.isOpen = true;
					bookBalloon.Popout.prototype.openPopout = that;
					if (typeof(that.onOpen) === 'function') {
						that.onOpen(popout);
					}
					new Chain()
						.chain(function () {
							that.thumb.element.setStyles({
									'z-index' : 1
								});
							this.callChain();
						})
						.chain(function () {
							that.details.element.setStyles({
									'opacity' : 1,
									'z-index' : 1
								});
							this.callChain();
						})
						.chain(function () {
							new Fx.Morph(that.details.element, {
									'duration': 'short'
								})
								.start({
									'left'   : that.openLeft,
									'width'  : bookBalloon.Popout.prototype.constants.detailsWidth,
									'height' : bookBalloon.Popout.prototype.constants.detailsHeight
								})
								.chain(function () {
									that.details.content.element.set('styles', {
										'display' : 'block'
									});
									that.details.sidebar.element.set('styles', {
										'display' : 'block'
									});
								});
							this.callChain();
						})
						.callChain();
				}
			};
			this.details = makeDetails();
			this.thumb = makeThumb();
			this.highlight = function () {
				that.thumb.element.addClass('popout_highlight');
			};
			this.unhighlight = function () {
				that.thumb.element.removeClass('popout_highlight');
			};
			this.addHighlighter = function (tag) {
				tag.addEvents({
					'mouseover' : that.highlight,
					'mouseout'  : that.unhighlight
				});
			};

		}, // Popout

		popoutManager : {
			currentBottom : -1,   // bottom of previous collapsed popout
			gap           : 10,   // min vertical distance between collapsed popouts
			id            : 0,    // unique ID incrementer
			left          : null, // the left position of collapsed popouts
			leftMargin    : 5,    // gap between rightColumn left and collapsed popout left
			rightColumn   : null, // the right column element
			init          : function () {
				this.rightColumn = $('rightcolumn');
				this.left = this.rightColumn.getPosition().x + this.leftMargin;
			}, // init
			/**
			 * Creates a new popout.
			 * @param parameters top and height
			 */
			createPopout  : function (parameters) {
				this.id++;
				var popout,
					top = parameters.top;
				if (top < this.currentBottom + this.gap) {
					top = this.currentBottom + this.gap;
				}
				this.currentBottom = top + parameters.height;
				popout = new bookBalloon.Popout({
					id      : this.id,
					top     : top,
					left    : this.left,
					height  : parameters.height,
					onClose : parameters.onClose,
					onOpen  : parameters.onOpen
				}); // popout
				popout.details.element.inject(this.rightColumn);
				popout.thumb.element.inject(this.rightColumn);
				return popout;
			} // createPopout
		}, // popoutManager

		fillYoutubePopout : function (popout, id, title) {
			popout.playerid = 'youtubeplayer_' + id;
			// inject the thumbnail
			new Element('img', {
					'class'  : 'bb_item_image',
					'src'    : 'http://img.youtube.com/vi/' + id + '/default.jpg',
					'title'  : title
				})
				.inject(popout.thumb.element);
			// inject the player
			new Element('div', {
					'id'   : popout.playerid
				})
				.inject(popout.details.content.element);
			swfobject.embedSWF(
				'http://www.youtube.com/v/' + id + '&border=1&color1=800000&enablejsapi=1',
				popout.playerid,
				'100%',
				'100%',
				'9',
				null,
				null, {
					'allowscriptaccess' : 'always'
				},
				null,
				null
			); // swfobject.embedSWF
			popout.onClose = function (popout) {
				popout.details.content.element.getElementById(popout.playerid).pauseVideo();
			}; // popout.onClose

		}, // fillYoutubePopout

		amazonLinkProcessor : (function () {

			/*
			---------------------------------------
			methods
			---------------------------------------
			*/

			function fillPopouts(data) {
				var asin, tabber, popout, i, item;
				for(asin in data.items) {
					item = amazonLinks[asin];
					for(i = 0; i < item.popouts.length; i++) {
						popout = item.popouts[i];
						popout.thumb.element.set('html', data.items[asin].item_data1);
						popout.details.content.element.set('html', data.items[asin].item_data2);
						tabber = popout.details.content.element.getElement('div.tabber');
						new tabberObj({
							'div' : tabber
						});
						popout.details.sidebar.element.set('html', data.items[asin].item_data3);
						popout.addHighlighter(item.links[i]);
					}
				}
			} // fillPopouts

			function putStats(data) {
				var html = ' fromCache = '  + data.counts.fromCache
					+ ', new = '       + data.counts['new']
					+ ', expired = '   + data.counts.expired
					+ ', duplicate = ' + data.counts.duplicate
					+ ', total = '     + data.counts.total;
				document.body.grab(new Element('span', {
					'styles' : {
						'display' : 'none'
					},
					'html' : html
				}));
			} // putStats

			/*
			---------------------------------------
			fields
			---------------------------------------
			*/

			var amazonLinks = [];

			/*
			---------------------------------------
			initialization
			---------------------------------------
			*/

			return {
				processor : function (link) {
					var popout,
						length,
						asins = null,
						asin = null,
						thumbHeight = 120,
						re = /(?:\/(dp|product)\/\w+)/i, // gets the asin from an amazon url
						href = link.get('href');
					if (href && href.toLowerCase().indexOf('amazon') > -1) {
						asins = re.exec(href);
						if (asins && asins.length > 0) {
							asin = asins[0];
							if (asin !== null) {
								if (asin.startsWith('/dp/')) {
									asin = asin.substr(4); // strip '/dp/' from string
								}
								else if (asin.startsWith('/product/')) {
									asin = asin.substr(9); // strip '/product/' from string
								}
								else {
									asin = null;
								}
								if (asin !== null) {
									popout = bookBalloon.popoutManager.createPopout({
										'top'      : link.getPosition().y,
										'height'   : thumbHeight
									}); // popout
									if (amazonLinks[asin]) {
										length = amazonLinks[asin].links.length;
										amazonLinks[asin].links[length] = link;
										amazonLinks[asin].popouts[length] = popout;
									} else {
										amazonLinks[asin] = {
											'asin'    : asin,
											'links'   : [link],
											'popouts' : [popout]
										};
									}
								}
							}
						}
					}
				}, // processor

				onComplete : function () {
					var key, link, asins = '', i = 0;
					for (key in amazonLinks) {
						if (amazonLinks.hasOwnProperty(key)
							&& typeof(amazonLinks[key] !== 'function')) {
							link = amazonLinks[key];
							if (i > 0) {
								asins += '+';
							}
							asins += link.asin;
							i++;
						}
					}
					new Request.JSON({
						secure        : true,
						data          : {
							'option' : 'com_bbservices',
							'task'   : 'amazon',
							'asin'   : asins
						},
						'method'      : 'get',
						'link'        : 'chain',
						'url'         : '/',
						'format'      : 'raw',
						onSuccess     : function (data) {
							fillPopouts(data);
							putStats(data);
						} // onSuccess
					}).send(); // Request.JSON
				}, // onComplete
				start : function () {
					bookBalloon.linkProcessors.add(this.processor);
					bookBalloon.linkFinder.handleComplete(this.onComplete);
				} // start

			}; // return

		}()), // amazonLinkProcessor

		executeLinkProcessors : function () {
			bookBalloon.popoutManager.init();
			//
			// amazon link processor
			//
			bookBalloon.amazonLinkProcessor.start();
			//
			// youtube link processor
			//
			bookBalloon.linkProcessors.add(function (link) {
				var ids,
					id,
					popout,
					re = /(\?v|\&v)\=[a-zA-Z0-9\-\_]+&??/i, // gets the video id from a youtube url
					href = link.get('href');
				if (href && href.toLowerCase().indexOf('youtube.com') > -1) {
					ids = re.exec(href);
					if (ids && ids.length > 0) {
						id = ids[0].substr(3); // strip '/v=' from string
						if (id !== null) {
							popout = bookBalloon.popoutManager.createPopout({
								'top'      : link.getPosition().y,
								'height'   : 90
							});
							bookBalloon.fillYoutubePopout(popout, id, link.get('text'));
							popout.addHighlighter(link);
						}
					}
				}
			}); // bookBalloon.linkProcessors.add

			//
			// go
			//
			bookBalloon.linkFinder.execute();
		} // executeLinkProcessors

	}; // return

}()); // bookBalloon

window.addEvent('domready', function () {
	var button = $("amazon_search_button"), container = $("amazon_search_window");
	if (container) {
		container.fade('hide');
		container.setStyles({
			top: button.getPosition().y + button.getSize().y,
			left: button.getPosition().x
		});
	}
	if (milestone !== null
			&& milestone !== undefined) {
		milestone.init();
	}
}); // window.addEvent

function DelayAddPopouts() {
	window.setTimeout(bookBalloon.executeLinkProcessors, 500);
} // DelayAddPopouts

