/******************************************************
          The Great Bookmarklet Combinatorix
*******************************************************/

var gotSomeInputs = false;
var combinedNameIsSet = false;

//Escape text for use in JavaScript strings
function esc_js(text){
	return text
		.replace(/\\/g, '\\\\')
		.replace(/\"/g, '\\x22')
		.replace(/\'/g, '\\x27')
		.replace(/\n/g, '\\n');
}

//Generate a combined bookmarklet from one or more bookmarklets entered
function generateCombinedBookmarklet(){
	//Collect all valid inputs
	var bookmarklets = [];
	var titles = $('#source input.title');
	var urls = $('#source input.url');
	//There's always an equal number of title and URL boxes
	for(var i = 0; i < titles.length; i++ ){
		var title = $(titles[i]);
		var url = $(urls[i]);
		 
		title = title.hasClass('example')?'':title.val();
		url = url.hasClass('example')?'':url.val();
		 
		//At least one of the title or URL must be specified
		if ( !title && !url){
			continue; 
		}
		
		//"javascript:" URLs that are URL-encoded break the "Run all" setting. Detect and decode such URLs.
		if ( url.match(/^\s*javascript:/i) ){
			//Most not-encoded bookmarklets have at least one internal space. Decode any that don't.
			if ( !url.match(/[^\s]\s/) ){
				url = url.replace(/%([^\d]|$)/g, "%25"); //Fix unencoded percent signs
				url = decodeURI(url);
			}
		} 
		
		bookmarklets.push({
			'title' : title,
			'url' : url?url:'#'
		});
	}
	
	gotSomeInputs = bookmarklets.length != 0;
	if ( !gotSomeInputs ){
		bookmarklets.push({
			'title' : 'No bookmarklets entered.',
			'url' : 'javascript:alert("No bookmarklets entered")'
		});
	}
	
	//Serialize the bookmarklet array
	var encodedBookmarklets = [];
	for(var i = 0; i < bookmarklets.length; i++ ){
		encodedBookmarklets.push(
			'{title:"'+esc_js(bookmarklets[i].title)+'",url:"'+esc_js(bookmarklets[i].url)+'"}'
		);
	}		
	encodedBookmarklets = '[' + encodedBookmarklets.join(',') + ']';
	
	//Get rid of any menus currently visible. 
	$('.ws_cmbmc').remove();
	
	var action = $('input[name="action"]:checked').val();
	
	//Generate a combined bookmarklet of the specified type
	var bookmarkletURL = '#';
	if ( action == 'menu' ){
		
		//The meta-bookmarklet that displays the bookmarklet menu 
		var menuCode = 'function(n,g,q,c,f){var s=document,l=s.onclick,h="ws_cmbm-"+f,b=s.getElementById(h),d="ws_cmbms-"+f,p=s.getElementById(d),e=null,o,a={tl:{left:"10px",top:"10px"},tr:{right:"10px",top:"10px"},bl:{left:"10px",bottom:"10px"},br:{right:"10px",bottom:"10px"}},k,m=".ws_cmbmc{position:fixed;z-index:1001;width:200px;display:block;visibility:hidden;border:1px solid #b0b0b0;background:#fff;padding:3px 0 3px 3px;text-align:left;border-radius:3px;-moz-border-radius:3px;-webkit-border-radius:3px;box-shadow:2px 2px 3px #777;-moz-box-shadow:2px 2px 3px #777;-webkit-box-shadow:2px 2px 3px #777;}.ws_cmbmc a{display:block;float:left;margin:0;width:191px;border:none;padding:8px 0 8px 6px;background:#fff;color:black;text-decoration:none;font:normal normal normal 12px/100% Verdana,sans-serif;letter-spacing:normal;word-spacing:normal;}.ws_cmbmc a:hover{background:#a0a0a0;color:white;border:none;text-decoration:none;font:normal normal normal 12px/100% Verdana,sans-serif;letter-spacing:normal;word-spacing:normal;}";function r(){b.style.visibility="hidden"}function j(){b.style.visibility="visible"}if(b){if(b.style.visibility=="visible"){r()}else{j()}return}if(!p){m=m.replace(/\.ws_cmbmc/g,"#"+h);p=s.createElement("style");p.type="text/css";p.id=d;p.appendChild(s.createTextNode(m));s.getElementsByTagName("head")[0].appendChild(p)}b=s.createElement("div");b.setAttribute("id",h);b.className="ws_cmbmc";for(o=0;o<n.length;o++){e=s.createElement("a");e.appendChild(s.createTextNode(n[o].title));e.setAttribute("href",n[o].url);e.onclick=(function(i){if(q){r()}});b.appendChild(e)}s.getElementsByTagName("body")[0].appendChild(b);if(a.hasOwnProperty(g)){for(k in a[g]){b.style[k]=a[g][k]}}else{if(g=="c"){b.style.left=Math.round((window.innerWidth-b.offsetWidth)/2)+"px";b.style.top=Math.round((window.innerHeight-b.offsetHeight)/2)+"px"}}if(c){s.onclick=(function(){r();if(typeof l=="function"){l()}});b.onclick=(function(i){i.stopPropagation()})}j()}';
		
		//Gather menu parameters
		var menuPosition =  $('#position').val(); 
		var closeAfterClick = $('#close-after-click').is(':checked');
		var closeIfElsewhere = $('#close-if-elsewhere').is(':checked');
		
		var randomId = (new Date).getTime()+''; //Each bookmarklet gets a unique menu ID to prevent conflicts
		
		//The combined bookmarklet = meta-bookmarklet + a bunch of parameters
		params = [
			encodedBookmarklets,
			'"' + menuPosition + '"',
			(closeAfterClick?'true':'false'),
			(closeIfElsewhere?'true':'false'),
			randomId
		];
		bookmarkletURL = 'javascript:('+menuCode+')('+params.join(',')+')';
		
	} else if ( action == 'run'){
		//The meta-bookmarklet that sequentially executes a bunch of other bookmarklets.
		//If any of the "bookmarklets" happens to be an URL, it will attempt to open it
		//in a new window/tab (only works if the browser doesn't block popups from bookmarklets).
		var runAll = 'function(bookmarklets){for(var i=0;i<bookmarklets.length;i++){var code=bookmarklets[i].url;if(code.indexOf("javascript:")!=-1){code=code.replace("javascript:","");eval(code)}else{code=code.replace(/^\s+|\s+$/g,"");if(code.length>0){window.open(code)}}}}';
		bookmarkletURL = 'javascript:('+runAll+')('+encodedBookmarklets+')';
	}
	
	$('#result').attr('href', encodeURI(bookmarkletURL));
	updateSaveButton();	
}

/********************************************************
                        UI stuff
*********************************************************/

function addAnotherInput(count){
	if ( !count ){
		count = 1;
	}
	
	var template = $('#source-template').contents();
	var result = null; 
	for(i = 0; i < count; i++){
		result = template.clone(true).appendTo('#source');
	}
	
	return result;
}

function updateBookmarkletTitle(){
	var combinedName = $('#combined-name');
	newTitle = combinedName.hasClass('example')?'':combinedName.val();
	
	if ( !newTitle ){
		newTitle = 'Untitled Bookmarklet';
		combinedNameIsSet = false;
	} else {
		combinedNameIsSet = true; 
	}
	
	$('#result').text(newTitle).attr('title', newTitle);
	updateSaveButton();
}

function updateSaveButton(){
	var saveButton = $("#save-bookmarklet"); 
	if ( gotSomeInputs && combinedNameIsSet ){
		saveButton.removeAttr('disabled');
	} else {
		saveButton.attr('disabled', 'disabled');
	}	
}

/********************************************************
               Event handlers and such
*********************************************************/

$(function(){
	//Make bookmarklets sortable
	$('#source').sortable({
		axis : 'y',
		update: (function(event, ui){
			//Update the bookmarklet when input bookmarklets are reordered
			generateCombinedBookmarklet();
		})
	});
	
	//Example text in input fields
	$('input[type="text"]').example(function(){
		return $(this).attr('title');	
	});
	
	//Add/reset inputs
	$('#add-bookmarklet').click(function(){
		addAnotherInput();
	});
	
	$('#reset-inputs').click(function(){
		$('#source').empty();
		addAnotherInput(3);
		generateCombinedBookmarklet();
		return false;
	});
	
	//Show/hide the "Close menu if..." checkboxes
	$('#toggle-menu-settings').click(function(){
		var settings = $('#menu-settings').toggle();
		/*return false;*/
	});
	
	//"Hide" button for notifications
	$('a.hide-notification').click(function(){
		$(this).parent().slideUp('fast');
		return false;
	});
	
	//Regenerate the bookmarklet when inputs are changed
	$('#combine').click(function(event){
		generateCombinedBookmarklet();
		event.stopPropagation();
	});
	
	$('#position').change(generateCombinedBookmarklet);
	$('input[name="action"]').change(generateCombinedBookmarklet);
	$('#menu-settings input').change(generateCombinedBookmarklet);
	
	$('#source input').live('change', (function(){
		generateCombinedBookmarklet();
	}));
	
	//Set the title of the combined bookmarklet. If no title is specified,
	//the value of the "Name your new bookmarklet" field is used. 
	$('#combined-name').keyup(updateBookmarkletTitle).change(updateBookmarkletTitle);
	
	//Auto-select info box contents
	$('.info').live('focus', function(){
		$(this).select();
	});
	
	//Don't submit the form on Enter (intuitively, the form doesn't look like
	//one that's meant to be submitted. Also, saving the result is optional).
	$('#save-bookmarklet').click(function(){
		$(this).parents('form').submit();
	});
	
	
	//The first generation (of the bookmarklet)
	updateBookmarkletTitle();
	generateCombinedBookmarklet();
});



