/*
 * Example:
 *********************************************************************************************
 *
 * <script type="text/javascript" src="bbcode.js"></script>
 * <body>
 *   <form name="post" onsubmit="return checkForm(this)">
 *     <textarea name="message"></textarea>
 *     <input type="button" value="test" name="addbbcode0" onClick="bbstyle(0)">
 *     <input type="button" value="test" onClick="bbfontstyle('[test]', '[/test]')">
 *   </form>
 * </body>
 *
 *********************************************************************************************
 *
 * Notable (external) functions:
 *   checkForm()
 *   bbfontstyle()
 *   bbstyle()
 *
 * Internal functions:
 *   getarraysize()
 *   arraypush()
 *   arraypop()
 *   mozWrap()
 *   storeCaret()
 */


/*
 * bbtags = array of all tags, which are available on the site. Format:
 *   '[opentab]', '[closetag]',
 */
bbtags = new Array('[b]', '[/b]',
                   '[i]', '[/i]',
                   '[u]', '[/u]',
                   '[s]', '[/s]',
                   '[raw]', '[/raw]',
                   '[link]', '[/link]',
                   '[quote]', '[/quote]');

/*
 * Initializing variables:
 *   theSelection = selected text with the mouse (false if none)
 *   bbcode = opened bbcode tags (so we can determine when to close them)
 */
var theSelection = false;
bbcode = new Array();

/*
 * Determines user's explorer type and version.
 */
var clientPC  = navigator.userAgent.toLowerCase();
var clientVer = parseInt(navigator.appVersion);

var is_ie  = ((clientPC.indexOf("msie")       != -1) &&
              (clientPC.indexOf("opera")      == -1));
var is_nav = ((clientPC.indexOf('mozilla')    != -1) &&
              (clientPC.indexOf('spoofer')    == -1) &&
              (clientPC.indexOf('compatible') == -1) &&
              (clientPC.indexOf('opera')      == -1) &&
              (clientPC.indexOf('webtv')      == -1) &&
              (clientPC.indexOf('hotjava')    == -1));
var is_win = ((clientPC.indexOf("win")        != -1) ||
              (clientPC.indexOf("16bit")      != -1));
var is_mac =  (clientPC.indexOf("mac")        != -1);
var is_moz = 0;

/*
 * getarraysize()
 *
 *  Input:
 *    thearray = array
 *
 *  Output:
 *    an integer
 *
 *  Description: Outputs number of elements found in array.
 */
function getarraysize(thearray)
{
  /*
   * Loop all elements of the array and if we reach an element
   * like undefined or "" or null, we decide that we hit
   * the rock (end of array).
   */
  for (i = 0; i < thearray.length; i++) {
    if ((thearray[i] == "undefined") ||
        (thearray[i] == "") ||
        (thearray[i] == null)) {
      return i;
    }
  }

  return thearray.length;
}

/*
 * arraypush()
 *
 *  Input:
 *    thearray = array
 *    value = value to put in array
 *
 *  Output:
 *    nothing
 *
 *  Description: Pushes an element at the end of the array.
 */
function arraypush(thearray, value)
{
  thearray[getarraysize(thearray)] = value;
}

/*
 * arraypop()
 *
 *  Input:
 *    thearray = array
 *
 *  Output:
 *    last element of the array
 *
 *  Description: Deletes last element of the array and returns it.
 */
function arraypop(thearray)
{
  /*
   * Get last value, delete, and return.
   */
  thearraysize = getarraysize(thearray);
  retval = thearray[thearraysize - 1];
  delete thearray[thearraysize - 1];
  return retval;
}

/*
 * checkForm()
 *
 *  Input:
 *
 *  Output:
 *   true or false
 *
 *  Description: Checks if the message in the textarea is long enough and also
 *               checks if there are any not closed tags and closes them.
 */
function checkForm()
{
  /*
   * Initialize var (textarea name && formErrors).
   */
  var txtarea = document.post.comment;
  formErrors = false;

  /*
   * Length check.
   */
  if (txtarea.value.length < 2) {
    formErrors = "You must input a message.";
  }

  /*
   * If there are any errors, output them with alert(), else
   */
  if (formErrors) {
    alert(formErrors);
    return false;
  /*
   * close all tags.
   */
  } else {
    bbstyle(-1);
    return true;
  }
}

/*
 * bbfontstyle()
 *
 *  Input:
 *   bbopen = start [bbtag] (for example [b])
 *   bbclose = end [bbtag] (for example [/b])
 *
 *  Output:
 *   nothing (read description)
 *
 *  Description: Inserts [bbtag][/bbtag] at the position where the cursor of
 *               the mouse is located, or in the beginning and in the end of
 *               the selected text in the textarea.
 */
function bbfontstyle(bbopen, bbclose)
{
  /*
   * Initialize var (textarea name).
   */
  var txtarea = document.post.comment;

  /*
   * If we are using windows and IE >= 4.x, try using the good old
   * M$ style when inserting [bbtag].
   */
  if ((clientVer >= 4) && is_ie && is_win) {
    /*
     * Grab the selected text.
     */
    theSelection = document.selection.createRange().text;

    /*
     * If there isn't a text selected, just input the [bbtags] at the end &&
     * focus on the textarea.
     */
    if (!theSelection) {
      txtarea.value += bbopen + bbclose;
      txtarea.focus();
      return;
    }

    /*
     * Else we have selected a text. Place in the beginning start [bbtag] and
     * in the end end [bbtag]. Focus on the textarea.
     */
    document.selection.createRange().text = bbopen + theSelection + bbclose;
    txtarea.focus();
    return;
  /*
   * Hack for selected text in other browsers.
   */
  } else if (txtarea.selectionEnd && (txtarea.selectionEnd - txtarea.selectionStart > 0)) {
   /*
    * Call mozWrap with the approperiate args, and we can relax for now...
    */
    mozWrap(txtarea, bbopen, bbclose);
    return;
  } else {
    /*
     * No text selected, not using IE, then place end && start [bbtags] at the end.
     */
    txtarea.value += bbopen + bbclose;
    txtarea.focus();
  }

  /*
   * Stores the caret (cursor) position of the textarea.
   */
  storeCaret(txtarea);
}

/*
 * bbstyle()
 *
 *  Input:
 *   bbnumber = even number of bbtag to insert (see bbtags at the beginning)
 *              can also be -1 to close all open tags.
 *
 *  Output:
 *   nothing (read description)
 *
 *  Description: If no text is selected, inserts start [bbtag] (or end [bbtag],
 *               depends whether you already have pressed this tag button),
 *               else it inserts start && end [bbtag] in the beginning and in
 *               the end of the selected area.
 *
 *               Second description - closes all open tags (depends on bbnumber).
 */
function bbstyle(bbnumber)
{
  /*
   * Focus on txtarea && initializing variables:
   *  txtarea = textarea element
   *  donotinsert = true if we must close the tag.
   *  theSelection = selected text with the mouse (false if none)
   *  bblast = index of the element, that is gonna be closed, in the
   *           bbcode array
   */
  var txtarea = document.post.comment;
  txtarea.focus();
  donotinsert = false;
  theSelection = false;
  bblast = 0;

  /*
   * Check if we are called with -1, then close all tags...
   */
  if (bbnumber == -1) {
    /*
     * Loop all elements, add the not-closed tag in the end, and remove the
     * * in the button (we place a * in every not-closed-tag button :)).
     */
    while (bbcode[0]) {
      butnumber = arraypop(bbcode) - 1;
      txtarea.value += bbtags[butnumber + 1];
      buttext = eval('document.post.addbbcode' + butnumber + '.value');
      eval('document.post.addbbcode' + butnumber + '.value ="' + buttext.substr(0,(buttext.length - 1)) + '"');
    }
    txtarea.focus();
    return;
  }

  /*
   * If we are using windows and IE >= 4.x, try using the good old
   * M$ style when inserting [bbtag].
   */
  if ((clientVer >= 4) && is_ie && is_win) {
    /*
     * Grab the selected text.
     */
    theSelection = document.selection.createRange().text;

    /*
     * If we have selected a text, place in the beginning start [bbtag] and
     * in the end end [bbtag]. Focus on the textarea.
     */
    if (theSelection) {
      document.selection.createRange().text = bbtags[bbnumber] + theSelection + bbtags[bbnumber+1];
      txtarea.focus();
      theSelection = '';
      return;
    }
  /*
   * Hack for selected text in other browsers. Call mozWrap with the
   * approperiate args, and we can relax for now...
   */
  } else if (txtarea.selectionEnd && (txtarea.selectionEnd - txtarea.selectionStart > 0)) {
    mozWrap(txtarea, bbtags[bbnumber], bbtags[bbnumber+1]);
    return;
  }

  /*
   * Determine, whether we must close the tag or not.
   */
  for (i = 0; i < bbcode.length; i++) {
    if (bbcode[i] == bbnumber+1) {
      bblast = i;
      donotinsert = true;
    }
  }

  /*
   * Closing tag...
   */
  if (donotinsert) {
    /*
     * Close all open tags until this one (recrusive closing...
     * if we have [b] opened and [i] after that, and we want to close
     * [b], then [i] will be closed too).
     *
     * Also modify button value to value* and delete it from the bbcode array.
     */
    while (bbcode[bblast]) {
      butnumber = arraypop(bbcode) - 1;
      txtarea.value += bbtags[butnumber + 1];
      buttext = eval('document.post.addbbcode' + butnumber + '.value');
      eval('document.post.addbbcode' + butnumber + '.value ="' + buttext.substr(0, (buttext.length - 1)) + '"');
    }

    /*
     * Focus on the txtarea.
     */
    txtarea.focus();
    return;
  /*
   * Opening tag.
   */
  } else {
    /*
     * Place tag in the end, insert it in the bbcode array and modify value
     * of button to value*. In the end focus on the txtarea.
     */
    txtarea.value += bbtags[bbnumber];
    arraypush(bbcode, bbnumber + 1);
    eval('document.post.addbbcode' + bbnumber + '.value += "*"');

    txtarea.focus();
    return;
  }

  /*
   * Stores the caret (cursor) position of the textarea.
   */
  storeCaret(txtarea);
}

/*
 * mozWrap()
 *
 *  Input:
 *   txtarea = textarea/textfield element
 *   open = start [bbtag] (for example [b])
 *   close = end [bbtag] (for example [/b])
 *
 *  Output:
 *   nothing (read description)
 *
 *  Description: Hack for any non IE browser, to insert start && end [bbtag]
 *               in the beginning and in the end of the selected area in the
 *               textarea.
 */
function mozWrap(txtarea, open, close)
{
  /*
   * Initializes variables:
   *  selLength = length of text in the txtarea
   *  selStart = position of the first selected symbol
   *  selEnd = position of the last selected symbol
   */
  var selLength = txtarea.textLength;
  var selStart = txtarea.selectionStart;
  var selEnd = txtarea.selectionEnd;

  /*
   * s1 = text from the beginning to the first selected symbol
   * s2 = text from the first selected symbol to the last selected symbol
   * s3 = text from the last selected symbol to the end of the text
   */
  var s1 = (txtarea.value).substring(0, selStart);
  var s2 = (txtarea.value).substring(selStart, selEnd)
  var s3 = (txtarea.value).substring(selEnd, selLength);

  /*
   * And finally we just stick it all together - with glue :)
   *
   */
  txtarea.value = s1 + open + s2 + close + s3;

  return;
}

/*
 * storeCaret()
 *
 *  Input:
 *   textEl = textarea/textfield element
 *
 *  Output:
 *   nothing (read description)
 *
 *  Description: Stores the caret (cursor) position of the textarea.
 */
function storeCaret(textEl)
{
  if (textEl.createTextRange) {
    textEl.caretPos = document.selection.createRange().duplicate();
  }
}
