/*jslint bitwise: true, browser: true, eqeqeq: true, evil: true, immed: true,
 newcap: true, nomen: true, onevar: true, regexp: true, 
 strict: true, undef: true, white: true, indent: 4 */
 
/*global window: false, encodeURIComponent: false, ActiveXObject: false , escape: false */
 
/*members
 length, item, push, splice, split, concat, substring, toLowerCase, join, ceil, floor, round, replace, getTime,
 readyState, responseText, status, open, send,
 body, hash, innerHTML, className, clientHeight, clientWidth, offsetHeight, offsetWidth, href, src, value, style, left, width, height,
 getElementById, getElementsByTagName, parentNode, attachEvent, addEventListener, detachEvent, removeEventListener,

 author, authorDisplayName, authorLink, authorPhotoLink, date, photo, photolink, photoLink, link, message, main, id, tweetLink
 */

 "use strict";
(function ()
{
	var tweetfeelings, ajaxSupport = false;

	function xmlHttp()
	{
		var i, obj, versions = ['MSXML2.XMLHttp.5.0', 'MSXML2.XMLHttp.4.0', 'MSXML2.XMLHttp.3.0', 'MSXML2.XMLHttp', 'Microsoft.XMLHttp'];
		
		if (typeof XMLHttpRequest !== 'undefined')
		{
			return new XMLHttpRequest();
		}
		else if (typeof ActiveXObject !== 'undefined')
		{
			for (i = 0; i < versions.length; i++)
			{
				try
				{
					obj = new ActiveXObject(versions[i]);
					return obj;
				}
				catch (err)
				{
					//Do nothing here, try next version
				}
			}
		}
		throw new Error('XMLHttp object cannot be created.');
	}
	
	function uriEncode(data)
	{
		if (typeof encodeURIComponent !== 'undefined')
		{
			return encodeURIComponent(data);
		}
		else
		{
			return escape(data);
		}
	}
	
	function trim(s)
	{
		if (typeof s === 'string' && s !== null)
		{
			return s.replace(/^\s+|\s+$/g, '');
		}
		return null;
	}
	
	function addEvent(obj, name, fn)
	{
		if (typeof obj === 'undefined' || obj === null || typeof fn !== 'function')
		{
			return;
		}
		if (typeof obj.addEventListener !== 'undefined')
		{
			obj.addEventListener(name, fn, false);
		}
		else if (typeof obj.attachEvent !== 'undefined')
		{
			obj.attachEvent('on' + name, fn);
		}
		else if (typeof(obj['on' + name]) === 'function')
		{
			var previousFn = obj['on' + name];
			obj['on' + name] = function ()
			{
				fn();
				previousFn();
			};
		}
		else
		{
			obj['on' + name] = fn;
		}
	}
	
	function removeEvent(obj, name, fn)
	{
		if (typeof obj === 'undefined' || obj === null || typeof fn !== 'function')
		{
			return;
		}
		if (typeof obj.removeEventListener !== 'undefined')
		{
			obj.removeEventListener(name, fn, false);
		}
		else if (typeof obj.detachEvent !== 'undefined')
		{
			obj.detachEvent('on' + name, fn);
		}
		else if (typeof(obj['on' + name]) === 'function')
		{
			obj['on' + name] = null;
		}
	}
		
	function containsClassName(obj, name)
	{
		if (typeof obj === 'undefined' || obj === null || typeof obj.className === 'undefined' ||
			obj.className.length < 1 ||	typeof name === 'undefined' || name === null)
		{
			return false;
		}
		var i, classes = obj.className.split(' ');
		for (i = 0; i < classes.length; i++)
		{
			if (classes[i] === name)
			{
				return true;
			}
		}
		return false;
	}
	
	function addClassName(obj, name)
	{
		if (typeof obj === 'undefined' || obj === null || typeof obj.className === 'undefined' ||
			typeof name === 'undefined' || name === null)
		{
			return;
		}
		if (obj.className.length > 0)
		{
			if (containsClassName(obj, name))
			{
				return;
			}
			obj.className += ' ' + name;
		}
		else
		{
			obj.className = name;
		}
	}
	
	function removeClassName(obj, name)
	{
		if (typeof obj === 'undefined' || obj === null || typeof obj.className === 'undefined' ||
			typeof name === 'undefined' || name === null)
		{
			return;
		}
		var i, classes = obj.className.split(' ');
		for (i = 0; i < classes.length; i++)
		{
			if (classes[i] === name)
			{
				classes.splice(i, 1);
			}
		}
		obj.className = classes.join(' ');
	}
				
	function resize(obj, height, width)
	{
		if (typeof obj === 'undefined' || obj === null)
		{
			return;
		}
		height = 300;
		var w = obj.offsetWidth <= width, h = obj.offsetHeight <= height;
		if (!w || !h)
		{
			w = obj.offsetWidth / width;
			h = obj.offsetHeight / height;
			if (w < h)
			{
				obj.style.height = height + 'px';
			}
			else
			{
				obj.style.width = width + 'px';
			}
		}
	}
		
    tweetfeelings = function ()
    {
		var delay = 7500, noTweetsDelay = 10000, anonymous = [], polaroid1 = {}, polaroid2 = {}, tweets = [], current = [], done = -1, activeFeeling, timer, navs, diff, pos1, pos2, update, index = ['', 'first', 'love', ':)', 'free'];

		function getTweets(feeling)
		{
			if (!ajaxSupport)
			{
				return;
			}
			try
			{
				if (typeof current[feeling] === 'undefined')
				{
					current[feeling] = -1;
					tweets[feeling] = [];
				}
				var anon, request = xmlHttp(), since = tweets[feeling].length > 0 ? tweets[feeling][0].id : 0;
				request.open('GET', '/project/tweetfeelings/api?search=' + uriEncode(feeling) + (since > 0 ? "&since=" + since : ""), true);
				addEvent(request, 'readystatechange', anon = function ()
				{
					if (request.readyState === 4)
					{
						if (request.status === 200)
						{
							var i, now, tmp = eval(request.responseText);
							if (typeof tmp !== 'undefined')
							{
								current[feeling] += tmp.length;
								tweets[feeling] = tmp.concat(tweets[feeling]);
								
								if (since === 0)
								{
									i = tmp.length - 1;
									now = Math.floor(new Date().getTime() / 1000);
									while (i > 0 && now - tweets[feeling][i].date < ((delay / 1000) * i))
									{
										i--;
									}
									current[feeling] = i;
								}
							}
							
							if (current[feeling] < 0)
							{
								setTimeout(function ()
								{
									getTweets(feeling);
								}, noTweetsDelay);
							}
							else
							{
								update(feeling);
							}
							removeEvent(request, 'readystatechange', anon);
							return;
						}
						alert(request.status + '\r\n' + request.responseText);
					}
				});
				request.send(null);
			}
			catch (err)
			{
				//alert(err.message);
			}
		}
		
		function getRelativeTweetTime(timestamp)
		{
			var i, relative = Math.floor(new Date().getTime() / 1000) - timestamp,
				prefix = ['', '', 'about ', 'about '],
				time = ['second', 'minute', 'hour', 'day'],
				timeDiv = [60, 60, 24, Infinity];
			if (relative < 0)
			{
				return 'moments ago';
			}
			for (i = 0; i < timeDiv.length; i++)
			{
				if (relative < timeDiv[i])
				{
					return prefix[i] + relative + ' ' + time[i] + (relative !== 1 ? 's' : '') + ' ago';
				}			
				relative = Math.floor(relative / timeDiv[i]);
			}
		}
		
		function setTweet(tweet)
		{
			var obj, height, width;
			obj = containsClassName(polaroid1.main, 'invisible') ? polaroid1 : polaroid2;
			
			height = obj.photo.parentNode.clientHeight;
			width = obj.photo.parentNode.clientWidth;
			
			removeEvent(obj.photo, 'load', anonymous[obj.main.id + 'load']);
			addEvent(obj.photo, 'load', anonymous[obj.main.id + 'load'] = function ()
			{
				resize(obj.photo, height, width);
				update(activeFeeling);
			});
			
			obj.photo.style.width = '';
			obj.photo.style.height = '';
			obj.photo.src = tweet.photoLink;
			obj.author.photolink.href = tweet.authorLink;
			obj.author.photo.src = tweet.authorPhotoLink;
			obj.author.link.href = tweet.authorLink;
			obj.author.link.innerHTML = tweet.authorDisplayName;
			
			obj.date.innerHTML = getRelativeTweetTime(tweet.date);
			
			obj.date.href = tweet.tweetLink;
			obj.message.innerHTML = tweet.message;
		}
		
		function shiftOut(output, input, step)
		{
			if (step === 0)
			{
				pos1 = document.body.clientWidth;
				pos2 = Math.floor((pos1 - output.clientWidth) / 2);
				diff = Math.ceil(((pos1 - output.clientWidth) / 2 + output.clientWidth) / 16);
				document.getElementById('main').style.width = pos1 + 'px';
				if (containsClassName(polaroid1.main, 'invisible') && containsClassName(polaroid2.main, 'invisible'))
				{
					pos2 = -9999;
				}
				removeClassName(input, 'invisible');
			}
			
			pos1 -= diff;
			pos2 -= diff;
			input.style.left = pos1 + 'px';
			output.style.left = pos2 + 'px';

			if (step < 15)
			{
				setTimeout(function ()
				{
					shiftOut(output, input, step + 1);
				}, 40);
			}
			else
			{
				output.style.left = '-9999px';
				addClassName(output, 'invisible');
				update(activeFeeling);
			}
		}
		
		update = function (feeling)
		{
			if (feeling !== activeFeeling)
			{
				return;
			}
			if (done === -1)
			{
				done = 1;
			}
			else if (done === 0)
			{
				done = 1;
				return;
			}
			else if (done === 1)
			{
				done = 2;
				if (containsClassName(polaroid1.main, 'invisible'))
				{
					shiftOut(polaroid2.main, polaroid1.main, 0);
				}
				else
				{
					shiftOut(polaroid1.main, polaroid2.main, 0);
				}
				return;
			}
			else if (done === 2)
			{
				done = 0;
				if (current[feeling] < 0)
				{
					done = -1;
					getTweets(feeling);
					return;
				}
				else
				{
					clearTimeout(timer);
					timer = setTimeout(function ()
					{
						update(feeling);
					}, delay);
				}
			}
			setTweet(tweets[feeling][current[feeling]]);
			current[feeling]--;
		};
		
		function setFeeling(feeling)
		{
			var i = 0, dyfunc, active = 0;
			activeFeeling = feeling = trim(feeling);
			
			while (active < index.length && index[active] !== feeling)
			{
				active++;
			}
			if (active === index.length)
			{
				navs[active].value = feeling;
			}
			
			if (location.hash.substring(1) !== feeling)
			{
				location.hash = (feeling === '' ? ' ' : feeling);
				scrollTo(0, 0);
			}

			for (i = 0; i < 6; i++)
			{
				dyfunc = (active !== i) ? removeClassName : addClassName;
				dyfunc(navs[i], 'active');
			}
			
			if (typeof current[feeling]  === 'undefined' || current[feeling] < 0)
			{
				getTweets(feeling);
			}
			else
			{
				update(feeling);
			}
			return false;
		}
		
		function setDOM(obj, value)
		{
			var divs, ahrefs;
			obj.main = value;
			divs = value.getElementsByTagName('div');
			obj.author = {};
			obj.author.main = divs[0];
			obj.photo = divs[2].getElementsByTagName('img')[0];
			ahrefs = divs[0].getElementsByTagName('a');
			obj.author.photolink = ahrefs[0];
			obj.author.photo = ahrefs[0].getElementsByTagName('img')[0];
			obj.author.link = ahrefs[1];		
			obj.date = ahrefs[2];
			obj.message = value.getElementsByTagName('h1')[0];
			
			addEvent(obj.photo, 'error', anonymous[obj.main.id + 'error'] = function ()
			{
				done = -1;
				update(activeFeeling);
			});
		}
		
		function retSetFeeling(i, feeling)
		{
			return (anonymous['nav' + i + 'click'] = function ()
			{
				return setFeeling(feeling);
			});
		}
	
		function loaded()
		{
			var i;
			navs = document.getElementById('header').getElementsByTagName('ul')[0].getElementsByTagName('a');
			navs[navs.length] = document.getElementById('header').getElementsByTagName('ul')[0].getElementsByTagName('input')[0];
			
			for (i = 0; i < index.length; i++)
			{
				addEvent(navs[i], 'click', retSetFeeling(i, index[i]));
			}
			addEvent(navs[5], 'click', anonymous['nav' + 5 + 'click'] = function ()
			{
				if (navs[5].value.length > 0)
				{
					setFeeling(navs[5].value);
				}
			});
			addEvent(navs[5], 'change', anonymous['nav' + 5 + 'change'] = function ()
			{
				setFeeling(navs[5].value);
			});
		
			setDOM(polaroid1, document.getElementById('p1'));
			setDOM(polaroid2, document.getElementById('p2'));

			setFeeling(location.hash.substring(1));
		}
		
		function unLoaded()
		{
			var i;
			for (i = 0; i < index.length + 1; i++)
			{
				removeEvent(navs[i], 'click', anonymous['nav' + i + 'click']);
			}
			removeEvent(navs[i], 'change', anonymous['nav' + 5 + 'change']);
			
			removeEvent(polaroid1.photo, 'error', anonymous[polaroid1.main.id + 'error']);
			removeEvent(polaroid1.photo, 'load', anonymous[polaroid1.main.id + 'load']);
			removeEvent(polaroid2.photo, 'error', anonymous[polaroid2.main.id + 'error']);
			removeEvent(polaroid2.photo, 'load', anonymous[polaroid2.main.id + 'load']);
			
			removeEvent(window, 'load', loaded);
			removeEvent(window, 'unload', unLoaded);
		}
		
		try
		{
			xmlHttp();
			ajaxSupport = true;
		}
		catch (exception)
		{
			ajaxSupport = false;
		}
		 		
		addEvent(window, 'load', loaded);
		addEvent(window, 'unload', unLoaded);
    };
    return tweetfeelings;
}())();
//EOF