/**
 * changes the bbcode-mode to given value
 * 
 * @param string mode the new mode
 * @access public
 */
function changeBBCodeMode(mode)
{
	BBCodeMode = mode;
}

/**
 * inserts a smiley at the current position in the textarea
 *
 * @param int id the id of the textfield
 * @param string smiley the smiley-code
 * @access public
 */
function insertSmiley(id,smiley)
{
	var textarea = document.getElementById(id);
	if(smiley)
	{
		_insertAtCursor(id,smiley);
		textarea.focus();
	}
}

/**
 * inserts a bbcode at the current position in the textarea
 *
 * @param int id the id of the textfield
 * @param string text the text to insert (the start-tag)
 * @param string tag the name of the tag
 * @param object object the button or null
 * @access public
 */
function insertBBCode(id,text,tag,object)
{
	var textarea = document.getElementById(id);
	if(text)
	{
		if(BBCodeMode == 'advanced')
		{
			if(!_surroundMarkedText(textarea,tag,text))
			{
				if(object != null)
					_pasteTag(id,object,tag,text);
				else
					_insertAtCursor(id,text);
			}
		}
		else
		{
			text = trim(text);
			if(_getSelection(id) != "")
				_surroundMarkedText(textarea,tag,text);
			else
			{
				var tagData = _getTagData(tag);
				if(tagData != null && tagData["prompt_text"] == "")
					_pasteTag(id,object,tag,text);
				else
					_showBBCodePrompt(id,text,tagData);
			}
		}
		
		textarea.focus();
	}
}

/**
 * closes all currently open tags in the textfield with given id
 *
 * @param int id the id of the textfield
 * @access public
 */
function closeBBCodeTags(id)
{
	var textarea = document.getElementById(id);
	var lower_text = textarea.value.toLowerCase();
	var pos;
	var tags = new Array();
	for(var x = 0;x < BBCODE.length;x++)
	{
		// determine the number of opening and closing occurrences of this tag
		var openingCount = 0;
		var closingCount = 0;
		
		switch(BBCODE[x]["param"])
		{
			case "no":
				openingCount = _subStringCount(lower_text,"[" + BBCODE[x]["tag"] + "]");
				pos = lower_text.indexOf("[" + BBCODE[x]["tag"] + "]");
				break;
			
			case "optional":
				openingCount = _subStringCount(lower_text,"[" + BBCODE[x]["tag"] + "]");
				openingCount += _subStringCount(lower_text,"[" + BBCODE[x]["tag"] + "=");
				var p1 = lower_text.indexOf("[" + BBCODE[x]["tag"] + "]");
				var p2 = lower_text.indexOf("[" + BBCODE[x]["tag"] + "=");
				if(p1 >= 0 && p2 >= 0)
					pos = Math.min(p1,p2);
				else if(p1 >= 0)
					pos = p1;
				else
					pos = p2;
				break;
			
			default:
				openingCount = _subStringCount(lower_text,"[" + BBCODE[x]["tag"] + "=");
				pos = lower_text.indexOf("[" + BBCODE[x]["tag"] + "=");
				break;
		}
		
		var closing = "[/" + BBCODE[x]["tag"] + "]";
		closingCount = _subStringCount(lower_text,closing);
		
		// missing closing tag?
		if(openingCount > closingCount)
			tags.push(new Array(pos,closing));
	}
	
	// ensure that we add the closing tags in the correct order
	tags.sort(_numericSort);
	tags.reverse();

	// add the tags to the end of the textarea
	for(var i = 0;i < tags.length;i++)
		textarea.value += tags[i][1];

	// remove the * from the buttons
	for(var i = 0;i < BBCODE.length;i++)
	{
		var object = document.getElementById("tag_" + BBCODE[i]["tag"]);
		if(object != null)
		{
			var len = object.value.length;
			if(object.value.substr(len - 1,1) == "*")
				object.value = object.value.substr(0,len - 1);
		}
	}
}

/**
 * tries to find the tag-data of the given tag
 *
 * @param string tag the tag
 * @access private
 * @return array the data from the BBCODE-array
 */
function _getTagData(tag)
{
	for(var i = 0;i < BBCODE.length;i++)
	{
		if(BBCODE[i]["tag"] == tag)
			return BBCODE[i];
	}
	
	return null;
}

/**
 * determines the current selection in the textfield with given id
 * 
 * @param int id the id of the textfield
 * @access private
 * @return string the selection
 */
function _getSelection(id)
{
	if(typeof document.selection != 'undefined')
  	return document.selection.createRange().text;

  var textarea = document.getElementById(id);
  if(typeof textarea.selectionStart != 'undefined')
  	return textarea.value.substring(textarea.selectionStart,textarea.selectionEnd);

  return "";
}

/**
 * inserts the given text in the textfield with given id at the position of the cursor
 *
 * @param int id the id of the textfield
 * @param string text the text to insert
 * @access private
 */
function _insertAtCursor(id,text)
{
  var textarea = document.getElementById(id);
  textarea.focus();

  // for IE and opera
  if(typeof document.selection != 'undefined')
  {
    // paste the text
    var range = document.selection.createRange();
    range.text = text;

    // move the cursor
    range = document.selection.createRange();
    if(window.opera)
    	range.move('character',text.length);
    range.select();
  }
  // for the gecko-engine
  else if(typeof textarea.selectionStart != 'undefined')
  {
    // paste the text
    var start = textarea.selectionStart;
    var end = textarea.selectionEnd;
    var content = textarea.value;
    textarea.value = content.substring(0,start);
		textarea.value += text;
		textarea.value += content.substring(end,content.length);

		// move the cursor
    var pos = start + text.length;
    textarea.selectionStart = pos;
    textarea.selectionEnd = pos;
  }
  // for all other browser
  else
  {
    // just paste the text at the end
    textarea.value += text;
  }
}

/**
 * surrounds the selected text with the given tag
 *
 * @param object textarea the textarea
 * @param string tag the affected tag
 * @param string startTag the startTag to paste (to allow parameters)
 * @access private
 * @return boolean true if it was successfull
 */
function _surroundMarkedText(textarea,tag,startTag)
{
	startTag = trim(startTag);

	var EndTag = "[/" + tag + "]";
	if(EndTag == "")
		return false;

	if(document.selection)
	{
		textarea.focus();
		var selection = document.selection.createRange().text;
		if(selection != "")
		{
			var range = document.selection.createRange();
			range.text = startTag + selection + EndTag;
			range.move('character',range.text);
			range.select();
			return true;
		}
		return false;
	}

	var content = textarea.value;
	if(textarea.selectionEnd != textarea.selectionStart)
	{
		var SelStart = textarea.selectionStart;
		var SelEnd = textarea.selectionEnd;
		textarea.value = content.substring(0,SelStart);
		textarea.value += startTag + content.substring(SelStart,SelEnd) + EndTag;
		textarea.value += content.substring(SelEnd,content.length);
		return true;
	}

	return false;
}

/**
 * inserts the given tag in the textfield. if the tag is currently open
 * (or lets say, the button has a * at the end) the tag will be closed
 * otherwise the given text will be inserted and the button will be "marked"
 *
 * @param int id the id of the tag
 * @param object object the button or null
 * @param string tag the affected tag
 * @param string text the text to paste
 * @access private
 */
function _pasteTag(id,object,tag,text)
{
	if(object == null)
		_insertAtCursor(id,text);
	else
	{
		var len = object.value.length;
		if(object.value.substr(len - 1,1) == "*")
		{
			_insertAtCursor(id,"[/" + tag + "]");
			object.value = object.value.substr(0,len - 1);
		}
		else
		{
			_insertAtCursor(id,text);
			object.value += "*";
		}
	}
}

/**
 * displays the bbcode-prompt for the given tagData (for the simple-mode)
 * 
 * @param int id the id of the textfield
 * @param string startTag the startTag to paste
 * @param array tagData the data of the tag from the BBCODE-array
 * @access private
 */
function _showBBCodePrompt(id,startTag,tagData)
{
	var textarea = document.getElementById(id);
	if(tagData["prompt_param_text"] != "")
	{
		var param = prompt(tagData["prompt_param_text"],"");
		if(param != null && param != "")
		{
			var text = prompt(tagData["prompt_text"],"");
			if(text != null)
				_insertAtCursor(id,"[" + tagData["tag"] + "=" + param + "]" + text + "[/" + tagData["tag"] + "]");
		}
	}
	else
	{
		var text = prompt(tagData["prompt_text"],"");
		if(text != null)
			_insertAtCursor(id,startTag + text + "[/" + tagData["tag"] + "]");
	}
}

/**
 * counts the number of occurrences of <code>needle</code> in <code>haystack</code>
 *
 * @param string haystack the text to find the <code>needle</code> in
 * @param string needle the substring you want to find
 * @access private
 * @return int the number of occurrences
 */
function _subStringCount(haystack,needle)
{
	var pos;
	var count = 0;
	for(var i = 0;i < haystack.length;i++)
	{
		pos = haystack.indexOf(needle);
		if(pos != -1)
		{
			count++;
			haystack = haystack.substr(pos + 3,haystack.length - pos + 3);
		}
		else
			break;
	}

	return count;
}

/**
 * the sort-function for the closing tags
 * will sort the tags in the order of the tag-positions
 *
 * @param array a the first element
 * @param array b the second element
 * @access private
 * @return int a negative value if b > a, a positive value if a > b, or 0 if a == b
 */
function _numericSort(a,b)
{
	return a[0] - b[0];
}
