/**
 * @param  {object} oDictionary  Object containing properties as keys and its values as captions
 * @return void
 *
 * @copyright Amiro.CMS. All rights reserved. Changes are not allowed.
 */
function amiDictionary(oDictionary){
    /**
     * @var {object}
     */
    this.oDictionary = typeof(oDictionary) == 'object' ? oDictionary : {};

    /**
     * Set single caption
     *
     * @param  {string} key
     * @param  {string} caption
     * @return void
     */
    this.set = function(key, caption){
        this.oDictionary[key] = caption;
    }

    /**
     * Append only new captions to dictionary
     *
     * @param  {object} oDictionary  Object containing properties as keys and its values as captions
     * @return void
     */
    this.append = function(oDictionary){
        for(var key in oDictionary){
            if(typeof(this.oDictionary[key]) == 'undefined'){
                this.oDictionary[key] = oDictionary[key];
            }
        }
    }

    /**
     * Append new captions, override obsolete
     *
     * @param  {object} oDictionary  Object containing properties as keys and its values as captions
     * @return void
     */
    this.megre = function(oDictionary){
        for(var key in oDictionary){
            this.oDictionary[key] = oDictionary[key];
        }
    }

    /**
     * Get caption by key
     *
     * @param  {string} key
     * @return {string} | null
     */
    this.get = function(key){
        if(typeof(this.oDictionary[key]) == 'undefined'){
            if(typeof(console) == 'object' && typeof(console.warn) == 'function'){
                // firebug debugging
                console.warn("Undefined dictionary key '" + key + "'");
                console.trace();
            }
            return null;
        }else{
            return this.oDictionary[key];
        }
    }

    /**
     * Parse caption specified by key using variables
     *
     * @param  {string} key
     * @param  {object} oVariables  Object containing properties as keys and its values as captions
     * @return {string} | null
     */
    this.parse = function(key, oVariables){
        var caption = this.get(key);
        if(caption){
            for(var variable in oVariables){
                caption = caption.replace('_' + variable + '_', oVariables[variable]);
            }
        }
        return caption;
    }
}

/**
 * Amiro.CMS text editor
 *
 * @param {string}  Global variable name
 * @param {amiDictionary} oDictionary
 *
 * Textarea editor with pseudo codes and preview support
 * @version 1.0. Last changes: 25/05/2010
 * @copyright Amiro.CMS. All rights reserved. Changes are not allowed.
 */
function amiroTEdit(varName, oDictionary){
    this.isInitialized = false;
    this.currentMode = 'editor';
    this.varName = varName;
    this.editorId = '';
    this.idPreviewDiv = 'amiroTEdDivPreview';
    this.previewButtonObj = undefined;
    this.editorObj = false;
    this.oDictionary = (oDictionary == undefined ? {} : oDictionary);
    this.isIE = true;
    this.useNoIndex = false;
    this.fontHeight = 15;
    this.regTextAreaResizeY = 0;
    this.editorModeCode = false;
    this.updatePreviewMode = '';
    this.allowedImages = [];
    this.bAllowURLs = true;
    this.aTags = {
        'empty'        : ['', ''],
        'bold'         : ['[B]', '[/B]'],
        'indent'       : ['[INDENT]', '[/INDENT]'],
        'code'         : ['[CODE]', '[/CODE]'],
        'italic'       : ['[I]', '[/I]'],
        'underlined'   : ['[U]', '[/U]'],
        'quote'        : ['[Q]', '[Q="#\#value#\#"]', '[/Q]'],
        'align:left'   : ['[LEFT]', '[/LEFT]'],
        'align:right'  : ['[RIGHT]', '[/RIGHT]'],
        'align:center' : ['[CENTER]', '[/CENTER]'],
        'align:justify': ['[JUSTIFY]', '[/JUSTIFY]'],
        'ulist'        : ['[LIST]', '\n[/LIST]'],
        'ulist_item'   : ['\n[*]', ''],
        'addlink'      : ['[URL="#\#value#\#"]', '[/URL]'],
        'addimg'       : ['[IMG]', '[/IMG]'],
        'font_family'  : ['[FONT="#\#value#\#"]', '[/FONT]'],
        'font_size'    : ['[SIZE="#\#value#\#"]', '[/SIZE]'],
        'font_color'   : ['[COLOR="#\#value#\#"]', '[/COLOR]'],
        'smile'        : ['', '']
    };
    this.usedFonts = ['Times New Roman','Georgia','Arial','Arial Black','Arial Narrow','Book Antiqua','Comic Sans MS','Courier New','Lucida Concole','Tahoma','Verdana'];
    this.maxTextSize = 7;
    this.usedColors = ['Black','Sienna','DarkOliveGreen','DarkGreen','DarkSlateBlue','Navy','Indigo','DarkSlateGray','DarkRed','DarkOrange','Olive','Green','Teal','Blue','SlateGray','DimGray','Red','SandyBrown','YellowGreen','SeaGreen','MediumTurquoise','RoyalBlue','Purple','Gray','Magenta','Orange','Yellow','Lime','Cyan','DeepSkyBlue','DarkOrchid','Silver','Pink','Wheat','LemonChiffon','PaleGreen','PaleTurquoise','LightBlue','Plum','White'];
    this.smilesPath = 'base';
    this.baseSmiles = [new Array('smile.gif', 'Smile', ':)'),new Array('laugh.gif', 'Laugh', ':D'),new Array('frown.gif', 'Frown', ':('),new Array('wink.gif', 'Wink', ';)'),new Array('blush.gif', 'Blush', ':blush:'),new Array('eek.gif', 'Eek', ':eek:'),new Array('pardon.gif', 'Pardon', ':pardon:'),new Array('cry.gif', 'Cry', ':cry:'),new Array('cool.gif', 'Cool', ':cool:'),new Array('angry.gif', 'Angry', ':angry:'),new Array('finger_up.gif', 'Thumbs up', ':finger_up:'),new Array('finger_down.gif', 'Thumbs down', ':finger_down:'),new Array('rose.gif', 'Rose', ':rose:')];
    this.allSmiles = [];
    this.allSmilesTitles = {'': ''};
    this.smilesCopyright = '';
    this.baseHref = typeof(frontBaseHref) != 'undefined' ? frontBaseHref : (typeof(editorBaseHref) != 'undefined' ? editorBaseHref : '');
    window.bbEditorBaseHref = this.baseHref;

    this.init = function(){
        userAgent = navigator.userAgent.toLowerCase();
        this.isIE = userAgent.indexOf('msie') != -1 && userAgent.indexOf('opera') == -1 && typeof(window.opera) == 'undefined';
        if(typeof(this.oDictionary) != 'object' || this.oDictionary.length == 0){
            this.oDictionary = new amiDictionary({
                'bold': 'Bold',
                'italic': 'Italic',
                'underline': 'Underline',
                'quote': 'Quote',
                'align_left': 'Align left',
                'align_center': 'Align center',
                'align_right': 'Align right',
                'justify': 'Justify',
                'insert_list': 'Insert list',
                'insert_link': 'Insert link',
                'delete_link': 'Delete link',
                'insert_image': 'Insert image',
                'font': 'Font',
                'size': 'Size',
                'color': 'Color',
                'more': 'more',
                'insert_code': 'Insert code',
                'indent': 'Indent',
                'outdent': 'Outdent',
                'preview': 'Preview',
                'hide_preview': 'Hide preview',
                'update_preview': 'Update preview',
                'warn_message_length': 'Message to short!',
                'warn_invalid_image_url': 'Invalid image URL!',
                'warn_image_url_internal_links_forbidden': 'Images from this site are forbidden!',
                'warn_image_url_external_links_forbidden': 'Images from other sites are forbidden!',
                'prompt_enter_list_element': 'Enter list element',
                'prompt_enter_next_list_element': 'Enter list element or leave field empty to finish',
                'prompt_enter_url': 'Enter URL',
                'prompt_enter_image_url': 'Enter image URL',
                'warn_urls_reg_only': 'Using URLs forbidden for unregistered users.'
            });
        }
        for(i = 0; i < this.baseSmiles.length; i++){
            this.allSmilesTitles[this.baseSmiles[i][0]] = this.baseSmiles[i][1];
        }
        for(i = 0; i < this.allSmiles.length; i++){
            this.allSmilesTitles[this.allSmiles[i][0]] = this.allSmiles[i][1];
        }
    }

    this.setUseNoindex = function(noindexState){
        this.useNoIndex = noindexState;
    }

    this.setFontHeight = function(fontHeight){
        this.fontHeight = fontHeight;
    }

    this.procAction = function(action, subaction){
        var res = false;
        if(this.isInitialized){
            if(this._procAction(action, subaction)){
                res = true;
            }
        }
        return res;
    }

    this._procAction = function(action, subaction){
        var success = false;
        switch(action){
            case 'bold':
            case 'italic':
            case 'underlined':
            case 'code':
            case 'indent':
                this._boundSelectionWithTags(this.aTags[action]);
                success = true;
                break;
            case 'outdent':
                var selTxt = this._getSelectedText();
                if(selTxt != '' && selTxt.indexOf('[INDENT]') != -1 && selTxt.indexOf('[/INDENT]') != -1){
                    selTxt = selTxt.replace(/\[INDENT\]((.|\r|\n)*?)\[\/INDENT\]/g, '$1');
                    this._boundSelectionWithTags(this.aTags['empty'], selTxt);
                    success = true;
                }
                break;
            case 'quote':
                if(typeof(subaction) == "undefined"){
                    subaction = "";
                }
                var selTxt = this._getSelectedText();
                var tmpTags = [subaction.length == 0 ? this.aTags['quote'][0] : this.aTags['quote'][1], this.aTags['quote'][2]];
                subaction = subaction.replace(/<[a-zA-Z\/].*?>/g, '');
                selTxt = selTxt.replace(/<[a-zA-Z\/].*?>/g, '');
                tmpTags[0] = tmpTags[0].replace(/#\#value#\#/g, subaction.replace(/"/g, '&quot;'));
                this._boundSelectionWithTags(tmpTags, selTxt);
                success = true;
                break;
            case 'align':
                if(subaction != undefined && this.aTags['align:'+subaction]){
                    this._boundSelectionWithTags(this.aTags['align:'+subaction]);
                    success = true;
                }
                break;
            case 'ulist':
                var selTxt = this._getSelectedText();
                if(selTxt != ''){
                    this._procSelectionList(selTxt);
                }else{
                    this._boundSelectionWithTags(this.aTags['ulist']);
                    var listLine = '';
                    listLine = prompt(this.oDictionary.get('prompt_enter_list_element'), '');
                    while(listLine != '' && listLine != null){
                        this._boundSelectionWithTags(this.aTags['ulist_item'], listLine, true);
                        listLine = prompt(this.oDictionary.get('prompt_enter_next_list_element'), '');
                    }
                }
                success = true;
                break;
            case 'addlink':
                if(this.bAllowURLs){
                    urlLine = prompt(this.oDictionary.get('prompt_enter_url'), 'http://');
                    if(urlLine != '' && urlLine != null){
                        var selTxt = this._getSelectedText();
                        var tmpTags = [this.aTags['addlink'][0], this.aTags['addlink'][1]];
                        tmpTags[0] = tmpTags[0].replace(/#\#value#\#/g, urlLine.replace(/"/g, '&quot;'));
                        selTxt = selTxt == '' ? urlLine : selTxt;
                        this._boundSelectionWithTags(tmpTags, selTxt);
                        success = true;
                    }
                }else{
                    alert(this.oDictionary.get('warn_urls_reg_only'));
                }
                break;
            case 'dellink':
                var selTxt = this._getSelectedText();
                if(selTxt != '' && selTxt.indexOf('[URL') != -1 && selTxt.indexOf('[/URL]') != -1){
                    selTxt = selTxt.replace(/\[URL=\".*?\"\]/g, '');
                    selTxt = selTxt.replace(/\[\/URL\]/g, '');
                    this._boundSelectionWithTags(this.aTags['empty'], selTxt);
                    success = true;
                }
                break;
            case 'addimg':
                var urlLine = 'http://';
                do {
                    urlLine = prompt(this.oDictionary.get('prompt_enter_image_url'), urlLine);
                    askURL = urlLine != null;
                    if (askURL) {
                        urlLine = urlLine.replace(/^(.*?)\?.*$/, '$1');
                        if (urlLine != '') {
                            var allowedImages = this.allowedImages;
                            var re = /^https?\:\/\/([^\/]+)(\/[^\?]*)(\?.*)?/;
                            re.exec(urlLine);
                            if (RegExp.$2 == '' || RegExp.$1 == '') {
                                alert(this.oDictionary.get('warn_invalid_image_url'));
                            } else if (allowedImages.indexOf('internal_links') < 0 && urlLine.indexOf(this.baseHref) == 0) {
                                alert(this.oDictionary.get('warn_image_url_internal_links_forbidden'));
                            } else if (allowedImages.indexOf('external_links') < 0 && urlLine.indexOf(this.baseHref) != 0) {
                                alert(this.oDictionary.get('warn_image_url_external_links_forbidden'));
                            } else {
                                var tmpTags = [this.aTags['addimg'][0], this.aTags['addimg'][1]];
                                this._boundSelectionWithTags(tmpTags, urlLine);
                                success = true;
                                askURL = false;
                            }
                        }
                    }
                } while (askURL);
                break;
            case 'font_family':
            case 'font_size':
            case 'font_color':
                if(subaction != undefined && subaction != ''){
                    var tmpTags = [this.aTags[action][0], this.aTags[action][1]];
                    tmpTags[0] = tmpTags[0].replace(/#\#value#\#/g, subaction);
                    this._boundSelectionWithTags(tmpTags);
                    success = true;
                }
                break;
            case 'smile':
                if(subaction != undefined){
                    this._boundSelectionWithTags(this.aTags['smile'], subaction, true);
                    success = true;
                }
                break;
        }
        this.updatePreviewButton();
        return success;
    }

    this._boundSelectionWithTags = function(pTags, text, setPointerToEnd){
        if(pTags[0] == undefined)
            pTags[0] = '';
        if(pTags[1] == undefined)
            pTags[1] = '';
        if(text == undefined)
            text = this._getSelectedText();
        this._replaceSelection(pTags[0]+text+pTags[1], pTags[0].length, pTags[1].length, setPointerToEnd);
    }

    this._procSelectionList = function(text){
        // Try to understand next regexp ;-). From start of string any not empty string which does not start from [/?LIST] or [*]
        text = text.replace(/(^|\n)(?!(\r?\n)|(\[\/?LIST\])|(\[\*\]))/g, this.aTags['ulist_item'][0]);
        this._boundSelectionWithTags(this.aTags['ulist'], text);
    }

    this._calcMultiLineTextLen = function(text){
        if(this.isIE){
            text = text.replace(/\r/g, '');
        }
        return text.length;
    }

    this._getSelectedText = function(){
        var text = '';
        this.editorObj.focus();
        if(document.selection && document.selection.createRange()){
            var sRange = document.selection.createRange();
            text = sRange.text;
        }else if(typeof(this.editorObj.selectionStart) != undefined){
            var sStart = parseInt(this.editorObj.selectionStart);
            var sEnd = parseInt(this.editorObj.selectionEnd);
            text = this.editorObj.value;
            text = text.substr(sStart, sEnd-sStart);
        }
        return text;
    }

    this._replaceSelection = function(newText, newSelDl, newSelDr, setPointerToEnd){
        this.editorObj.focus();

        if(document.selection && document.selection.createRange()){
            var sRange = document.selection.createRange();
            sRange.text = newText.replace(/\r?\n/g, '\r\n');
            if(setPointerToEnd)
                sRange.moveStart('character', -newSelDr);
            else
                sRange.moveStart('character', -this._calcMultiLineTextLen(newText)+newSelDl);
            sRange.moveEnd('character', -newSelDr);
            sRange.select();

        }else if(typeof(this.editorObj.selectionStart) != undefined){
            var sStart = parseInt(this.editorObj.selectionStart);
            var sEnd = parseInt(this.editorObj.selectionEnd);
            var sTop = this.editorObj.scrollTop;
            var sText = this.editorObj.value;
            this.editorObj.value = sText.substr(0, sStart)+newText+sText.substr(sEnd);
            if(setPointerToEnd)
                this.editorObj.selectionStart = sStart+newText.length-newSelDr;
            else
                this.editorObj.selectionStart = sStart+newSelDl;
            this.editorObj.selectionEnd = sStart+newText.length-newSelDr;
            this.editorObj.scrollTop = sTop;
        }
    }

    this.regTextAreaResize = function(clientY){
        this.regTextAreaResizeY = clientY;
        globalATEObj = this;
        document.onmousemove = handleMouseMove;
        document.onmouseup = releaseMouseMoveHandler;
        return false;
    }

    this.handleMouseMove = function(clientY){
        if(this.regTextAreaResizeY > 0){
            var reqHeight = this.editorObj.offsetHeight-this.regTextAreaResizeY+clientY;
            if(reqHeight > 50){
                this.editorObj.style.height = reqHeight;
                this.regTextAreaResizeY = clientY;
            }
        }
        return false;
    }

    this._HTMLSpecialChars = function(taValue){
        taValue = taValue.replace(/&/g, '&amp;');
        taValue = taValue.replace(/"/g, '&quot;');
        taValue = taValue.replace(/</g, '&lt;');
        taValue = taValue.replace(/>/g, '&gt;');
        return taValue;
    }


    this.getHTMLContent = function(cutLongURL){
        var smilesPath = this.baseHref + '_mod_files/smiles/' + this.smilesPath + '/';
        var specSmiles = {";)":"wink", ":)":"smile", ":D":"laugh", ":(":"frown"};
        var localUseNoIndex = this.useNoIndex;
        var fontHeight = this.fontHeight;

        taValue = this._HTMLSpecialChars(this.editorObj.value);
        taValue = taValue.replace(/\r?\n/g, '<br>\r\n');
        taValue = taValue.replace(/\[(\/?)(B|I|U)\]/gi, '<$1$2>');
        window.amiSimpleEditorCodes = [];
        taValue = taValue.replace(/\[CODE\]((?:.|\r|\n)*?)\[\/CODE\]/gi,  function(allstr, tagContent){
            tagContent = tagContent.replace(/<br>/gi, '');
            var nlCount = 1;
            var nlPos = tagContent.indexOf('\n');
            while(nlPos != -1){
                nlCount++;
                nlPos = tagContent.indexOf('\n', nlPos+1);
            }
            if(nlCount > 10)
                nlCount = 10;
            var codeKey = window.amiSimpleEditorCodes.length;
            window.amiSimpleEditorCodes[codeKey] = tagContent;
            return '<PRE class="edCode" style="height:'+(nlCount*fontHeight+40)+'">CodeId_'+codeKey+'</PRE>';
        });
        taValue = taValue.replace(/\[Q\]/gi, '<BLOCKQUOTE class="edQuote">');
        taValue = taValue.replace(/\[Q=&quot;(.*?)&quot;\]/gi, '<BLOCKQUOTE class="edQuote"><b>$1:</b><br>');
        taValue = taValue.replace(/\[(\/?)(INDENT|Q)\]/gi, '<$1BLOCKQUOTE>');
        taValue = taValue.replace(/\[(LEFT|RIGHT|CENTER|JUSTIFY)\]/gi, '<P align="$1">');
        taValue = taValue.replace(/\[\/(LEFT|RIGHT|CENTER|JUSTIFY)\]/gi, '</P>');
        taValue = taValue.replace(/\[LIST\]/gi, '<UL>');
        taValue = taValue.replace(/\[\/LIST\]/gi, '</LI></UL>');
        taValue = taValue.replace(/\[\*\]/gi, '<LI>');
        taValue = taValue.replace(/\[FONT=&quot;(.*?)&quot;\]/gi, function(allstr, fontName){return '<FONT face="'+_tagsParamReplace(fontName, false)+'">'});
        taValue = taValue.replace(/\[(COLOR|SIZE)=&quot;(.*?)&quot;\]/gi, function(allstr, tagParam, paramValue){return '<FONT '+tagParam+'="'+_tagsParamReplace(paramValue, false)+'">'});
        taValue = taValue.replace(/\[\/(FONT|SIZE|COLOR)\]/gi, '</FONT>');

        var urlMaxLength = typeof(cutLongURL) == 'undefined' ? 0 : 50;
        taValue = taValue.replace(/\[URL=&quot;(.*?)&quot;\]((?:.|\r|\n)*?)\[\/URL\]/gi, function(allstr, url, linkContent){
            var curUseNoIndex = localUseNoIndex;
            var curUrl = _tagsParamReplace(url, false);
            if(curUseNoIndex && (!curUrl.match(/^https?:\/\//i) || (window.bbEditorBaseHref.length > 0 && curUrl.indexOf(window.bbEditorBaseHref) >= 0)))
                curUseNoIndex = false;
            var attributes = '';
            linkContent = _trim(linkContent);
            var noTagsLinkContent = _trim(_stripTags(linkContent).replace(/\"/g, '&quot;'));
            if ((urlMaxLength > 0) && (noTagsLinkContent.length > urlMaxLength)) {
                attributes =
                    ' title="' + noTagsLinkContent + '"';
                linkContent = noTagsLinkContent.substr(0, urlMaxLength - 8 - 3) + '...' + noTagsLinkContent.substr(noTagsLinkContent.length - 8);
            }
            return (curUseNoIndex ? '<NOINDEX>' : '')+'<A HREF="'+curUrl+'"'+(curUseNoIndex ? ' rel="nofollow"' : '')+' target="_blank"' + attributes + '>'+linkContent+'</A>'+(curUseNoIndex ? '</NOINDEX>' : '');
        });

        var allSmilesTitles = this.allSmilesTitles;
        taValue = taValue.replace(/\[IMG\](.*?)\[\/IMG\]/gi, function(allstr, url){return '<IMG SRC="'+_tagsParamReplace(url, true)+'">'});
        taValue = taValue.replace(/(;\)|:\)|:D|:\()/g, function(allstr, smile){var imgName = specSmiles[smile]+'.gif'; return '<IMG SRC="'+smilesPath+imgName+'" title="'+(typeof(allSmilesTitles[imgName]) != 'undefined' ? allSmilesTitles[imgName] : '')+'">'});
        taValue = taValue.replace(/\:([a-z\_]{1,20})\:/gi, function(allstr, smile){var imgName = smile+'.gif'; return '<IMG SRC="'+smilesPath+smile+'.gif" title="'+(typeof(allSmilesTitles[imgName]) != 'undefined' ? allSmilesTitles[imgName] : '')+'">'});

        taValue = taValue.replace(/((?:<IMG .*?>)|(?:<A (?:.|\r|\n)*?<\/A>))/gi, function(allstr, pTagContent){
            pTagContent = pTagContent.replace(/http(s?)\:/gi, 'htBREAKtp$1:');
            pTagContent = pTagContent.replace(/www/gi, 'wBREAKwBREAKw');
            return pTagContent;
        });
        taValue = taValue.replace(/(https?:\/\/www\.|https?:\/\/|www\.)(?:[a-z0-9\-]+\.)+[a-z]{2,8}[^ \r\n\t'"><]*/gi, function(allstr, prefx){
            var curUseNoIndex = localUseNoIndex;
            var curUrl = _tagsParamReplace(allstr);
            if(prefx.toLowerCase() == 'www.'){
                curUrl = 'http://' + curUrl;
            }
            if(curUseNoIndex && (!curUrl.match(/^https?:\/\//i) || (window.bbEditorBaseHref.length > 0 && curUrl.indexOf(window.bbEditorBaseHref) >= 0)))
                curUseNoIndex = false;
            return (curUseNoIndex ? '<NOINDEX>' : '')+'<A HREF="'+curUrl+'"'+(curUseNoIndex ? ' rel="nofollow"' : '')+' target="_blank">'+allstr+'</A>'+(curUseNoIndex ? '</NOINDEX>' : '');
        });
        taValue = taValue.replace(/((?:<IMG .*?>)|(?:<A (?:.|\r|\n)*?<\/A>))/gi, function(allstr, pTagContent){
            pTagContent = pTagContent.replace(/wBREAKwBREAKw/gi, 'www');
            pTagContent = pTagContent.replace(/htBREAKtp(s?):/gi, 'http$1:');
            return pTagContent;
        });

        taValue = taValue.replace(/(<PRE[^>]*?>)CodeId_(\d+)(<\/PRE>)/g, function(allstr, preStart, codeId, preEnd){
            var result = preStart;
            if(window.amiSimpleEditorCodes[codeId]){
                result += window.amiSimpleEditorCodes[codeId];
            }
            result += preEnd;
            return result;
        });
        window.amiSimpleEditorCodes = [];

        return taValue;
    }

    this.fromHTMLContent = function(taValue){
        var smilesPath = '_mod_files/smiles/' + this.smilesPath + '/';
        var specSmiles = {"wink":";)", "smile":":)", "laugh":":D", "frown":":("};

        // Make single line string
        taValue = taValue.replace(/\r?\n?<br.*?>\r?\n?/gi, '\r\n');
        taValue = taValue.replace(/\\([rn])/gi, '[_spec_rpl_val_$1]');
        taValue = taValue.replace(/\r?\n/g, '\\n');

        // Replace simple elements
        taValue = taValue.replace(/<(\/?)PRE.*?>/gi, '[$1CODE]');
        taValue = taValue.replace(/<(\/?)(B|I|U)(?:>|[^a-z].*?>)/gi, '[$1$2]');
        taValue = taValue.replace(/<(\/?)UL.*?>/gi, '[$1LIST]');
        taValue = taValue.replace(/<LI.*?>/gi, '[*]');
        taValue = taValue.replace(/<\/LI.*?>/gi, '');

        // Replace images and smiles
        taValue = taValue.replace(/<img[^>]*?src=((?:"|').*?(?:"|')|[^\s]*).*?>/gi,
                  function(allstr, tagUrl){
                    var tagUrl = tagUrl.replace(/^('|")(.*?)\1$/g, '$2');
                    var pathPos = tagUrl.indexOf(smilesPath);
                    if(pathPos >= 0){
                        var dotPos = tagUrl.indexOf(".", pathPos+smilesPath.length);
                        if(dotPos >= 0){
                            var startPos = pathPos+smilesPath.length;
                            var smileName = tagUrl.substr(startPos, dotPos-startPos);
                            if(specSmiles[smileName] != undefined){
                                return specSmiles[smileName];
                            }else
                                return ':'+smileName+':';
                        }
                    }
                    return '[IMG]'+tagUrl+'[/IMG]';}
                  );

        // Replace nested elements
        var replaceType = ['align', 'font', 'url', 'blockquote'];
        for(var i = 0; i < replaceType.length; i++){
            var checkLen = 0;
            do{
                checkLen = taValue.length;
                if(replaceType[i] == 'align')
                    taValue = taValue.replace(/^(.*)<p[^a-z][^>]*?align=(?:"|')?(right|left|center|justify)(?:"|')?.*?>(.*?)<\/p(?:>|[^a-z].*?>)/i, '$1[$2]$3[/$2]');
                else if(replaceType[i] == 'font')
                    taValue = taValue.replace(/^(.*)<font[^>]*?(face|size|color)=((?:"|').*?(?:"|')|[^\s>]*).*?>(.*?)<\/font.*?>/i, function(allstr, textStart, tagName, tagValue, tagContent){var tagTag = (tagName.toLowerCase() == "face" ? "FONT" : tagName.toUpperCase()); tagValue = tagValue.replace(/^('|")(.*?)\1$/g, '$2'); return textStart+'['+tagTag+'="'+tagValue+'"]'+tagContent+'[/'+tagTag+']';});
                else if(replaceType[i] == 'url') {
                    taValue = taValue.replace(/^(.*)<a[^a-z]([^>]*?)href=((?:"|').*?(?:"|')|[^\s>]*)(.*?)>(.*?)<\/a(?:>|[^a-z].*?>)/i,  function(allstr, textStart, tagParams1, tagUrl, tagParams2, tagContent){
                        var tagUrl = tagUrl.replace(/^('|")(.*?)\1$/g, '$2');
                        urlContent = tagContent;
                        if(aParts = (tagParams1 + " " + tagParams2).match(/[^a-z]title="([^"]+)"/i)){
                            urlContent = aParts[1].replace(/&quot;/mg, '"').replace(/&#10;/mg, '\n').replace(/&#13;/mg, '\r');
                        }
                        return textStart + '[URL="' + tagUrl + '"]' + urlContent + '[/URL]';
                    });

                }
                else if(replaceType[i] == 'blockquote'){
                    taValue = taValue.replace(/^(.*)<BLOCKQUOTE(.*?)>(?:\[B\](.*?):\[\/B\]\\n)?(.*?)<\/BLOCKQUOTE>/i, function(allstr, tagBefore, tagInner, qAuthor, tagContent){
                        var isQuote = (tagInner.indexOf('edQuote') >= 0);
                        var hasAuthor = (typeof(qAuthor) != "undefined" && qAuthor.length > 0);
                        if(isQuote){
                            var startTag = '[Q'+(hasAuthor ? '="'+qAuthor+'"' : '')+']';
                            return tagBefore+startTag+tagContent+'[/Q]';
                        }else{
                            return tagBefore+'[INDENT]'+(hasAuthor ? qAuthor : '')+tagContent+'[/INDENT]';
                        }
                    });
                }
            }while(checkLen != taValue.length);
        }

        // Replace HTML base chars
        taValue = taValue.replace(/&lt;/gi, '<');
        taValue = taValue.replace(/&gt;/gi, '>');
        taValue = taValue.replace(/&reg;/gi, '®');
        taValue = taValue.replace(/&copy;/gi, '©');
        taValue = taValue.replace(/&laquo;/gi, '«');
        taValue = taValue.replace(/&raquo;/gi, '»');
        taValue = taValue.replace(/&ndash;/gi, '–');
        taValue = taValue.replace(/&mdash;/gi, '—');
        taValue = taValue.replace(/&euro;/gi, '€');

        // Make multiline string
        taValue = taValue.replace(/\\n/g, '\r\n');
        taValue = taValue.replace(/\[\_spec\_rpl\_val\_([rn])\]/gi, '\\$1');

        return taValue;
    }

    this.createEditor = function(taWidth, taHeight, taValueName, taValue, isValueHTML, idPreviewDiv){
        if (typeof(isValueHTML) != undefined) {
            var re = /(<noindex>|<\/noindex>)/gi;
            taValue = taValue.replace(re, '');
        }
        this.editorId = 'id'+taValueName;
        var i = 0;

        var usedFonts = '';
        for(i = 0; i < this.usedFonts.length; i++){
            usedFonts += '<option value="'+this.usedFonts[i]+'">'+this.usedFonts[i]+'</option>';
        }

        var usedSizes = '';
        for(i = 1; i <= this.maxTextSize; i++){
            usedSizes += '<option value="'+i+'">'+i+'</option>';
        }

        var usedColors = '';
        for(i = 0; i < this.usedColors.length; i++){
            usedColors += '<option value="'+this.usedColors[i]+'" style="background-color:'+this.usedColors[i]+'"> </option>';
        }

        var baseSmiles = '';
        for(i = 0; i < this.baseSmiles.length; i++){
            baseSmiles += '<img src="' + this.baseHref + '_mod_files/smiles/' + this.smilesPath + '/' +this.baseSmiles[i][0]+'" title="'+this.baseSmiles[i][1]+'" onClick="txtEd.procAction(\'smile\', \''+this.baseSmiles[i][2]+'\')" class="amiroTEdSmile">';
        }

        var allSmiles = baseSmiles;
        for(i = 0; i < this.allSmiles.length; i++){
            allSmiles += '<img src="' + this.baseHref + '_mod_files/smiles/' + this.smilesPath + '/' +this.allSmiles[i][0]+'" title="'+this.allSmiles[i][1]+'" onClick="txtEd.procAction(\'smile\', \''+this.allSmiles[i][2]+'\')" class="amiroTEdSmile">';
        }

        var contentPreviewDiv = '';
        if(typeof(idPreviewDiv) != "undefined"){
            this.idPreviewDiv = idPreviewDiv;
        }else{
            this.idPreviewDiv = 'amiroTEdDivPreview';
            contentPreviewDiv = '<div id="amiroTEdDivPreview" class="amiroTEdDivPreview" style="width:' + (taWidth - 12) + 'px;margin-bottom:7px"></div>';
        }

        var allowedImages = this.allowedImages;
        document.writeln(
            '<div style="width:'+taWidth+'px" id="amiroTEdDiv" class="amiroTEdDiv">' +
            contentPreviewDiv +
            '<div id="amiroTEdPureDiv">' +
            '<nobr>' +
            '<img src="' + this.baseHref + '_img/ed_bold.gif" title="'+this.oDictionary.get('bold')+'" onClick="txtEd.procAction(\'bold\')" class="amiroTEdCtrl">' +
            '<img src="' + this.baseHref + '_img/ed_italic.gif" title="'+this.oDictionary.get('italic')+'" onClick="txtEd.procAction(\'italic\')" class="amiroTEdCtrl">' +
            '<img src="' + this.baseHref + '_img/ed_underline.gif" title="'+this.oDictionary.get('underline')+'" onClick="txtEd.procAction(\'underlined\')" class="amiroTEdCtrl">' +
            '<img src="' + this.baseHref + '_img/ed_quote.gif" title="'+this.oDictionary.get('quote')+'" onClick="txtEd.procAction(\'quote\')" class="amiroTEdCtrl">' +
            '</nobr>' +
            '<img src="' + this.baseHref + '_img/ed_sep.gif" class="amiroTEdSep">' +
            '<nobr>' +
            '<img src="' + this.baseHref + '_img/ed_outdent.gif" title="'+this.oDictionary.get('outdent')+'" onClick="txtEd.procAction(\'outdent\')" class="amiroTEdCtrl">' +
            '<img src="' + this.baseHref + '_img/ed_indent.gif" title="'+this.oDictionary.get('indent')+'" onClick="txtEd.procAction(\'indent\')" class="amiroTEdCtrl">' +
            '</nobr>' +
            '<img src="' + this.baseHref + '_img/ed_sep.gif" class="amiroTEdSep">' +
            '<nobr>' +
            '<img src="' + this.baseHref + '_img/ed_alignl.gif" title="'+this.oDictionary.get('align_left')+'" onClick="txtEd.procAction(\'align\', \'left\')" class="amiroTEdCtrl">' +
            '<img src="' + this.baseHref + '_img/ed_alignc.gif" title="'+this.oDictionary.get('align_center')+'" onClick="txtEd.procAction(\'align\', \'center\')" class="amiroTEdCtrl">' +
            '<img src="' + this.baseHref + '_img/ed_alignr.gif" title="'+this.oDictionary.get('align_right')+'" onClick="txtEd.procAction(\'align\', \'right\')" class="amiroTEdCtrl">' +
            '<img src="' + this.baseHref + '_img/ed_alignj.gif" title="'+this.oDictionary.get('justify')+'" onClick="txtEd.procAction(\'align\', \'justify\')" class="amiroTEdCtrl">' +
            '</nobr>' +
            '<img src="' + this.baseHref + '_img/ed_sep.gif" class="amiroTEdSep">' +
            '<img src="' + this.baseHref + '_img/ed_list.gif" title="'+this.oDictionary.get('insert_list')+'" onClick="txtEd.procAction(\'ulist\')" class="amiroTEdCtrl">' +
            '<img src="' + this.baseHref + '_img/ed_sep.gif" class="amiroTEdSep">' +
            '<nobr>' +
            '<img src="' + this.baseHref + '_img/ed_link.gif" title="'+this.oDictionary.get('insert_link')+'" onClick="txtEd.procAction(\'addlink\')" class="amiroTEdCtrl">' +
            '<img src="' + this.baseHref + '_img/ed_unlink.gif" title="'+this.oDictionary.get('delete_link')+'" onClick="txtEd.procAction(\'dellink\')" class="amiroTEdCtrl">' +
            (allowedImages.length ? '<img src="' + this.baseHref + '_img/ed_image.gif" title="'+this.oDictionary.get('insert_image')+'" onClick="txtEd.procAction(\'addimg\')" class="amiroTEdCtrl">' : '') +
            '<img src="' + this.baseHref + '_img/ed_code.gif" title="'+this.oDictionary.get('insert_code')+'" onClick="txtEd.procAction(\'code\')" class="amiroTEdCtrl">' +
            '</nobr>' +
            '<img src="' + this.baseHref + '_img/ed_sep.gif" class="amiroTEdSep">' +
            '<nobr>' +

            '<select name="amiroTEdit_selfont" onChange="txtEd.procAction(\'font_family\', this.value);this.options[0].selected=true;" class="amiroTEdCtrl">' +
            '<option value="">'+this.oDictionary.get('font')+'</option>' +
            usedFonts +
            '</select>' +
            '<select name="amiroTEdit_selsize" onChange="txtEd.procAction(\'font_size\', this.value);this.options[0].selected=true;" class="amiroTEdCtrl">' +
            '<option value="">'+this.oDictionary.get('size')+'</option>' +
            usedSizes +
            '</select>' +
            '<select name="amiroTEdit_selcolor" onChange="txtEd.procAction(\'font_color\', this.value);this.options[0].selected=true;" class="amiroTEdCtrl">' +
            '<option value="">'+this.oDictionary.get('color')+'</option>' +
            usedColors +
            '</select>' +
            '</nobr>' +
            '<br>' +

            '<div id="amiroTEdDivBaseSmiles">' +
            baseSmiles +
            (allSmiles.length > baseSmiles.length ? '<span onClick="document.getElementById(\'amiroTEdDivAllSmiles\').style.display=\'block\';document.getElementById(\'amiroTEdDivBaseSmiles\').style.display=\'none\'" class="amiroTEdMore">'+this.oDictionary.get('more')+'</span>' +
            '</div>' +
            '<div id="amiroTEdDivAllSmiles" style="display:none">' +
            allSmiles : '') +
            (this.smilesCopyright != '' ? '<div align="right">'+this.smilesCopyright+'</div>' : '') +
            '</div>' +

            '</div>' +
            '</div>' +

            '<div id="amiroTEdDivEditor" class="amiroTEdDivEditor">' +
            '<textarea id="'+this.editorId+'" name="'+taValueName+'" wrap="fisical" class="amiroTEdCtrl" style="width:'+taWidth+'px;height:'+taHeight+'px" onKeyDown="return '+varName+'.procKeyPress(event)" onKeyUp="'+varName+'.procKeyUp()">' +
            (typeof(isValueHTML) == undefined || !isValueHTML ? taValue : this.fromHTMLContent(taValue)) +
            '</textarea><br>' +
            '<div class="amiroTEdDivResize" style="width:'+taWidth+'px;background-image: url(' + this.baseHref + '_img/ed_resize.gif)" onMouseDown="'+this.varName+'.regTextAreaResize(event.pageY ? event.pageY : window.event.clientY)"><img src="' + this.baseHref + '_img/empty.gif" width="1" height="3"></div>' +
            '</div>'

        );
        this.editorObj = document.getElementById(this.editorId);
        this.isInitialized = true;
    }

    this.insertContent = function(taValue, actionType, isValueHTML, subaction, addon){
        if (typeof(isValueHTML) != undefined) {
            var re = /(<noindex>|<\/noindex>)/gi;
            taValue = taValue.replace(re, '');
        }

        this.setMode('editor');
        if(typeof(addon) != "undefined" && actionType == "bold"){
            taValue = "[B]"+taValue+"[/B]"+addon;
            this._replaceSelection(typeof(isValueHTML) == undefined || !isValueHTML ? taValue : this.fromHTMLContent(taValue), 0, 0, true);
        }else{
            this._replaceSelection(typeof(isValueHTML) == undefined || !isValueHTML ? taValue : this.fromHTMLContent(taValue), 0, 0);
            if(actionType != 'undefined' && (actionType == 'quote' || actionType == 'bold' || actionType == 'italic' || actionType == 'underlined')){
                this.procAction(actionType, subaction);
            }
        }
    }

    this.setMode = function(mode){
        if(mode == 'editor' && !this.updatePreviewMode){
            document.getElementById('amiroTEdDivPreview').style.display = 'none';
            this.currentMode = 'editor';
            if(this.editorModeCode.length > 0){
                eval(this.editorModeCode);
            }
        }else if(mode == 'preview' || this.updatePreviewMode){
            var content = this.getHTMLContent(1);
            if (content.length) {
                document.getElementById('amiroTEdDivPreview').style.display = 'block';
                document.getElementById('amiroTEdDivPreview').innerHTML = content;
                this.currentMode = 'preview';
                if (this.updatePreviewMode) {
                    this.previewButtonObj.value = this.oDictionary.get('hide_preview');
                }
                this.updatePreviewMode = false;
            }
        }
        if (typeof(amiroTEditOnSwitchMode) == 'function') {
            amiroTEditOnSwitchMode(this.currentMode);
        }
    }

    this.switchMode = function(){
        if(this.currentMode == 'editor'){
            this.setMode('preview');
        }else{
            this.setMode('editor');
        }
    }

    this.stopEvent = function(evt){
        if(typeof(evt.stopPropagation) == "function"){
            evt.stopPropagation();
            evt.preventDefault();
            return evt;
        }else{
            window.event.returnValue = false;
            window.event.cancelBubble = true;
            return window.event;
        }
    }

    this.procKeyPress = function(evt){
        if(evt.ctrlKey && evt.keyCode != 17){
            switch(evt.keyCode){
                case 66 /*B*/:
                    this.procAction('bold');
                    return this.stopEvent(evt);
                    break;
                case 73 /*I*/:
                    this.procAction('italic');
                    return this.stopEvent(evt);
                    break;
                case 85 /*U*/:
                    this.procAction('underlined');
                    return this.stopEvent(evt);
                    break;
            }
        }else if(!evt.ctrlKey && !evt.altKey){
            this.updatePreviewButton();
        }
    }

    this.procKeyUp = function()
    {
        if (this.currentMode == 'preview' && this.contentLength() < 2) {
            this.updatePreviewMode = false;
            this.previewButtonOnClick();
            alert(this.oDictionary.get('warn_message_length'));
        }
    }

    this.contentLength = function(){
        var contentData = this.editorObj.value;
        contentData = contentData.replace(/[ \t\r\n]/g, '');

        var replaceType = ['q'];
        for(var i = 0; i < replaceType.length; i++){
            var checkLen = 0;
            do{
                checkLen = contentData.length;
                if(replaceType[i] == 'q'){
                    contentData = contentData.replace(/^(.*)\[Q[^\]]*?\](.*?)\[\/Q\]/i, '$1');
                }
            }while(checkLen != contentData.length);
        }

        contentData = contentData.replace(/\[.*?\]/g, '');
        return contentData.length;
    }

    this.previewButtonOnClick = function(btn)
    {
        if (btn != undefined) {
            this.previewButtonObj = btn;
        } else {
            btn = this.previewButtonObj;
        }
        if (this.currentMode == 'preview') {
            btn.value = this.oDictionary.get('preview');
            txtEd.setMode('editor');
        } else if (this.contentLength() < 2) {
            alert(this.oDictionary.get('warn_message_length'));
            this.editorObj.focus();
        } else {
            btn.value = this.oDictionary.get('hide_preview');
            txtEd.setMode('preview');
        }
        return false;
    }

    this.updatePreviewButton = function(){
        if (this.currentMode == 'preview' && this.previewButtonObj != undefined) {
            this.previewButtonObj.value = this.oDictionary.get('update_preview');
            this.updatePreviewMode = true;
        }
    }

    this.checkURLUsage = function(){
        var res = this.bAllowURLs || !this.getHTMLContent().match(/<A[^>]+HREF=/gi);
        if(!res){
            alert(this.oDictionary.get('warn_urls_reg_only'));
        }
        return res;
    }

    this.init();
}
function handleMouseMove(evt){
    if(typeof(globalATEObj) == 'object')
        return globalATEObj.handleMouseMove(evt == undefined ? window.event.clientY : evt.pageY);
    else
        return false;
}
function releaseMouseMoveHandler(){
    document.onmousemove = null;
    document.onmouseup = null;
    return false;
}
function _tagsParamReplace(param, doCheckImage){
    var res = param.replace(/&amp;/, '&');

    do{
        var prevLength = res.length;
        res = res.replace(/^\s*javascript\:/, '');
    }while(res.length != prevLength);

    if(doCheckImage){
        var test = res.replace(/^ *(.*?) *$/i, '$1').toLowerCase();
        if(test.indexOf('/_admin/') >= 0){
            res = '';
        }else{
            var isRelativeAddress = (test.search(/^https?:\/\//) == -1);
            var isLocalAddress = false;
            if(!isRelativeAddress){
                test = test.replace(/^https:\/\//, 'http://');
                var localURL = window.bbEditorBaseHref;
                if(localURL != '' && test.indexOf(localURL) == 0){
                    isLocalAddress = true;
                }
            }
            if((isRelativeAddress || isLocalAddress) && test.search(/^[^?]*\.(jpg|png|gif|jpeg|swf)$/) == -1){
                res = '';
            }
        }
    }

    return res;
}

function _stripTags(str)
{
    return str.replace(/<\/?[^\s^>]+[^>]*?>/gi, '');
}

function _trim(str)
{
    return str.replace(/^\s+/mg, '').replace(/\s+$/mg, '');
}
