/**
 * Formats text using specified formatting (or removes formatting,
 * if it already exists)
 * 
 * setup:
 * - selector (string): "bold", "italic", "code.inline", etc.
 * - characters (string): "**", "_", "`", etc.
 */

action.performWithContext = function(context, outError) {
	// Init our variables
	var targetSelector = new SXSelector(action.setup.selector + ', ' + action.setup.selector + ' *'),
		rootSelector = new SXSelector(action.setup.selector),
		wrapChars = action.setup.characters,
		recipe = new CETextRecipe(),
		// Loop vars
		range, zone, snippet;
	
	// Loop through our selections and process them all
	for (var i = 0, count = context.selectedRanges.length; i < count; i++) {
		range = context.selectedRanges[i];
		zone = context.syntaxTree.zoneAtCharacterIndex(range.location);
		// If we are removing formatting from the selection, it's the same for all cases; just perform that action
		if (targetSelector.matches(zone)) {
			// Parse up the tree to the main zone (if necessary)
			while (!rootSelector.matches(zone)) {
				zone = zone.parent;
			}
			// Delete the punctuation zones (first and last child zones)
			recipe.deleteRange(zone.childAtIndex(0).range);
			recipe.deleteRange(zone.childAtIndex(zone.childCount - 1).range);
		} else if (range.length === 0) {
			// The range is zero-length, so that means we are inserting a snippet and returning (since there will not be any other ranges)
			wrapChars = wrapChars.replace(/[`$]/g, '\\$&');
			snippet = new CETextSnippet(wrapChars + '$1' + wrapChars);
			return context.insertTextSnippet(snippet);
		} else if (context.selectedRanges.length === 1) {
			// We are only working with a single range, so we can again use snippets and immediately return
			wrapChars = wrapChars.replace(/[`$]/g, '\\$&');
			snippet = new CETextSnippet(wrapChars + '${1:$EDITOR_SELECTION}' + wrapChars);
			return context.insertTextSnippet(snippet);
		} else {
			// We are working with multiple ranges, so queue all changes in the recipe, and we'll apply it after the loop exist
			recipe.replaceRange(range, wrapChars + context.substringWithRange(range) + wrapChars);
		}
	}
	
	// Finalize our changes!
	return context.applyTextRecipe(recipe);
};
