// a set of text modifiers function, like replacing smileys with images
// or highlighting links

// ------------------------------------------------------------------
// peforms a predefined order of text modifiers to the desired
// string
// remember, that maxImageWidth, SMILEYS_PATH and maxWordLength
// must be defined before this function call
function prepareText( input )
{
  return shortUpLongWords( 
    highlightUrls( 
    replaceSymsWithSmileys( 
    makeWebUploadTagsValid( 
    makeImagesTagsValid( 
    prettyUpText( 
      
      input 
      
    ),                // prettyUpText
    maxImageWidth )   // makeImagesTagsValid
    ),                // makeVideosTagsValid
    SMILEYS_PATH )    // replaceSymsWithSmileys
    ),                // highlightUrls
    maxWordLength );  // shortUpLongWords
}

// ------------------------------------------------------------------
// Replaces ":)", ":(" and so on with images corresponded 
function replaceSymsWithSmileys( input, smileysPath )
{
  var patternsLeft = "([\\s\\)\\(\\.,!\\?>;:]|^)";
  var patternsRight = "([\\s\\)\\(\\.,!\\?<:]|$)";
  
  var patterns = new Array();
  patterns[0]  = "(:-?\\))"; // :-)
  patterns[1]  = "(;-?\\))"; // ;-)
  patterns[2]  = "(:-?\\()"; // :-(
  patterns[3]  = "(:-?P)";  // :-P
  patterns[4]  = "(B-?\\))"; // B-)
  patterns[5]  = "(\\&gt;:-?\\&lt;)";  // >:-< angry
  patterns[6]  = "(:-?[\\\\\\/])";  // :-\
  patterns[7]  = "(=-?O)";  // =-O
  patterns[8]  = "(:-?\\&gt;)";  // :->
  patterns[9]  = "(:-?D)";  // :-D
  patterns[10] = "(\\(\\*_\\*\\))";  // (*_*) in love
  patterns[11] = "(\\&lt;3)";  // <3 heart
  patterns[12] = "(\\(9_9\\))";  // (9_9) rolling eyes
  patterns[13] = "(:[,\\']-?\\()";  // :,-(
  patterns[14] = "(O:-?\\))";  // O:-)
  patterns[15] = "(O_o)";  // O_o

  var replacementsLeft = "$1<img class='smiley' src='" + smileysPath;
  var replacementsRight = "' />$3";
  var replacements = new Array();
  replacements[0]  = "sm11.gif";
  replacements[1]  = "sm10.gif";
  replacements[2]  = "sm5.gif";
  replacements[3]  = "sm14.gif";
  replacements[4]  = "sm6.gif";
  replacements[5]  = "sm13.gif";
  replacements[6]  = "sm15.gif";
  replacements[7]  = "sm2.gif";
  replacements[8]  = "sm7.gif";
  replacements[9]  = "sm1.gif";
  replacements[10] = "sm4.gif";
  replacements[11] = "sm3.gif";
  replacements[12] = "sm8.gif";
  replacements[13] = "sm9.gif";
  replacements[14] = "sm12.gif";
  replacements[15] = "sm16.gif";

  var re = new RegExp();
  for ( var i in patterns )
  {
    //alert(patternsLeft + patterns[i] + patternsRight);
    re.compile( patternsLeft + patterns[i] + patternsRight, "gim");
    input = input.replace( re, replacementsLeft + replacements[i] + replacementsRight );
  };
  
  // done
  return input;
}

// ------------------------------------------------------------------
// replaces URL strings with anchors to them
function highlightUrls( input )
{
  var patterns = new Array();
  patterns[0]  = "<a>([^<]+)</a>";

  var replacements = new Array();
  replacements[0]  = "<a href='$1'>$1</a>";

  var re = new RegExp();
  for ( var i in patterns )
  {
    //alert(patternsLeft + patterns[i] + patternsRight);
    re.compile( patterns[i], "gim");
    input = input.replace( re, replacements[i] );
  };
  
  // done
  return input;
  
/*
  var patterns = Array();
  patterns[0]  = "([^\\\"]|^)(http:\\/\\/[^\\s<]+)\\&nbsp;";
  patterns[1]  = "([^\\\"]|^)(ftp:\\/\\/[^\\s<]+)\\&nbsp;";
  patterns[2]  = "([^\\\"]|^)(https:\\/\\/[^\\s<]+)\\&nbsp;";
  patterns[3]  = "([^\\\"\\/]|^)(www\\.[^\\s<]+)\\&nbsp;";
  patterns[4]  = "([^\\\"]|^)(http:\\/\\/[^\\s<]+)";
  patterns[5]  = "([^\\\"]|^)(ftp:\\/\\/[^\\s<]+)";
  patterns[6]  = "([^\\\"]|^)(https:\\/\\/[^\\s<]+)";
  patterns[7]  = "(\\s|^)(www\\.[^\\s<]+)";

  var replacements = Array();
  replacements[0]  = "$1$2 ";
  replacements[1]  = "$1$2 ";
  replacements[2]  = "$1$2 ";
  replacements[3]  = "$1$2 ";
  replacements[4]  = "$1<a href='$2'>$2</a>";
  replacements[5]  = "$1<a href='$2'>$2</a>";
  replacements[6]  = "$1<a href='$2'>$2</a>";
  replacements[7]  = "$1<a href='http://$2'>$2</a>";

  var re = new RegExp();
  for ( var i in patterns )
  {
    //alert(patternsLeft + patterns[i] + patternsRight);
    re.compile( patterns[i], "gim");
    input = input.replace( re, replacements[i] );
  };
  
  // done
  return input;
*/
}

// ------------------------------------------------------------------
// shorts up the long words in tags, not in attributes
function shortUpLongWords( input, maxWordLength )
{
  var output = "";
  // is true when currently inside the <> bracket
  var inTag = false;
  
  var leftTags = input.split( "<" );
  if ( leftTags.length == input.length )
  {
    leftTags = new Array();
    leftTags[0] = input;
  };  
  for ( var leftI = 0; leftI < leftTags.length; leftI++ )
  {
    if ( leftI > 0 )
      inTag = true;
    var rightTags = leftTags[leftI].split( ">" );
    if ( rightTags.length == leftTags[leftI].length )
    {
      rightTags = new Array();
      rightTags[0] = leftTags[leftI];
    };  
    for ( var rightI = 0; rightI < rightTags.length; rightI++ )
    {
      if ( rightI > 0 )
        inTag = false;
  
      // splitting into words
      var spaceWords = rightTags[rightI].split( " " );
      if ( spaceWords.length == rightTags[rightI].length )
      {
        spaceWords = new Array();
        spaceWords[0] = rightTags[rightI];
      };  
      for ( var spaceI = 0; spaceI < spaceWords.length; spaceI++ )
      {
        var nbspWords = spaceWords[spaceI].split( "&nbsp;" );
        
        if ( nbspWords.length == spaceWords[spaceI].length )
        {
          nbspWords = new Array();
          nbspWords[0] = spaceWords[spaceI];
        };  
        for ( var nbspI = 0; nbspI < nbspWords.length; nbspI++ )
        {
          // the current word
          var word = nbspWords[nbspI];
          // keeps the previous symbol
          var previousSymbol;
          
          // splitting into symbols
          var symbols = new Array();
          var symbolsI = -1;
          if ( word.length > 0 )
            for ( var wordI = 0; wordI < word.length; wordI++ )
            {
              // the symbol, that should be added into the current symbol code
              if ( symbols[symbolsI] && 
                   ( symbols[symbolsI].charAt(0) == "&" ) && 
                   ( symbols[symbolsI].charAt(symbols[symbolsI].length-1) != ";" ) )
              {
                symbols[symbolsI] += word.charAt(wordI);
              }
              else
              {
                symbolsI++;
                symbols[symbolsI] = word.charAt(wordI);
              };
            };
          
          // checking the length of the current word and shorting it, if required
          if ( symbols.length > maxWordLength && !inTag )
          {
            // the symbols, that should be deleted indicies range
            var firstDelSymbol = ( maxWordLength - 1 ) * 0.75;
            var lastDelSymbol = symbols.length - ( maxWordLength - firstDelSymbol );
            var shortSymbols = symbols.slice( 0, firstDelSymbol-1 );
            shortSymbols[shortSymbols.length] = "...";
            shortSymbols = shortSymbols.concat( symbols.slice( lastDelSymbol-1 ) );
            delete symbols;
            symbols = shortSymbols;
          };
          
          // adding to the output
          //if ( symbols.length > 0 )
          //  for ( var symbolsI = 0; symbolsI < symbols.length; symbolsI++ )
          //    output += symbols[symbolsI];
          output += symbols.join( "" );
          if ( nbspI < nbspWords.length - 1 )
            output += "&nbsp;";
        };
        if ( spaceI < spaceWords.length - 1 )
          output += " ";
      };

      if ( rightI < rightTags.length - 1 )
        output += ">";
    };
    if ( leftI < leftTags.length - 1 )
      output += "<";
  };
  return output;
}

// ------------------------------------------------------------------
// obtains the images dimensions and, if they are wider, than the
// limit, - scales them to the limited width
function makeImagesTagsValid( input, maxImageWidth )
{
  // searching for images in the source
  var inputLeft = input;
  var output = "";
  while ( true )
  {
    // searching for the img tag start
    var leftI = inputLeft.search( /<img[^>]+>[^<]+<\/img>/mi );
    // checking, if there is something to do
    if ( leftI < 0 )
    {
      output += inputLeft;
      break;
    };
    
    // adding the part before the image to the output
    if ( leftI > 0 )
      output += inputLeft.slice( 0, leftI );
      
    // the part of the input, untreated is:
    inputLeft = inputLeft.slice( leftI );
    
    // searching for the end of the image
    var rightI = inputLeft.search( /<\/img>/mi ) + 5;
    // checking, if there is a error in tags
    if ( rightI < 5 )
    {
      output += inputLeft;
      break;
    };
    
    // obtaining the image tag properties
    var imageTag = inputLeft.slice( 0, rightI+1 );
    var width = parseInt( imageTag.match( /width\s*=\s*[\'\"](\d+)/mi )[1] );
    var height = parseInt( imageTag.match( /height\s*=\s*[\'\"](\d+)/mi )[1] );
    var src = imageTag.match( />([^<]+)</mi )[1];
    // scaling, if required
    if ( width > maxImageWidth )
    {
      var scale = 0.5 + maxImageWidth / width - 0.5;
      width = Math.floor( scale * width + 0.5 );
      height = Math.floor( scale * height + 0.5 );
      var imageTag = "<a href='" + src + "'><img src='"+src+"' width='"+width+"' height='"+height+"' /></a>";
    }
    else
      var imageTag = "<img src='"+src+"' width='"+width+"' height='"+height+"' />";
    // and adding to the output
    output += imageTag;
    
    // the part of the input, untreated is:
    inputLeft = inputLeft.slice( rightI+1 );
  };
  
  // done
  return output;
  
/*
  // searching for images in the source
  var inputLeft = input;
  var output = "";
  while ( true )
  {
    // searching for the img tag start
    var leftI = inputLeft.search( /<img[^>]+>/mi );
    // checking, if there is something to do
    if ( leftI < 0 )
    {
      output += inputLeft;
      break;
    };
    
    // adding the part before the image to the output
    if ( leftI > 0 )
      output += inputLeft.slice( 0, leftI-1 );
      
    // the part of the input, untreated is:
    inputLeft = inputLeft.slice( leftI );
    
    // searching for the end of the image
    var rightI = inputLeft.search( />/mi );
    // checking, if there is a error in tags
    if ( rightI < 0 )
    {
      output += inputLeft;
      break;
    };
    
    // obtaining the image tag properties
    var imageTag = inputLeft.slice( 0, rightI+1 );
    var width = parseInt( imageTag.match( /width\s*=\s*[\'\"](\d+)/mi )[1] );
    var height = parseInt( imageTag.match( /height\s*=\s*[\'\"](\d+)/mi )[1] );
    var src = imageTag.match( /src\s*=\s*[\'\"]([^\'\"]+)/mi )[1];
    // scaling, if required
    if ( width > maxImageWidth )
    {
      var scale = 0.5 + maxImageWidth / width - 0.5;
      width = Math.floor( scale * width + 0.5 );
      height = Math.floor( scale * height + 0.5 );
      var imageTag = "<a href=\"" + src + "\">" + 
        imageTag.replace( /(width\s*=\s*[\'\"])(\d+)/mi, "$1" + width )
                .replace( /(height\s*=\s*[\'\"])(\d+)/mi, "$1" + height ) +
        "</a>";
    };
    // and adding to the output
    output += imageTag;
    
    // the part of the input, untreated is:
    inputLeft = inputLeft.slice( rightI+1 );
  };
  
  // done
  return output;
*/
}

// ------------------------------------------------------------------
// obtains the videos, audios and other upload services type and replaces the tag
// with valid constructions for this service
function makeWebUploadTagsValid( input )
{
  // performing replacements for different video services
  var output = input.replace( 
    /<webupload>[^<]*youtube.com[^<]*\?v=([^<\?]+)[^<]*<\/webupload>/gmi, 
    '<object width="425" height="355"><param name="movie" value="http://www.youtube.com/v/$1"></param><param name="wmode" value="transparent"></param><embed src="http://www.youtube.com/v/$1" type="application/x-shockwave-flash" wmode="transparent" width="425" height="355"></embed></object>'
  );
  output = output.replace( 
    /<webupload>[^<]*loadup.ru[^<]*\?id=([^<\?]+)[^<]*<\/webupload>/gmi, 
    '<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="400" height="330"><param name="movie" value="http://pics.loadup.ru/scrubber_custom8.swf?file=$1&bufferTime=3&autoStart=false&str_lang=rus&xmlsource=http%3A%2F%2Fpics.loadup.ru%2Fskin.xml" /><param name="allowScriptAccess" value="always" /><param name="allowFullScreen" value="true" /><param name="bgcolor" value="#ffffff" /><embed src="http://pics.loadup.ru/scrubber_custom8.swf?file=$1&bufferTime=3&autoStart=false&str_lang=rus&xmlsource=http%3A%2F%2Fpics.loadup.ru%2Fskin.xml" quality="high" allowscriptaccess="always" allowfullscreen="true" wmode="window"  width="400" height="330" type="application/x-shockwave-flash"></embed></object>'
  );
  output = output.replace( 
    /<webupload>[^<]*rutube.ru[^<]*\?v=([0-9a-f]+)[^<]*<\/webupload>/gmi, 
    '<object width="400" height="353"><param name="movie" value="http://video.rutube.ru/$1"></param><param name="wmode" value="window"></param><param name="allowFullScreen" value="true"></param><embed src="http://video.rutube.ru/$1" type="application/x-shockwave-flash" wmode="window" width="400" height="353" allowFullScreen="true" ></embed></object>'
  );
  // default processing: inserting as a link
  output = output.replace( 
    /<webupload>[^<]*http:\/\/([^<\?\/]+)([^<]*)<\/webupload>/gmi, 
    '<a href="http://$1$2">$1</a>'
  );

  // done
  return output;
}

// ------------------------------------------------------------------
// performs some formatting on the text to make it look better
function prettyUpText( input )
{
  // formatting lines as paragraphs if they're not starting from tags
  // also replacing <br /> tag with the new line symbol
  var lines = input.split( "<br />" );
  
  var preOpened = false;
  
  for ( var lineI = 0; lineI < lines.length; lineI++ )
  {
    if ( lines[lineI].match( /^.*<pre>.*$/i ) )
      preOpened = true;
    if ( lines[lineI].match( /^.*<\/pre>.*$/i ) )
      preOpened = false;

    if ( !lines[lineI].match( /^\s*<\/?(h|img|ul|ol|li|table|tr|td)/i ) &&
         !preOpened )
      lines[lineI] = "<p>" + lines[lineI] + "</p>";
  };
  
  // done
  return lines.join( "\n" );
}

// ------------------------------------------------------------------
// Replaces &amp; &quot; and other HTML entities with their right ASCII encoded
// symbols
function decodeHtmlEntities( input )
{
  var htmlEntities = new Array
  ( 
    "&amp;", 
    "&gt;", 
    "&lt;", 
    "<br />",
    "&nbsp;", 
    "&iexcl;",
    "&cent;",
    "&pound;",
    "&curren;",
    "&yen;",
    "&brvbar;",
    "&sect;",
    "&uml;",
    "&copy;",
    "&ordf;",
    "&laquo;",
    "&not;",
    "&shy;",
    "&reg;",
    "&macr;",
    "&deg;",
    "&plusmn;",
    "&sup2;",
    "&sup3;",
    "&acute;",
    "&micro;",
    "&para;",
    "&middot;",
    "&cedil;",
    "&sup1;",
    "&ordm;",
    "&raquo;",
    "&frac14;",
    "&frac12;",
    "&frac34;",
    "&iquest;",
    "&Agrave;",
    "&Aacute;",
    "&Acirc;",
    "&Atilde;",
    "&Auml;",
    "&Aring;",
    "&AElig;",
    "&Ccedil;",
    "&Egrave;",
    "&Eacute;",
    "&Ecirc;",
    "&Euml;",
    "&Igrave;",
    "&Iacute;",
    "&Icirc;",
    "&Iuml;",
    "&ETH;",
    "&Ntilde;",
    "&Ograve;",
    "&Oacute;",
    "&Ocirc;",
    "&Otilde;",
    "&Ouml;",
    "&times;",
    "&Oslash;",
    "&Ugrave;",
    "&Uacute;",
    "&Ucirc;",
    "&Uuml;",
    "&Yacute;",
    "&THORN;",
    "&szlig;",
    "&agrave;",
    "&aacute;",
    "&acirc;",
    "&atilde;",
    "&auml;",
    "&aring;",
    "&aelig;",
    "&ccedil;",
    "&egrave;",
    "&eacute;",
    "&ecirc;",
    "&euml;",
    "&igrave;",
    "&iacute;",
    "&icirc;",
    "&iuml;",
    "&eth;",
    "&ntilde;",
    "&ograve;",
    "&oacute;",
    "&ocirc;",
    "&otilde;",
    "&ouml;",
    "&divide;",
    "&oslash;",
    "&ugrave;",
    "&uacute;",
    "&ucirc;",
    "&uuml;",
    "&yacute;",
    "&thorn;",
    "&yuml;",
    "&quot;", 
    "&#039;", 
    "&acute;", 
    "&sbquo;", 
    "&bdquo;", 
    "&lsquo;", 
    "&rsquo;", 
    "&ldquo;", 
    "&rdquo;", 
    "&laquo;", 
    "&raquo;",
    "&mdash;"
  );
  var characters = new Array
  ( 
    "&",
    ">",
    "<",
    "\n",
    String.fromCharCode( 0xA0 ),
    String.fromCharCode( 0xA1 ),
    String.fromCharCode( 0xA2 ),
    String.fromCharCode( 0xA3 ),
    String.fromCharCode( 0xA4 ),
    String.fromCharCode( 0xA5 ),
    String.fromCharCode( 0xA6 ),
    String.fromCharCode( 0xA7 ),
    String.fromCharCode( 0xA8 ),
    String.fromCharCode( 0xA9 ),
    String.fromCharCode( 0xAA ),
    String.fromCharCode( 0xAB ),
    String.fromCharCode( 0xAC ),
    String.fromCharCode( 0xAD ),
    String.fromCharCode( 0xAE ),
    String.fromCharCode( 0xAF ),
    String.fromCharCode( 0xB0 ),
    String.fromCharCode( 0xB1 ),
    String.fromCharCode( 0xB2 ),
    String.fromCharCode( 0xB3 ),
    String.fromCharCode( 0xB4 ),
    String.fromCharCode( 0xB5 ),
    String.fromCharCode( 0xB6 ),
    String.fromCharCode( 0xB7 ),
    String.fromCharCode( 0xB8 ),
    String.fromCharCode( 0xB9 ),
    String.fromCharCode( 0xBA ),
    String.fromCharCode( 0xBB ),
    String.fromCharCode( 0xBC ),
    String.fromCharCode( 0xBD ),
    String.fromCharCode( 0xBE ),
    String.fromCharCode( 0xBF ),
    String.fromCharCode( 0xC0 ),
    String.fromCharCode( 0xC1 ),
    String.fromCharCode( 0xC2 ),
    String.fromCharCode( 0xC3 ),
    String.fromCharCode( 0xC4 ),
    String.fromCharCode( 0xC5 ),
    String.fromCharCode( 0xC6 ),
    String.fromCharCode( 0xC7 ),
    String.fromCharCode( 0xC8 ),
    String.fromCharCode( 0xC9 ),
    String.fromCharCode( 0xCA ),
    String.fromCharCode( 0xCB ),
    String.fromCharCode( 0xCC ),
    String.fromCharCode( 0xCD ),
    String.fromCharCode( 0xCE ),
    String.fromCharCode( 0xCF ),
    String.fromCharCode( 0xD0 ),
    String.fromCharCode( 0xD1 ),
    String.fromCharCode( 0xD2 ),
    String.fromCharCode( 0xD3 ),
    String.fromCharCode( 0xD4 ),
    String.fromCharCode( 0xD5 ),
    String.fromCharCode( 0xD6 ),
    String.fromCharCode( 0xD7 ),
    String.fromCharCode( 0xD8 ),
    String.fromCharCode( 0xD9 ),
    String.fromCharCode( 0xDA ),
    String.fromCharCode( 0xDB ),
    String.fromCharCode( 0xDC ),
    String.fromCharCode( 0xDD ),
    String.fromCharCode( 0xDE ),
    String.fromCharCode( 0xDF ),
    String.fromCharCode( 0xE0 ),
    String.fromCharCode( 0xE1 ),
    String.fromCharCode( 0xE2 ),
    String.fromCharCode( 0xE3 ),
    String.fromCharCode( 0xE4 ),
    String.fromCharCode( 0xE5 ),
    String.fromCharCode( 0xE6 ),
    String.fromCharCode( 0xE7 ),
    String.fromCharCode( 0xE8 ),
    String.fromCharCode( 0xE9 ),
    String.fromCharCode( 0xEA ),
    String.fromCharCode( 0xEB ),
    String.fromCharCode( 0xEC ),
    String.fromCharCode( 0xED ),
    String.fromCharCode( 0xEE ),
    String.fromCharCode( 0xEF ),
    String.fromCharCode( 0xF0 ),
    String.fromCharCode( 0xF1 ),
    String.fromCharCode( 0xF2 ),
    String.fromCharCode( 0xF3 ),
    String.fromCharCode( 0xF4 ),
    String.fromCharCode( 0xF5 ),
    String.fromCharCode( 0xF6 ),
    String.fromCharCode( 0xF7 ),
    String.fromCharCode( 0xF8 ),
    String.fromCharCode( 0xF9 ),
    String.fromCharCode( 0xFA ),
    String.fromCharCode( 0xFB ),
    String.fromCharCode( 0xFC ),
    String.fromCharCode( 0xFD ),
    String.fromCharCode( 0xFE ),
    String.fromCharCode( 0xFF ),
    "\"",
    "'",
    "`",
    "‚",
    "„",
    "‘",
    "’",
    "“",
    "”",
    "«",
    "»",
    "—"
  );

  for ( var i in htmlEntities )
  {
    var re = new RegExp(htmlEntities[i], "gim");
    input = input.replace( re, characters[i] );
  };
  
  // done
  return input;
}

