/**
 * Lists actions related to the content of the page, so users can easily pick
 * and choose how they want to make a difference in the world.
 * 
 * @copyright Copyright (c) 2009 Christian Siegert (http://christian-siegert.com/)
 * @link http://christian-siegert.com/take-action-button "Take Action" Button
 * @license http://www.opensource.org/licenses/mit-license.php The MIT License
 */


/**
 * Path to the take-action-button folder.
 * 
 * Change only if you want to upload the folder to a subdirectory instead to
 * your server's root directory or if you want to rename the folder.
 * 
 * Do not forget a leading and trailing slash /.
 *  
 * @var string path
 */
var path = "/take-action-button/";


/**
 * Words that are not allowed as keywords.
 * 
 * Make sure to sort descending, i.e. first "your" then "you", to avoid partial
 * replacement of blacklisted words. So "your" is removed completely instead
 * of removing only "you" and leaving "   r".
 * 
 * List contains 700 most used words to reduce text length by about 50%.
 * 
 * @var RegEx_Object blacklist
 */
var blacklist = /\b(z|your|young|you\'ll|you|yet|yes|year|y|x|written|write|would|worry|world|work|wood|wonder|woman|without|with|wish|winter|window|wind|will|wild|wide|why|whole|who|white|while|which|whether|where|when|wheels|wheel|what|west|were|went|we\'ll|well|weight|week|weather|we|way|waves|water|watch|was|warm|war|want|wall|walk|wait|w|vowel|voice|very|v|usually|usual|use|us|upon|up|until|unit|understand|under|u|type|two|turn|try|true|tree|travel|translate|train|town|toward|top|took|too|told|together|today|to|time|through|three|thousands|thousand|thought|though|those|this|third|think|thing|they\'ll|they|these|there|then|them|their|the|that|than|test|ten|tell|teacher|teach|talk|take|tail|table|t|system|syllables|swim|surface|sure|sun|summer|sum|suddenly|such|succeed|subject|study|strong|street|story|store|stop|stood|still|step|stay|state|start|stars|star|stand|square|spend|spell|special|speak|space|south|sound|soon|song|sometimes|something|some|soft|so|snow|smoke|small|slowly|slow|sleep|sky|size|six|sit|sing|since|simple|sign|side|shut|shown|show|should|short|ship|she|shape|shall|several|set|serve|sentence|send|sell|self|seen|seem|see|second|sea|scientists|science|school|says|say|saw|sat|same|said|s|run|rule|round|root|room|rock|road|river|right|return|rest|represent|reply|remember|region|red|record|recently|reason|really|real|ready|read|reached|reach|ran|raised|rain|race|r|quickly|quick|questions|question|q|put|pulled|pull|public|products|product|produce|problem|probably|press|present|power|pound|possible|pose|port|point|play|plant|plane|plan|plain|place|piece|picture|picked|person|perhaps|people|pay|pattern|past|passed|pass|part|paragraph|paper|pair|paint|page|p|own|over|out|our|other|organise|order|or|open|only|one|once|on|old|oil|oh|often|off|of|ocean|object|o|numeral|number|now|notice|nothing|note|not|north|no|night|next|new|never|need|near|name|n|my|must|music|much|mrs|mr|move|mountain|mother|most|morning|more|moon|months|money|miss|minutes|minute|mind|million|mile|might|men|members|meet|measure|mean|me|may|matter|material|mark|map|many|man|make|main|made|machine|m|low|love|lot|lose|look|long|live|little|listen|list|line|like|light|life|letter|let|less|length|legs|left|leave|learn|lead|lay|laugh|later|late|last|large|language|land|l|known|know|knew|king|kind|kept|keep|k|just|job|j|its|it|island|is|into|interest|instruments|inside|Indian|include|inches|inch|in|important|i\'ll|if|idea|i|hurt|hundred|however|how|house|hours|hour|hot|horse|home|hold|his|himself|him|high|here|her|help|held|heavy|heat|heart|heard|hear|head|he|have|has|hard|happy|happened|happen|hand|halt|half|had|h|grow|group|ground|green|great|government|govern|got|good|gone|gold|go|glass|give|girl|get|general|gave|game|g|full|front|from|friends|friend|free|four|found|form|forget|forest|force|for|foot|food|follow|fly|flowers|fix|five|fit|fish|first|fire|finished|finish|fine|find|finally|final|filled|fill|figure|field|few|felt|feet|feel|father|fast|farmers|farm|far|family|fall|fact|face|f|eye|explain|exercise|example|every|ever|even|Europe|equation|enough|English|energy|end|eggs|edge|eat|easy|east|ease|earth|early|each|e|during|dry|drop|drive|drink|draw|dr|down|door|don\'t|done|dog|does|do|divided|distance|discovered|direction|direct|different|difference|differ|didn\'t|did|developed|develop|describe|deep|decided|decide|day|dark|dance|d|cut|cry|cross|cried|covered|cover|course|country|count|could|cough|correct|contain|complete|complain|company|common|come|comb|color|cold|clothes|close|clear|clean|class|city|circle|children|child|check|change|certain|center|cells|cause|case|carry|carefully|care|car|can\'t|cannot|cancel|can|came|call|c|by|buy|but|busy|built|building|build|brought|brother|bring|break|boy|box|both|borrow|book|body|boat|blue|black|birds|bird|bill|big|between|better|best|beside|below|believe|being|behind|begin|began|before|been|bed|become|because|became|beauty|beautiful|be|base|ball|bad|back|b|away|at|ask|as|around|arms|area|are|appear|anything|any|answer|another|animal|and|an|among|America|am|always|also|along|almost|allow|all|air|ago|age|against|again|after|add|act|across|accept|above|about|able|a)\b/g;


/**
 * HTML template for the dashboard.
 * 
 * The dashboard contains the list of actions.
 * 
 * Do not forget the backslash \ at the end of every line.
 */
var dashboardContentTemplate = '\
  <div id="taDashboardTop"></div>\
  <div id="taDashboardMiddle">\
    <div id="taDashboardMiddleShine">\
      <div id="taDashboardMenu">\
        <a id="taDashboardCloseButton">Close</a>\
      </div>\
      \
      <div id="taDashboardLoadingScreen">\
        <img alt="Looking for related actions..." height="32" src="' + location.protocol + '//' + location.host + path +'img/loader.gif" width="32" />\
        <div>Let’s see who needs help ...</div>\
      </div>\
      \
      <ul id="taList"></ul>\
    </div>\
  </div>\
  <div id="taDashboardBottom"></div>\
';
  

/**
 * HTML template for li elements.
 * 
 * This code will be placed inside a li element. Placeholders (strings in curly
 * brackets {}) will be replaced by the actual data.
 * 
 * Do not forget the backslash \ at the end of every line.
 * 
 * Supported placeholders:
 *	* created
 *	* description
 *	* siteName
 *	* siteUrl
 *	* title
 *	* type
 *	* url
 */
var liContentTemplate = '\
  <div class="header">\
    <a class="title" href="{url}">{title}</a>\
    <div class="type">{type}</div>\
  </div>\
  <div class="description">{description}</div>\
  <div class="footer">\
  	<span class="created">Started {created} ago</span>\
  	on <a class="site" href="{siteUrl}">{siteName}</a>\
  	<div class="pagination">\
  	  <a class="previousAction" onclick="showPreviousAction(this);">&laquo; See previous</a>\
  	  <a class="nextAction" onclick="showNextAction(this);">See next &raquo;</a>\
  	</div>\
  </div>\
';


/**
 * Dashboard.
 * 
 * @param sender Button that was clicked.
 * @return
 */
function Dashboard(sender) {
	this.isOpened = false;
	
	var dashboardEl = new Element("div", {id: "taDashboard"});
	
	/**
	 * Fills the HTML list with actions.
	 * 
	 * Uses a template and replaces placeholders with actual data from the
	 * actions. Each HTML li is then inserted into the HTML ul.
	 * 
	 * @param actions Actions in JSON format.
	 * @return void
	 */
	this.show = function() {				
		this.isOpened = true;
		
		// Create dashboard
		var substitutes = {
			//websiteName: websiteName
		};
		var dashboardContent = dashboardContentTemplate.substitute(substitutes);
		
		dashboardEl.set("html", dashboardContent);
		dashboardEl.inject($(document.body), "top");	
		
		this.adjustPosition();
		this.adjustBackground();
		
		// Add event to close dashboard
		$("taDashboardCloseButton").addEvent("click", function() {
			$("taDashboard").destroy();		
		});
	}
	
	/**
	 * Fill dashboard with actions.
	 *
	 * @param actions Actions in JSON format.
	 * @return void
	 */
	this.fill = function(actions) {
		// Hide loading screen
		$("taDashboardLoadingScreen").setStyle("display", "none");
		
		// Create list of actions
		var numberOfActions = actions.length;
		var type = "";
		for (var i = 0; i < numberOfActions; i++) {
			switch (actions[i].action_type.id) {
				case 1: type = "Fundraising"; break;
				case 2: type = "Campaign"; break;
				case 3: type = "Pledge"; break;
				case 4: type = "Event"; break;
				case 5: type = "Affinity group"; break;
				case 6: type = "Volunteer opportunity"; break;
				case 7: type = "Microcredit"; break;
				case 8: type = "Petition"; break;
				default: type = "";
			}			
			
			substitutes = {
				created: formatDate(actions[i].created_at),
				description: actions[i].description,
				siteName: actions[i].site.name,
				siteUrl: actions[i].site.url,
				title: actions[i].title,
				type: type,
				url: actions[i].url				
			};

			var liContent = liContentTemplate.substitute(substitutes);
			var li = new Element("li");
			li.set("html", liContent);
			
			// Hide "Previous" link at first action 
			if (i == 0) {
				li.getElements("a.previousAction").setStyle("display", "none");
			}
			
			// Hide "Next" link at last action
			if (i == numberOfActions-1) {
				li.getElements("a.nextAction").setStyle("display", "none");
			}
			
			// Hide all actions but the first
			if (i > 0) {
				li.setStyle("display", "none");
			}
			
			li.inject("taList");
		}	
		
		if (numberOfActions == 0) {
			this.showErrorMessage("Mhh, we couldn't find anything that relates to this topic.");
		}
		
		this.adjustBackground();
	}
	
	this.adjustBackground = function() {
		if (dashboardEl.getSize().y < 190) {
			$("taDashboardMiddleShine").setStyle("background-position", "left bottom");
		} else {
			$("taDashboardMiddleShine").setStyle("background-position", "left top");
		}
	}
	
	this.adjustPosition = function() {
		// Distance to button
		var margin = 5;

		// Initialize position for dashboard
		var top = 0;
		var left = 0;
		
		// Show dashboard at the height of the button's middle
		top = sender.getCoordinates().top + sender.getCoordinates().height / 2;

		// Show dashboard either left or right of the button, depending on where more space is
		if (sender.getCoordinates().left <= window.getSize().x / 2) {		
			left = sender.getCoordinates().left + sender.getCoordinates().width + margin;
		} else {
			left = sender.getCoordinates().left - dashboardEl.getStyle("width").toInt() - margin;		
		}
		
		// If there is too little space next to the button, center the dashboard on-screen
		if (left < 0 
				|| left > window.getSize().x - dashboardEl.getStyle("width").toInt()) {
			// Center horizontally
			left = (window.getSize().x - dashboardEl.getStyle("width").toInt()) / 2;
			
			// Place below button
			top = sender.getCoordinates().top + sender.getCoordinates().height + margin; 
		}
		
		dashboardEl.setStyle("top", top);
		dashboardEl.setStyle("left", left);
	}
	
	this.showErrorMessage = function(message) {
		if (this.isOpened) {
			$("taDashboardLoadingScreen").setStyle("display", "none");
			var errorMessage = new Element("div", {"id": "taError"});
			errorMessage.set("html", message);
			errorMessage.inject("taDashboardMiddleShine");	
		}	
	}
}


/**
 * Shows next action.
 * 
 * @param sender Button that was clicked.
 * @return void
 */
function showNextAction(sender) {
	var currentAction = $(sender).getParent("li");		
	var nextAction = currentAction.getNext("li"); 
	
	// Show next action
	if (nextAction != null) {
		currentAction.setStyle("display", "none");
		nextAction.setStyle("display", "block");
	}
}


/**
 * Shows previous action.
 * 
 * @param sender Button that was clicked.
 * @return void
 */
function showPreviousAction(sender) {
	var currentAction = $(sender).getParent("li");		
	var previousAction = currentAction.getPrevious("li"); 
	
	// Show previous action
	if (previousAction != null) {
		currentAction.setStyle("display", "none");
		previousAction.setStyle("display", "block");
	}
}


/**
 * Creates an easily readable string telling you how much time elapsed between a
 * given date and now.
 * 
 * @param date Date in the format "yyyy/MM/dd HH:mm:ss"
 * @return string prettyDate
 */
function formatDate(date) {
	// Get UNIX style dates
	var dateCreated = new Date(date).getTime() / 1000;
	var now = new Date().getTime() / 1000;
	
	// Calculate elapsed time
	var seconds = now - dateCreated;
	var minutes = seconds / 60;
	var hours = minutes / 60;
	var days = hours / 24;
	var weeks = days / 7;
	var months = weeks / 4;
	var years = months / 12;
	
	var prettyDate = "";
	
	if (months >= 24) {
		prettyDate = years.floor() + " years";
	} else if (months >= 12 ) {
		prettyDate = years.floor() + " year";
	} else if (weeks >= 8) {
		prettyDate = months.floor() + " months";
	} else if (weeks >= 4) {
		prettyDate = months.floor() + " month";
	} else if (days >= 14) {
		prettyDate = weeks.floor() + " weeks";
	} else if (days >= 7) {
		prettyDate = weeks.floor() + " week";
	} else if (hours >= 48) {
		prettyDate = days.floor() + " days";
	} else if (hours >= 24) {
		prettyDate = days.floor() + " day";
	} else if (minutes >= 120) {
		prettyDate = hours.floor() + " hours";
	} else if (minutes >= 60) {
		prettyDate = hours.floor() + " hour";
	} else if (seconds >= 120){
		prettyDate = minutes.floor() + " minutes";
	} else if (seconds >= 60){
		prettyDate = minutes.floor() + " minute";
	} else if (seconds >= 2) {
		prettyDate = seconds.floor() + " seconds";
	} else {
		prettyDate = seconds.floor() + " second";
	}
		
	return prettyDate;
}


/**
 * Finds keywords in a given HTML element.
 * 
 * TODO: Improve determination of keywords (Weighting).
 * 
 * @param string elementToLookIn
 * @return string keywords Keywords separated by %20
 */
function findKeywords(elementToLookIn) {		
	var content = elementToLookIn.get("html").toLowerCase();
	
	// Remove blacklisted words
	content = content.replace(blacklist, "");
	
	// Remove HTML elements
	content = content.replace(/<[^>]+>/g, " ");
	
	// Replace characters not listed below with spaces
	content = content.replace(/[^a-zA-ZŠŒŽšœžŸ¥µÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýÿ]/g, " ");
	                            
	// Remove unnecessary spaces
	content = content.clean();
	content = content.trim();
	
	// Remove duplicate words
	var uniqueWords = new Array();	
	uniqueWords.combine(content.split(" "));

	// Separate keywords with underscore
	var keywords = uniqueWords.join("_");	
	return keywords;
}

  
/**
 * Get actions.
 * 
 * @param string keywords
 * @return void
 */
function getActions(keywords, myDashboard) {	
	var myJsonRequest = new Request.JSON({
		url: location.protocol + "//" + location.host + path + "proxy.php" + "?keywords=" + keywords,
		onComplete: function(actions) {
			if (actions != null) {
				// Fill dashboard if user has not closed it in the meantime
				if (myDashboard.isOpened) {
					myDashboard.fill(actions);
				}
			} else {
				// Error: Reponse is empty or no actions found
				myDashboard.showErrorMessage("Mhh, the SocialActions server is too busy.<br />Seems like many people want to take action!");
			}
		},
		onFailure: function() {
			// Error: No response from the SocialActions server
			myDashboard.showErrorMessage("Mhh, the SocialActions server is too busy.<br />Seems like many people want to take action!");
		}
	}).send();
}


/**
 * Show actions in a pretty pop-up.
 * 
 * @param sender Button that was clicked.
 * @param contentEl Element holding content we want to find actions for.
 * @return void
 */
function takeAction(sender, contentEl) {	
	// Assume whole page is relevant if specified contentEl does not exist
	if ($(contentEl) == null) {	
		contentEl = $(document.body);
	}

	// Close possibly previously opened pop-up
	if (document.getElementById("taDashboard")) {
		$("taDashboard").destroy();
	}
	
	// Show barebone dashboard
	var myDashboard = new Dashboard($(sender));
	myDashboard.show();
	
	// Fill dashboard with actions
	var keywords = findKeywords($(contentEl));		
	getActions(keywords, myDashboard);
}


/**
 * Adds CSS and MooTools library to page.
 * 
 * @return void
 */
function initializeScript() {
	// Add link element to DOM to load our CSS
	var linkEl = document.createElement("link");
	linkEl.setAttribute("href", path + "css/take-action.css");
	linkEl.setAttribute("rel", "stylesheet");
	linkEl.setAttribute("type", "text/css");	
	document.getElementsByTagName("head")[0].appendChild(linkEl);

	// Add script element to DOM to load MooTools	
	var scriptEl = document.createElement("script");
	scriptEl.setAttribute("src", path + "js/mootools-1.2.1-core-yc.js");
	scriptEl.setAttribute("type", "text/javascript");	
	document.getElementsByTagName("head")[0].appendChild(scriptEl);
	
	// Preload images
	// TODO: Remove this and use one big image with CSS clip 
	if (document.images) {
		// Button
		var preload_image = new Image(96, 38);
		preload_image.src = location.protocol + "//" + location.host + path + "img/button-medium_hover.png";

		var preload_image2 = new Image(84, 27);
		preload_image2.src = location.protocol + "//" + location.host + path + "img/button-small_hover.png";
		
		// Pop-up
		var preload_image3 = new Image(556, 16);
		preload_image3.src = location.protocol + "//" + location.host + path + "img/dashboard-bottom.png";
		
		var preload_image4 = new Image(556, 1);
		preload_image4.src = location.protocol + "//" + location.host + path + "img/dashboard-middle.png";
		
		var preload_image5 = new Image(556, 16);
		preload_image5.src = location.protocol + "//" + location.host + path + "img/dashboard-top.png";
		
		var preload_image6 = new Image(32, 32);
		preload_image6.src = location.protocol + "//" + location.host + path + "img/loader.gif";
		
		var preload_image7 = new Image(510, 158);
		preload_image7.src = location.protocol + "//" + location.host + path + "img/dashboard-background.png";
	}
}

initializeScript();