/**
 * iBegin Share 2.6 (Build 1606)
 * For more info & download: http://www.ibegin.com/labs/share/
 * Created as a part of the iBegin Labs Project - http://www.ibegin.com/labs/
 * For licensing please see readme.html (MIT Open Source License)
*/

var iBeginShare = function() {
	var _pub = {
		// Change this to your base URL
		// This only affects a couple plugins, and realistically should be removed
		// from the share framework.
		base_url: './',
		
		// Default skin values
		default_skin: 'default',
		default_link: 'button',
		default_link_skin: 'default',
		
		// Set script handler to the relative path of the script which will handle
		// stats logging.
		// This is very limited at the moment, if you want to create a new backend
		// please contact us first for support, so we may improve upon this.
		script_handler: false,

		// The little thing that appears in the corner to close the box.
		close_label: 'X',

		// The label which appears for both included widgets.
		text_link_label: 'Share',
		
		// STOP EDITING
		// These are replaced by our automagic subversion handler with the current
		// tag and revision.
		version_number: '2.6',
		build_number: '1606',
		
		// Don't you love browser inconsistencies?
		is_opera: navigator.userAgent.indexOf('Opera/9') != -1,
		is_ie: navigator.userAgent.indexOf("MSIE ") != -1,
		is_safari: navigator.userAgent.indexOf('webkit') != -1,
		is_ie6: false /*@cc_on || @_jscript_version < 5.7 @*/,
		is_firefox: navigator.appName == "Netscape" && navigator.userAgent.indexOf("Gecko") != -1 && navigator.userAgent.indexOf("Netscape") == -1,
		is_mac: navigator.userAgent.indexOf('Macintosh') != -1,
		http: null,

		/**
		 * Generic function to enable the default PHP logging platform
		 * This has to be called after `base_url` is set.
		 */
		enableStats: function() {
			_pub.script_handler = _pub.base_url + 'share.php?action=log';
		},
		/**
		 * Creates an HTML element.
		 */
		createElement: function(tag, params) {
			var el = document.createElement(tag);
			if (!params) return el;
			for (var key in params) {
				if (key == 'className') el.className = params[key];
				else if (key == 'text') el.appendChild(document.createTextNode(params[key]));
				else if (key == 'html') el.innerHTML = params[key];
				else if (key == 'id') el.id = params[key];
				else if (key == 'children') continue;
				else if (key == 'events') {
					for (var name in params[key]) _pub.addEvent(el, name, params[key][name]);
				}
				else if (key == 'styles') {
					for (var name in params[key]) {
						el.style[name] = params[key][name];
					}
				}
				else el.setAttribute(key, params[key]);
			}
			if (params.children) for (var i=0; i<params.children.length; i++) el.appendChild(params.children[i]);
			return el;
		},
		/**
		 * Parses the arguments in the rel attribute
		 * @param {String} query
		 */
		parseQuery: function(query) {
			 var params = new Object();
			 if (!query) return params; 
			 var pairs = query.split(/[;&]/);
			 var end_token;
			 for (var i=0; i<pairs.length; i++) {
					var keyval = pairs[i].split('=');
					if (!keyval || keyval.length != 2) continue;
					var key = unescape(keyval[0]);
					var val = unescape(keyval[1]);
					val = val.replace(/\+/g, ' ');
					if (val[0] == '"') var token = '"';
					else if (val[0] == "'") var token = "'";
					else var token = null;
					if (token) {
						if (val[val.length-1] != token) {
							do {
								i += 1;
								val += '&'+pairs[i];
							}
							while ((end_token = pairs[i][pairs[i].length-1]) != token)
						}
						val = val.substr(1, val.length-2);
					}
					if (val == 'true') val = true;
					else if (val == 'false') val = false;
					else if (val == 'null') val = null;
					params[key] = val;
			 }
			 return params;
		},
		/**
		 * Serializes form elements into an object-array.
		 * @return {Object}
		 */
		serializeFormData: function(form) {
				var data = {};
				var els = form.getElementsByTagName('input');
				for (var i=0, el=null; (el=els[i]); i++) {
						if (el.name) {
								if (el.type == 'text' || el.type == 'hidden' || el.type == 'password'
										|| ((el.type == 'radio' || el.type == 'checkbox') && el.checked))
										data[el.name] = encodeURIComponent(el.value);
						}
				}
				var els = form.getElementsByTagName('textarea');
				for (var i=0, el=null; (el=els[i]); i++) {
						if (el.name) data[el.name] = encodeURIComponent(el.value);
				}
				var els = form.getElementsByTagName('select');
				for (var i=0, el=null; (el=els[i]); i++) {
						if (el.name) data[el.name] = encodeURIComponent(el[el.selectedIndex].value);
				}
				return data;
		},
		/**
		 * Returns a string that is considered safe for keys and slugs.
		 * @param {String} string
		 * @return {String} string
		 */
		makeSafeString: function(string) {
			return string.replace(/[^a-zA-Z0-9_-s.]/, '').toLowerCase()
		},
		/**
		 * Outputs a GET parameter string from an object array.
		 * @param {Object} params
		 * @return {String}
		 */
		createParametersString: function(params) {
			var parameters = ''; // string version of params
			for (var key in params) {
					if (typeof params[key] == 'object')
							for (var i=0; i<params[key].length; i++)
									parameters += (key + '=' + encodeURIComponent(params[key][i]) + '&');
					else
							parameters += (key + '=' + encodeURIComponent(params[key]) + '&');
			}
			return parameters;
		},
		/**
		 * Initiates an XMLHttpRequest and executes callback(responseText)
		 * @param {String} url Request url
		 * @param {Object} params Request parameters in an object-array format
		 * @param {Function} success Successful callback function
		 * @param {Function} error Error callback function
		 */
		ajaxRequest: function(url, method, params, success, error) {
			if (!method) var method = 'GET';
			var parameters = _pub.createParametersString(params);
			if (method == 'GET' && parameters) {
				if (url.indexOf('?')) url += '&' + parameters;
				else url += '?' + parameters;
			}
			_pub.http.open(method, url, true);
			_pub.http.onreadystatechange = function() {
					if (_pub.http.readyState == 4) {
							if (_pub.http.status == 200)
									success(_pub.http.responseText);
							else
									if (error)
											error(_pub.http, _pub.http.responseText);
					}
			}
			_pub.http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
			if (method == 'POST') _pub.http.setRequestHeader("Content-length", parameters.length);
			_pub.http.setRequestHeader("Connection", "close");
			_pub.http.send(parameters);
		},
		showLoadingBar: function() {
			containers.loading.style.display = 'block';
			containers.content_inner.style.display = 'none';
		},
		hideLoadingBar: function() {
			containers.loading.style.display = 'none';
			containers.content_inner.style.display = 'block';
		},
		hasClass: function(obj, className) {
				if (obj.className) {
						var arrList = obj.className.split(' ');
						var strClassUpper = className.toUpperCase();

						for (var i=0; i<arrList.length; i++) {
								if (arrList[i].toUpperCase() == strClassUpper) {
										return true;
								}
						}
				}
				return false;
		},
		toggleClass: function(obj, className) {
			if (_pub.hasClass(obj, className)) _pub.removeClass(obj, className);
			else _pub.addClass(obj, className);
		},
		addClass: function(obj, className) {
			obj.className = (obj.className ? obj.className + ' ' + className : className);
		},
		removeClass: function(obj, className) {
			if (obj.className) {
				var arrList = obj.className.split(' ');
				var strClassUpper = className.toUpperCase();

				for (var i=0; i<arrList.length; i++) {
					if (arrList[i].toUpperCase() == strClassUpper) {
						arrList.splice(i, 1);
						i--;
					}
				}
				obj.className = arrList.join(' ');
			}
		},
		/**
		 * Empties the content of an object.
		 */
		empty: function(obj) {
			while (obj.firstChild) obj.removeChild(obj.firstChild);
		},
		/**
		 * Updates the content of the share box
		 * @param {HTMLObject|String} html
		 */
		html: function(html) {
			if (!html) return;
			_pub.hideLoadingBar();
			_pub.empty(containers.content_inner);
			if (typeof(html) == 'string') containers.content_inner.innerHTML = html;
			else containers.content_inner.appendChild(html);
		},
		/**
		 * Hides the share box.
		 */
		hide: function() {
			if (active.tab && active.tab.plugin.unload) active.tab.plugin.unload();
			if (active.link) _pub.removeClass(active.link, 'share-active');
			active = {}
			containers.box.style.display = 'none';
			_pub.addClass(containers.box, 'share-box-show');
		},
		/**
		 * Shows the share box and (if obj is present) positions
		 * it relative to the container.
		 * @param {HTMLObject} obj
		 * @param {Object} params
		 */
		show: function(obj, params) {
			// if no plugins are active bail
			if (!_pub.plugins.list.length) return false;
			// if the current link is active bail
			if (active.link == obj) return false;

			if (!params) var params = {};
			
			if (!params.link) params.link = window.location.href;
			if (!params.title) params.title = document.title;
			if (!params.skin) params.skin = _pub.default_skin;
			
			// hide it first to stop the bug where active button still shows
			if (active.link) _pub.hide();

			active.link = obj;
			active.link.params = params;

			_pub.addClass(obj, 'share-active');
			
			if (!params.skin) params.skin = 'default';
						
			containers.box.className = 'share-skin-' + params.skin;
			
			containers.box.style.position = 'absolute';
			containers.box.style.display = 'block';
			containers.box.style.visibility = 'hidden';
			containers.box.style.top = 0;
			containers.box.style.left = 0;

			var curtop = curleft = 0;
			var border;
			curtop += obj.offsetHeight + 5;
			if (obj.getBoundingClientRect) {
				var bounds = obj.getBoundingClientRect();
				curleft += bounds.left - 2;
				curtop += bounds.top + document.documentElement.scrollTop - 2;
			}
			else if (obj.offsetParent) {
				do {
					// XXX: If the element is position: relative we have to add borderWidth
					if (_pub.getStyle(obj, 'position') == 'relative') {
						if (border = _pub.getStyle(obj, 'border-top-width')) curtop += parseInt(border);
						if (border = _pub.getStyle(obj, 'border-left-width')) curleft += parseInt(border);
					}
					else if (obj.currentStyle && obj.currentStyle.hasLayout && obj !== document.body) {
						curleft += obj.clientLeft;
						curtop += obj.clientTop;
					}

					curtop += obj.offsetTop;
					curleft += obj.offsetLeft;
				}
				while (obj = obj.offsetParent)
			}
			else if (obj.x) {
				curtop += obj.y;
				curleft += obj.x;
			}
			
			pagesize = _pub.getPageSize();
			if (containers.box.offsetWidth + curleft > pagesize.width) {
				// if the box is larger than the page width, set it to 20px on the left
				if (containers.box.offsetWidth > pagesize.width-20) {
				 curleft = 20;
				}
				else {
					// otherwise set it to page width - box length - 20px
					curleft = pagesize.width-20-containers.box.offsetWidth;
				}
			}
			containers.box.style.top = curtop + 'px';
			containers.box.style.left = curleft + 'px';
			containers.box.style.visibility = 'visible';
			_pub.removeClass(containers.box, 'share-box-show');

			for (var i=0; i<_pub.plugins.list.length; i++) {
				var cur = _pub.plugins.list[i];
				var valid = true;
				if (cur.requires) {
					// validate variables exist in the params for the plugin
					for (var z=0; z<cur.requires.length; z++) {
						if (!params || !params[cur.requires[z]]) {
							valid = false;
							break;
						}
					}
				}
				if (valid) cur.tab.style.display = 'block';
				else cur.tab.style.display = 'none';
				cur.tab.className = '';
			}
			active.tab = _pub.plugins.list[0].tab;
			active.tab.className = 'active';
			active.tab.plugin.render(_pub.showPlugin, params);
		},
		
		/**
		 * Gets the page constraints
		 */
		getPageSize: function() {
			return {
				width: window.innerWidth || (document.documentElement && document.documentElement.clientWidth) || document.body.clientWidth,
				height: window.innerHeight || (document.documentElement && document.documentElement.clientHeight) || document.body.clientHeight
			};
		},
		
		showPlugin: function(html, params) {
			_pub.html(html);
			var h2 = _pub.createElement('h2', {html: active.tab.plugin.label});
			containers.content_inner.insertBefore(h2, containers.content_inner.firstChild);
		},
		handleLink: function(e) {
			if (!e) var e = window.event;
			var obj = e.target ? e.target : e.srcElement;
			if (e.preventDefault) e.preventDefault();
			var params = (obj.params ? obj.params : _pub.parseQuery(obj.getAttribute('rel')));
			if (_pub.hasClass(obj, 'share-active')) iBeginShare.hide(obj);
			else iBeginShare.show(obj, params);
		},
		/**
		 * Draws a link on an object immediately.
		 * @param {HTMLObject} obj
		 * @param {Object} params
		 * @param {String} skin
		 */
		drawLink: function(obj, params) {
			if (params === undefined) var params = {}
			if (params.link_style === undefined) params.link_style = _pub.default_link;
			if (params.link_skin === undefined) params.link_skin = _pub.default_link_skin;
			if (params.link_label === undefined) params.link_label = _pub.text_link_label;
						
			var link = _pub.createElement('a', {
				className: 'share-link',
				href: 'javascript:void(0)',
				html: params.link_label,
				events: {
					click: _pub.handleLink
				}
			});
			link.params = params;

			obj.appendChild(_pub.createElement('span', {
				className: 'share-link-wrapper share-link-' + params.link_style + ' share-link-' + params.link_style + '-' + params.link_skin,
				children: [link]
			}));
		},
		/**
		 * Draws a button on an object immediately.
		 * @param {HTMLObject} obj
		 * @param {Object} params
		 */
		drawButton: function(obj, params) {
			params.link_style = 'button';
			_pub.drawLink(obj, params);
		},
		/**
		 * Draws a text link on an object immediately.
		 * @param {HTMLObject} obj
		 * @param {Object} params
		 */
		drawTextLink: function(obj, params) {
			params.link_style = 'text';
			_pub.drawLink(obj, params);
		},
		/**
		 * Attaches a share link to an object when the page is loaded.
		 * @param {HTMLObject|String} obj
		 * @param {Object} params
		 * @param {String} skin
		 */
		attachLink: function(obj, params) {
			if (typeof(obj) == 'string') obj = document.getElementById(obj);
			_pub.addEvent(window, 'load', _pub.bind(function(e, obj, params){iBeginShare.drawLink(obj, params);}, obj, params));
		},
		/**
		 * Attaches a button to an object when the page is loaded.
		 * @param {HTMLObject|String} obj
		 * @param {Object} params
		 */
		attachButton: function(obj, params) {
			params.link_style = 'button';
			_pub.attachLink(obj, params);
		},
		/**
		 * Attaches a text link to an object when the page is loaded.
		 * @param {HTMLObject|String} obj
		 * @param {Object} params
		 */
		attachTextLink: function(obj, params) {
			params.link_style = 'text';
			_pub.attachLink(obj, params);
		},
		/**
		 * Binds arguments to a callback function
		 */
		bind: function(fn) {
				var args = [];
				for (var n=1; n<arguments.length; n++) args.push(arguments[n]);
				return function(e) { return fn.apply(this, [e].concat(args)); };
		},
		/**
		 * Binds an event listener
		 * @param {Object} obj Object to bind the event to.
		 * @param {String} evType Event name.
		 * @param {Function} fn Function callback reference.
		 */
		addEvent: function(obj, evType, fn) {
			if (obj.addEventListener) {
				obj.addEventListener(evType, fn, false);
				return true;
			}
			else if (obj.attachEvent) {
				var r = obj.attachEvent("on"+evType, fn);
				return r;
			}
			else {
				return false;
			}
		},
		getStyle: function(obj, styleProp) {
			if (obj.currentStyle)
				return obj.currentStyle[styleProp];
			else if (window.getComputedStyle)
				return document.defaultView.getComputedStyle(obj,null).getPropertyValue(styleProp);
		},
		getContainer: function() {
			return containers.box;
		},
		/**
		 * If `script_handler` is enabled this will return a URL which will log the action.
		 * @param {String} url
		 * @param {String} label The label for the log action (e.g. 'Delicious').
		 */
		makeLoggableUrl: function(link, to, name) {
			if (!_pub.script_handler) return to;
			if (name === undefined) var name = '';
			var log_key = active.tab.plugin.log_key;
			if (!log_key) var log_key = _pub.makeSafeString(active.tab.plugin.label);
			return _pub.script_handler + '&plugin=' + encodeURIComponent(log_key) + '&name=' + encodeURIComponent(name) + '&link=' + encodeURIComponent(link) + '&to=' + encodeURIComponent(to) + '&' + ts();
		},
		plugins: {
			builtin: {
				bookmarks: function() {
					var bookmarks_per_line = 7;
					var lines_per_page = 2;

					var current_page;
					var link;
					var title;

					var getI