
function zLinkFormatter( io_formatter ) {
  this.mo_formatter = io_formatter;
}

zLinkFormatter.prototype.format = function( is_string ) {

  var ls_string = is_string;

  var ls_htmlToken = ' ' + String.fromCharCode(260) + ' ';
  var ls_anchorToken = ' ' + String.fromCharCode(261) + ' ';

  var lr_anchor = /<a[^>]*>.*<\/a>/ig;
  var lr_html = /<\/?(?:[A-Z]\w*)\b[^>]*>/ig;
  var lr_htmlTokens = new RegExp( ls_htmlToken, 'g');
  var lr_anchorTokens = new RegExp( ls_anchorToken, 'g' );

  var la_html = ls_string.match( lr_html );
  var la_anchors = ls_string.match( lr_anchor );

  // replace all <a></a> and HTML tags with tokens
  ls_string = ls_string.replace( lr_anchor, ls_anchorToken );
  ls_string = ls_string.replace( lr_html, ls_htmlToken );

  // replace
  var la_wordList = ls_string.split(' ');
  for( var i = 0; i < la_wordList.length; i++ ) {

    // If the word is a URL
    if( zFormatterUtils.isURL( la_wordList[i] ) ) {
      la_wordList[i] = la_wordList[i].replace( zFormatterUtils.mr_url, this.replaceURL.bind(this) );
    // The word isn't a URL
    } else {
      // Put normal spaces back into brackets so they wordwrap
      la_wordList[i] = la_wordList[i].replace('&#032;',' ','g');
    }
  }
  ls_string = la_wordList.join(' ');

  if( lr_htmlTokens.test( ls_string ) ) {
    var la_tokens = ls_string.match( lr_htmlTokens );
    for( i = 0; i < la_tokens.length; i++ ){
      ls_string = ls_string.replace( ls_htmlToken, la_html[i] );
    }
  }
  if( lr_anchorTokens.test( ls_string ) ) {
    var la_tokens = ls_string.match( lr_anchorTokens );
    for( i = 0; i < la_tokens.length; i++ ){
      ls_string = ls_string.replace( ls_anchorToken, la_anchors[i] );
    }
  }
  
  ls_string = ls_string.replace(/<a\s/gi,'<a target="_blank" ');
  
  if( this.mo_formatter != null ) {
    return this.mo_formatter.format(ls_string);
  } else {
    return ls_string;
  }
}


// repURL -- changes urls to links
zLinkFormatter.prototype.replaceURL = function( ) {
  var ls_url = arguments[1];
  var ls_title = arguments[2];
  if( ls_title ) { ls_title = ls_title + ' - ' + ls_url; }
  else { ls_title = ls_url; }
  var ls_dis = ( ls_url.length > 50 ) ? ls_url.substr(0,50) + "..." : ls_url;
  if( ls_url.indexOf('://') == -1 ) { ls_url = 'http://' + ls_url; }
  return '<a href="' + ls_url + '" title="' + ls_title + '">' + ls_dis + '</a>';
}


/*---------------------------------------------------------------------------*
 * -- zFormatterUtils
 *---------------------------------------------------------------------------*
 *  Utility methods for filtering text (replacing,fixing,finding URLS, etc)
 *---------------------------------------------------------------------------*/

function zFormatterUtils() {}
zFormatterUtils.replaceURLSpaces = function( is_url ) {
  // for replacing spaces with %20 between the first / and first . if the first . is followed by an extension
  var lr_urlSpaces = /((?:ft|ht)tp(?:s)?:\/\/|www)[^\/]+[^\.]+\.(?:htm|php|asp|jsp|jpg|jpeg|jpe|gif|png|bmp|wav)/gi;
  return is_url.replace( lr_urlSpaces, function(s){return s.replace(' ','%20','g')} );
};

zFormatterUtils.replaceAsciiSpaces = function(is_url) {
  return is_url.replace(' ','&#032;','g');
};

// tld - com|edu|biz|gov|info|mil|net|org..etc "[a-z]{2}\b" kept getting false positives
// image formats - jpg|jpeg|jpe|gif|png|bmp
// web extentions - html|htm|jsp|asp|php|css|js
zFormatterUtils.mr_url = /^(?:\s+)?((?:(?:ft|ht)tps?:\/\/)?(?:(?:[^\s\.@\/]+\.)+(?:(?:com|edu|biz|gov|info|mil|net|org|name|pro|aero|coop|jobs|tel|travel|asia|[a-z]{2})\b)|(?:\d{1,3}\.){3}\d{1,3}\b)\/?(?:[!\w\-\.,\@\?\^=%&;:\/\*\~\+#\(\)]*[\w\-\@?^=%&;\/\~\+#\(\)])?)(?:\[(\S*)\])?(?:\s+)?$/gi;
zFormatterUtils.mr_img   = /^(?:\s+)?((?:(?:ft|ht)tps?:\/\/)?[\w\-_]+(?:\.[\w\-_]+)+(?:[!\w\-\.,\@\?\^=%&;:\*\/~\+#\(\)]*[\w\-\@\?^=%&;\/~\+#\(\)])\.(?:jpg|jpeg|jpe|gif|png|bmp))(?:[^\s\[]*)?(?:\[(\S*)\])?(?:\s+)?$/gi;
zFormatterUtils.mr_media = /^(?:\s+)?((?:(?:ft|ht)tps?:\/\/)?[\w\-_]+(?:\.[\w\-_]+)+(?:[!\w\-\.,\@\?\^=%&;:\*\/~\+#\(\)]*[\w\-\@\?^=%&;\/~\+#\(\)])\.(?:wav|wave|mp3|mp4|wmv|wma|ogv))(?:[^\s\[]*)?(?:\[(\S*)\])?(?:\s+)?$/gi;

zFormatterUtils.isURL = function( is_string ) { return zFormatterUtils.mr_url.test( is_string ); };
zFormatterUtils.isImgURL = function( is_string ) { return zFormatterUtils.mr_img.test( is_string ); };
zFormatterUtils.isMediaURL = function( is_string ) { return zFormatterUtils.mr_media.test( is_string ); };

// Splits words over x chracters to be max characters long
zFormatterUtils.splitLongWord = function( is_string, in_max ) {
  if( is_string.length > in_max ) {
    is_string = is_string.substr( 0, in_max )
                + '-<br />'
                + zFormatterUtils.splitLongWord( is_string.substring( in_max, is_string.length ), in_max );
  }
  return is_string;
};

// Converts bbcodes to HTML
zFormatterUtils.bbCodeToHTML = function( is_string ) {
  var ls_result = is_string;
  ls_result = ls_result.replace( /\[list\](.+?)\[\/list\]/gi, '<ul><li>$1<\/ul>' );
  ls_result = ls_result.replace( /\[img\](.+?)\[\/img\]/gi, '<img src=\"$1\" alt=\"$1\" title=\"$1\" \/>' );
  ls_result = ls_result.replace( /\[(b|i|u|code)\](.+?)\[\/\1\]/gi, '<$1>$2<\/$1>' );
  ls_result = ls_result.replace( /\[color=\"(.+?)\"\](.+?)\[\/color\]/gi, '<span style=\"color:$1\">$2<\/span>' );
  ls_result = ls_result.replace( /\[size=\"(.+?)\"\](.+?)\[\/size\]/gi, '<span style=\"font-size:$1%\">$2<\/span>' );
  ls_result = ls_result.replace( /\[url=\"(.+?)\"\](.+?)\[\/url\]/gi, '<a href=\"$1\">$2<\/a>' );
  ls_result = ls_result.replace( /\[mail=\"(.+?)\"\](.+?)\[\/mail\]/gi, '<a href=\"mailto:$1\">$2<\/a>' );
  // repeat until no more changes are made/found
  if( ls_result != is_string ) {
    return zFormatterUtils.bbCodeToHTML( ls_result );
  } else {
    return ls_result;
  }
};
