/********************
 * Iniciação e Funções globais
 ********************/
AttachOnLoadEvent(initializeTextEditors);

var textEditors = new Array();

function initializeTextEditors() {
    for (var i = 0; i < textEditors.length; i++) {
        textEditors[i].init();
    }
}

function beforeSubmit(index) {
    var te = textEditors[index];
    
    if (te.mode == TextEditorMode.HTML) {
        te.switchMode(); // tem de estar em modo WYSIWYG para podermos copiar o conteúdo correctamente
    }
    var content = te.getContentHTML();
    document.getElementById(te.hiddenFieldID).value = content;
    
    return true;
}

function catchEnter(index, button, event) {
    var te = textEditors[index];
    te.catchEnter(button, event);
}


/********************
 * Mode
 ********************/
var TextEditorMode = { WYSIWYG:1, HTML:2 };


/********************
 * SelectOption
 ********************/
function TextEditorSelectOption(value, description) {
    this.value = value;
    this.description = description;
}

TextEditorSelectOption.prototype.value;
TextEditorSelectOption.prototype.description;


/********************
 * Select
 ********************/
 function TextEditorSelect(name, description) {
    this.name = name;
    this.method = 'select';
    this.description = description;
    this.options = new Array();
}

TextEditorSelect.prototype.name;
TextEditorSelect.prototype.method;
TextEditorSelect.prototype.description;
TextEditorSelect.prototype.options;


/********************
 * Image
 ********************/
function TextEditorImage(url, alt, width, height) {
    this.url = url;
    this.alt = alt;
    this.width = width;
    this.height = height;
}

TextEditorImage.prototype.url;
TextEditorImage.prototype.alt;
TextEditorImage.prototype.width;
TextEditorImage.prototype.height;


/********************
 * ImageButton
 ********************/
function TextEditorImageButton(buttonImg, img, ask) {
    this.buttonImg = buttonImg;
    this.img = img;
    this.ask = ask;
}

TextEditorImageButton.prototype.buttonImg;
TextEditorImageButton.prototype.img;
TextEditorImageButton.prototype.ask;


/********************
 * TextEditor
 ********************/
function TextEditor(formID, id, varid, content, contentStylesheet, scriptsUrl, root, mode, frameHeight
        , showControls, showAdvancedToolbar, isAdmin, selects, imgButtons
        , cssClass, controlsCssClass, buttonCssClass, separatorCssClass
        , linkCssClass, advancedCssClass, imagesCssClass, imageFormCssClass) {
    this.id = id + '_iframe';
    this.mode = mode;
    this.isAdmin = isAdmin;
    this.frameHeight = frameHeight;
    this.root = root;
    
    // css
    this.cssClass = cssClass;
    this.buttonCssClass = buttonCssClass;
    this.separatorCssClass = separatorCssClass;
    this.linkCssClass = linkCssClass;
    this.advancedCssClass = advancedCssClass;
    this.imagesCssClass = imagesCssClass;
    this.controlsCssClass = controlsCssClass;
    this.imageFormCssClass = imageFormCssClass;
    
    // browser detect
    var browser = navigator.userAgent.toLowerCase();
    this.isIE = ( (browser.indexOf('msie') != -1)
                && (browser.indexOf('opera') == -1)
                && (browser.indexOf('webtv') == -1) );
    this.isOpera = (browser.indexOf('opera') != -1);
    this.isFirefox = (browser.indexOf('firefox') != -1);
    this.isNetscape = (browser.indexOf('netscape') != -1);
    this.isSafari = (browser.indexOf('safari') != -1);
    
    // ids
    this.varid = varid;
    this.hiddenFieldID = id;
    this.mainDivID = this.varid + '_mainDiv';
    this.controlsLinkID = this.varid + '_a_opcoes';
    this.controlsDivID = this.varid + '_opcoes';
    this.advancedLinkID = this.varid + '_a_opcoesAvancadas';
    this.advancedDivID = this.varid + '_opcoesAvancadas';
    this.formImageDivID = this.varid + '_formImage';
    this.formImageAltID = this.varid + '_imageForm_alt';
    this.formImageURLID = this.varid + '_imageForm_url';
    this.formImageAlignID = this.varid + '_imageForm_align';
    this.formImageOKID = this.varid + '_imageForm_ok';
    
    // constroi
    this.make(selects, imgButtons);
    this.showAdvanced(showAdvancedToolbar);
    this.showControls(showControls);

    // trata da form e funções globais
    var index = this.index = textEditors.length;
    textEditors[textEditors.length] = this;
    this.writeContent(content, contentStylesheet, scriptsUrl);
    var form = document.getElementById(formID);
    var submitFunction = form.onsubmit;
    var onkeydownFunction = form.onkeydown;
    var formImageOKID = this.formImageOKID;
    
    form.onsubmit = function() {
        var previousReturn = true;
        
        if (submitFunction != null && typeof(submitFunction) != 'undefined') {
            previousReturn = submitFunction(); // a função que anteriormente estava associada ao onsubmit
        }
        return previousReturn && beforeSubmit(index); // tem de ser passada uma variável (não pode ser passado o atributo da classe senão não dá);
    }
    
    if (this.isIE) {
        form.onkeydown = function() { // IE já tem event cá dentro
            if (onkeydownFunction != null && typeof(onkeydownFunction) != 'undefined') {
                onkeydownFunction(); // a função que anteriormente estava associada ao onkeydown
            }
            catchEnter(index, formImageOKID, event);
        }    
    } else {
        form.onkeydown = function(event) {
            if (onkeydownFunction != null && typeof(onkeydownFunction) != 'undefined') {
                onkeydownFunction(); // a função que anteriormente estava associada ao onkeydown
            }
            catchEnter(index, formImageOKID, event);
        }
    }
}

TextEditor.prototype.id;
TextEditor.prototype.root;
TextEditor.prototype.index;
TextEditor.prototype.hiddenFieldID;
TextEditor.prototype.varid;
TextEditor.prototype.isIE;
TextEditor.prototype.isFirefox;
TextEditor.prototype.isNetscape;
TextEditor.prototype.isOpera;
TextEditor.prototype.isSafari;
TextEditor.prototype.mode;
TextEditor.prototype.isAdmin;
TextEditor.prototype.frameHeight;
TextEditor.prototype.cssClass;
TextEditor.prototype.separatorCssClass;
TextEditor.prototype.buttonCssClass;
TextEditor.prototype.linkCssClass;
TextEditor.prototype.advancedCssClass;
TextEditor.prototype.imagesCssClass;
TextEditor.prototype.controlsCssClass;
TextEditor.prototype.imageFormCssClass;
TextEditor.prototype.mainDivID;
TextEditor.prototype.controlsLinkID;
TextEditor.prototype.controlsDivID;
TextEditor.prototype.advancedLinkID;
TextEditor.prototype.advancedDivID;
TextEditor.prototype.formImageDivID;
TextEditor.prototype.formImageAltID;
TextEditor.prototype.formImageURLID;
TextEditor.prototype.formImageAlignID;
TextEditor.prototype.formImageOKID;


/********************
 * Init
 ********************/
TextEditor.prototype.init = function() {
    this.getDocument().designMode = 'On';
    //this.focus();
}


/********************
 * getContentHTML
 ********************/
TextEditor.prototype.getContentHTML = function() {
    return this.getDocument().body.innerHTML;
}


/********************
 * Construção
 ********************/
TextEditor.prototype.writeContent = function(content, stylesheet, scripts) {
    var html = '';
    
    html += '<html>';
    html += '<head>';
    html += '<title></title>';
    
    if (stylesheet != '' && stylesheet != null) {
        html += '<link rel="stylesheet" type="text/css" href="' + stylesheet + '" />';
    }
    
    if (scripts != null) {
        for (var i = 0; i < scripts.length; i++) {
            html += '<script type="text/javascript" src="' + scripts[i] + '"></script>';
        }
    }
    html += '</head>';
    html += '<body style="margin: 10px; background: #FFFFFF;">';
    html += content;
    html += '</body>';
    html += '</html>';
    this.getDocument().open();
    this.getDocument().write(html);
    this.getDocument().close();
}

TextEditor.prototype.write = function(html) {
    document.write(html );
}

TextEditor.prototype.makeSeparator = function(cssClass) {
   this.write('<font class="' + cssClass + '">|</font>');
}

TextEditor.prototype.makeButton = function(name, description, cssClass) {
    var a_href = '<a href="javascript:' + this.varid + '.' + name + '()"'
            + ' title="' + description + '">';
    var img = '<img src="' + this.root + 'imagens/editor/' + name + '.gif"'
            + ' class="' + cssClass + '"'
            + ' alt="' + description + '"'
            + ' />';
    this.write(a_href + img + '</a>');
}

TextEditor.prototype.makeImageButton = function(imgButton) {
    if (imgButton.ask) {
        var a_href = '<a href="javascript:' + this.varid
                            + '.imageAsk(\'' + imgButton.img.url + '\''
                                    + ', \'' + imgButton.img.alt + '\''
                                    + ', 0'
                                    + ', true'
                                    + ')"'
                    + ' title="' + imgButton.buttonImg.alt + '">';
    } else {
        var a_href = '<a href="javascript:' + this.varid
                            + '.imageHTML(\'' + imgButton.img.url + '\''
                                    + ', \'' + imgButton.img.alt + '\''
                                    + ', ' + imgButton.img.width
                                    + ', ' + imgButton.img.height
                                    + ", 'absmiddle'"
                                    + ')"'
                    + ' title="' + imgButton.buttonImg.alt + '">';
    }
    var img = '<img src="' + imgButton.buttonImg.url + '"'
            + ' width="' + imgButton.buttonImg.width + 'px"'
            + ' height="' + imgButton.buttonImg.height + 'px"'
            + ' alt="' + imgButton.buttonImg.alt + '"'
            + ' />';
    this.write(a_href + img + '</a>');
}

TextEditor.prototype.makeSelect = function(select) {
    var selectHTML = '<select name="' + select.name + '" id="' + select.name + '"'
            + ' onChange="' + this.varid + '.' + select.method + '(this)">';
    var optionsHTML = '<option value=""'
                + ' selected="selected">-- ' + select.description + '</option>';
    
    for (var i = 0; i < select.options.length; i++)
    {
        optionsHTML += '<option value="' + select.options[i].value + '">' + select.options[i].description + '</option>'
    }
    this.write(selectHTML + optionsHTML + '</select>');
}

TextEditor.prototype.makeSimpleToolbar= function() {
    this.makeButton('undo', 'Desfazer', this.buttonCssClass);
    this.makeButton('redo', 'Refazer', this.buttonCssClass);
    this.makeSeparator(this.separatorCssClass);
    
    var styleSelect = new TextEditorSelect('heading', 'Estilo');
    styleSelect.method = 'heading';
    styleSelect.options[0] = new TextEditorSelectOption('<p>', 'Normal');
    styleSelect.options[1] = new TextEditorSelectOption('<h1>', 'Título 1 (maior)');
    styleSelect.options[2] = new TextEditorSelectOption('<h2>', 'Título 2 (médio)');
    styleSelect.options[3] = new TextEditorSelectOption('<h3>', 'Título 3 (menor)');
    
    this.makeSelect(styleSelect);
    
    this.makeButton('bold', 'Bold', this.buttonCssClass);
    this.makeButton('italic', 'Itálico', this.buttonCssClass);
    this.makeButton('quote', 'Citação', this.buttonCssClass);
    this.makeSeparator(this.separatorCssClass);
    
    this.makeButton('listOrdered', 'Lista ordenada', this.buttonCssClass);
    this.makeButton('list', 'Lista', this.buttonCssClass);
    this.makeSeparator(this.separatorCssClass);
    
    this.makeButton('link', 'Inserir hyperlink', this.buttonCssClass);
    this.makeButton('unlink', 'Remover hyperlink', this.buttonCssClass);
    this.makeButton('image', 'Inserir imagem', this.buttonCssClass);
    this.makeButton('table', 'Inserir tabela', this.buttonCssClass);
}

TextEditor.prototype.openEditor = function(cssClass) {
    this.openDiv('', this.cssClass);
    var span = '<span><span><span><span><span><span><span>';
    this.write(span);
}

TextEditor.prototype.closeEditor = function() {
    var span = '</span></span></span></span></span></span></span>'; // falta uma span por causa de fix para IE!
    this.write(span);
    this.closeDiv();
}

TextEditor.prototype.openDiv = function(id, cssClass) {
    var div = '<div';
    
    if (id != '' && id != null) {
        div += ' id="' + id + '"';
    }
    
    if (cssClass != '' && cssClass != null) {
        div += ' class="' + cssClass + '"';
    }
    this.write(div + '>');
}

TextEditor.prototype.closeDiv = function() {
    this.write('</div>');
}

TextEditor.prototype.makeAdvancedToolbar = function(selects, imgButtons) {
    var a_href = '<a href="javascript:' + this.varid + '.toggleAdvanced()"'
            + ' title="Mostrar / esconder opções avançadas"'
            + ' class="' + this.linkCssClass + '"'
            + ' id="' + this.advancedLinkID + '"'
            + '>&nbsp;Mostrar opções avançadas</a>';
    this.write('<br />' + a_href);
    this.openDiv(this.advancedDivID, this.advancedCssClass);
    
    for (var i = 0; i < selects.length; i++) {
        this.makeSelect(selects[i]);
    }
    this.write('<br />');
    this.openDiv('', this.imagesCssClass);
    this.write('&nbsp;');
    
    for (var i = 0; i < imgButtons.length; i++) {
        this.makeImageButton(imgButtons[i]);
    }
    this.closeDiv();
    this.closeDiv();
}

TextEditor.prototype.catchEnter = function(button, event) {
    var keyCode;

    if (event.keyCode) {
        keyCode = event.keyCode;
    } else if (event.which) {
        keyCode = event.which;
    }

    if (keyCode == 13) {
        event.returnValue = false;
        event.cancel = true;
        document.getElementById(button).click();
    }
}

TextEditor.prototype.cancelEnter = function(event) {
    var keyCode;

    if (event.keyCode) {
        keyCode = event.keyCode;
    } else if (event.which) {
        keyCode = event.which;
    }

    if (keyCode == 13) {
        return false;
    }

    return true;
}

TextEditor.prototype.makeImageForm = function() {
    var labelFix = (this.isFirefox || this.isNetscape ? ' style="display: -moz-inline-box;"' : '');
    
    this.openDiv(this.formImageDivID, this.imageFormCssClass);
    this.write('<hr />');
    this.write('<fieldset>');
    
    if (this.isIE) {
        this.write('<legend style="margin: 0 -7px;">Inserir imagem</legend>');
    } else {
        this.write('<legend>Inserir imagem</legend>');
    }
    this.write('<ol>');
    this.write('<li><label' + labelFix + ' for="' + this.formImageURLID + '">URL (endereço) <em>*</em></label><input id="' + this.formImageURLID + '" onkeypress="return ' + this.varid + '.cancelEnter(event);" style="width: 300px" /></li>');
    this.write('<li><label' + labelFix + ' for="' + this.formImageAltID + '">Descrição <em>*</em></label><input id="' + this.formImageAltID + '" onkeypress="return ' + this.varid + '.cancelEnter(event);" style="width: 300px" /></li>');
    this.write('<li><label' + labelFix + ' for="' + this.formImageAlignID + '">Alinhamento</label>');
    this.write('<select name="' + this.formImageAlignID + '" id="' + this.formImageAlignID + '" onkeypress="return ' + this.varid + '.cancelEnter(event);">');
    this.write('<option value="" selected="selected"></option>');
    this.write('<option value="center">Centro</option>');
    this.write('<option value="right">Direita</option>');
    this.write('<option value="left">Esquerda</option>');
    this.write('</select>');
    this.write('</li>');
    this.write('</ol>');
    this.write('</fieldset>');
    this.write('<input type="button" value="Inserir" id="' + this.formImageOKID + '" onClick="' + this.varid + '.validateImage()" />');
    this.write('<input type="button" value="Cancelar" onClick="' + this.varid + '.showImageForm(false);' + this.varid + '.focus();" />');
    this.closeDiv();
}

TextEditor.prototype.make = function(selects, imgButtons) {
    this.write('<input type="hidden" name="' + this.hiddenFieldID + '" id="' + this.hiddenFieldID + '" />');
    this.openEditor();
    this.openDiv(this.mainDivID, this.controlsCssClass);
    var a_href = '<a href="javascript:' + this.varid + '.showControls(true)"'
        + ' title="Mostrar barra de ferramentas"'
        + ' class="' + this.linkCssClass + '"'
        + ' id="' + this.controlsLinkID + '"'
        + '>Mostrar barra de ferramentas</a>';
    this.write(a_href);
    this.openDiv(this.controlsDivID, '');
    document.getElementById(this.controlsDivID).style.display = 'none';
    this.write('&nbsp;');
    this.makeSimpleToolbar();
    this.makeAdvancedToolbar(selects, imgButtons);
    this.makeImageForm();
    this.closeDiv();
    this.closeDiv();
    this.write('<iframe name="' + this.id + '" id="' + this.id + '" height="' + this.frameHeight + '" frameborder="0" scrolling="auto" class="textEditor"></iframe>');
    
    if (this.isAdmin) {
        this.write('<br />');
        this.write('<a href="javascript:' + this.varid + '.switchMode()" title="Ver / esconder HTML"><img src="' + this.root + 'imagens/editor/mode.gif" alt="Ver / esconder HTML" class="' + this.buttonCssClass + '" /></a>');
    }
    this.write('</span>\n'); // fix para IE!
    this.closeEditor();
    
    this.getElement().width = '99%';
}

   
/********************
 * Mode
 ********************/
TextEditor.prototype.getMode = function() {
    return this.mode;
}

TextEditor.prototype.setMode = function(mode) {
    this.mode = mode;
    this.activateMode();
}

TextEditor.prototype.switchMode = function() {
    this.mode = ( this.mode == TextEditorMode.WYSIWYG ? TextEditorMode.HTML : TextEditorMode.WYSIWYG );
    this.activateMode();
}

TextEditor.prototype.activateMode = function() {
    if (this.mode == TextEditorMode.HTML) {
        if (this.getDocument().body.innerText) {
            var html = this.getDocument().body.innerHTML;
            this.getDocument().body.innerText = html;        
        }
        else {
            var html = document.createTextNode(this.getDocument().body.innerHTML);
            this.getDocument().body.innerHTML = '';
            this.getDocument().body.appendChild(html);
        }
        this.showToolbar(false);
    } else {
        if (this.getDocument().body.innerText) {
            var text = this.getDocument().body.innerText;
            this.getDocument().body.innerHTML = text;
        } else {
            var html = this.getDocument().createRange();
            html.selectNodeContents(this.getDocument().body);
            this.getDocument().body.innerHTML = html.toString();
        }
        this.showToolbar(true);
    }
    this.focus();
}


/********************
 * show advanced / controls
 ********************/
TextEditor.prototype.show = function(show, linkID, divID) {
    var div = document.getElementById(divID);
    var link = document.getElementById(linkID);

    if (show) {
        div.style.display = 'block';
        link.style.display = 'none';
    } else {
        div.style.display = 'none';
        link.style.display = 'inline';
    }
}

TextEditor.prototype.showAdvanced = function(show) {
    this.show(show, this.advancedLinkID, this.advancedDivID);
}

TextEditor.prototype.showControls = function(show) {
    this.show(show, this.controlsLinkID, this.controlsDivID);
}

TextEditor.prototype.showToolbar = function(show) {
    var div = document.getElementById(this.mainDivID);
    div.style.display = (show ? 'block' : 'none');
}

TextEditor.prototype.showImageForm = function(show) {
    var div = document.getElementById(this.formImageDivID);
    div.style.display = (show ? 'block' : 'none');
}


/********************
 * toggleAdvanced
 ********************/
TextEditor.prototype.toggleAdvanced = function() {
    var div = document.getElementById(this.advancedDivID);
    var display = div.style.display;
    
    this.showAdvanced( (display == 'block' ? false : true) );
}


/********************
 * Comandos
 ********************/
TextEditor.prototype.bold = function() {
    this.execCommand('bold', null);
}

TextEditor.prototype.italic = function() {
    this.execCommand('italic', null);
}

TextEditor.prototype.list = function() {
    this.execCommand('insertunorderedlist', null);
}

TextEditor.prototype.listOrdered = function() {
    this.execCommand('insertorderedlist', null);
}

TextEditor.prototype.undo = function() {
    this.execCommand('undo', null);
}

TextEditor.prototype.redo = function() {
    this.execCommand('redo', null);
}

TextEditor.prototype.unlink = function() {
    this.execCommand('unlink', null);
}

TextEditor.prototype.link = function() {
    if (!this.isSafari) {
        var selection = this.getSelectionHTML();
    }
    
    var url = prompt('URL (com http://)', 'http://');
    
    if (!this.isSafari && selection == null || selection == '') {
        var texto = prompt('Texto do link', '');
        
        if (texto != null) {
            this.insertHTML('<a href="' + url + '">' + texto + '</a>');
        }
    } else if (url != null) {
        this.execCommand('createlink', url);
    }
}

TextEditor.prototype.heading = function(select) {
    var headingType = select.options[select.selectedIndex].value;
    
    if (headingType != '') {
        this.execCommand('formatblock', headingType);
    }
    select.selectedIndex = 0;
}


/********************
 * Comandos especiais
 ********************/
TextEditor.prototype.image = function() {
    this.imageAsk('', '', 0, false);
}

TextEditor.prototype.imageAsk = function(urlText, altText, alignIndex, disableTextInputs) {
    var url = document.getElementById(this.formImageURLID);
    var alt = document.getElementById(this.formImageAltID);
    var align = document.getElementById(this.formImageAlignID);
    url.disabled = disableTextInputs;
    alt.disabled = disableTextInputs;
    url.value = urlText;
    alt.value = altText;
    
    if (!this.isOpera) { // opera tem um bug em que não selecciona o indice neste situação
        align.selectedIndex = alignIndex;
    }
    this.showImageForm(true);
    
    if (disableTextInputs) {
        align.focus();
    } else {
        url.focus();
    }
}

TextEditor.prototype.validateImage = function() {
    var errorMsg = "Tem de especificar:\n";
    var error = false;
    
    var url = document.getElementById(this.formImageURLID).value;
    var alt = document.getElementById(this.formImageAltID).value;
    var align = document.getElementById(this.formImageAlignID).value;
    
    if (url == null || url == '') {
        errorMsg += " - o URL (endereço http://)\n";
        error = true;
    }
    
    if (alt == null || alt == '') {
        errorMsg += " - a descrição\n";
        error = true;
    }
    
    if (error) {
        alert(errorMsg);
    } else {
        this.insertImage(url, alt, align);
        this.showImageForm(false);
    }
}

TextEditor.prototype.table = function() {
    var rowstext = prompt('Número de linhas', '');
    
    if (rowstext == null) {
        return;
    }
    var colstext = prompt('Número de colunas', '');
    
    if (colstext == null) {
        return;
    }
    var rows = parseInt(rowstext);
    var cols = parseInt(colstext);

    if (rows > 0 && cols > 0) {
        var table = '<table>';
        var thead = '<thead>';
        thead += '<tr>';
        
        for (var i = 0; i < cols; i++) {
            thead += '<th><br /></th>';
        }
        thead += '</tr>';
        thead += '</thead>';
        
        var tbody = '<tbody>';

        for (var i = 0; i < rows; i++) {
            var tr = '<tr>';

            for (var j = 0; j < cols; j++) {
                tr += '<td><br /></td>';
            }
            tr += '</tr>';
            tbody += tr;
        }
        tbody += '</tbody>';
        table += thead + tbody + '</table>';
        this.insertHTML(table);
    }
}

TextEditor.prototype.quote = function() {
    this.surroundHTML('<blockquote>', '<br /></blockquote>');
}

TextEditor.prototype.select = function(select) {
    var selectedOption = select.options[select.selectedIndex].value;
    
    if (selectedOption != '') {
        this.insertHTML(selectedOption);
    }
    select.selectedIndex = 0;
}

TextEditor.prototype.imageHTML = function(url, alt, width, height, align) {
    var img = '<img src="' + url + '"'
            + ' alt="' + alt + '"'
            + ' width="' + width + 'px"'
            + ' height="' + height + 'px"'
            + ' align="' + align + '"'
            + ' />';
    this.insertHTML(img);
}

TextEditor.prototype.insertImage = function(url, alt, align) {
    var img;
    
    if (align == 'center') {
        img = '<center><img src="' + url + '"'
            + ' alt="' + alt + '"'
            + ' /></center>';    
    } else {
        img = '<img src="' + url + '"'
            + ' alt="' + alt + '"'
            + (align != '' ? ' align="' + align + '"' : '')
            + ' />';
    }
    this.insertHTML(img);
}


/********************
 * Funções auxiliares
 ********************/
 TextEditor.prototype.getElement = function() {
    return document.getElementById(this.id);
}

TextEditor.prototype.getDocument = function() {
    return this.getElement().contentWindow.document;
}

TextEditor.prototype.execCommand = function(command, option) {
    this.focus();
    this.getDocument().execCommand(command, false, option);
    this.focus();
}

TextEditor.prototype.focus = function() {
    if (this.isIE) {
        window.frames[this.id].focus();
    } else if (this.isOpera) {
        this.getElement().focus();
    } else {
        this.getElement().contentWindow.focus();
    }
}

TextEditor.prototype.getRange = function() {
    var window = this.getElement().contentWindow;

    if (window.getSelection) { // W3C
        var selection = window.getSelection();

      	if (selection.getRangeAt) {
    		return selection.getRangeAt(0);
    	} else { // Safari
    		var range = this.getDocument().createRange();
    		range.setStart(selection.anchorNode, selection.anchorOffset);
    		range.setEnd(selection.focusNode, selection.focusOffset);
            
    		return range;
    	}
    } else if (document.selection) { // IE
        return this.getDocument().selection.createRange();
    }
}

TextEditor.prototype.deselect = function(window) {
    if (window.getSelection) {
        window.getSelection().removeAllRanges();
    } else if (document.selection) {
        this.getDocument().selection.empty();
    }
    
}

TextEditor.prototype.deleteSelection = function(range) {
    if (window.getSelection) {
        range.deleteContents();
    } else if (document.selection) {
        this.getDocument().selection.clear();
    }
}

TextEditor.prototype.insertHTML = function(html) {
    if (this.isIE && this.getDocument().selection) {
        this.focus();
        var range = this.getDocument().selection.createRange();
        
        range.pasteHTML(html);
        range.collapse(false);
        range.select();
    } else {
        this.execCommand('insertHTML', html);
    }
}

TextEditor.prototype.surroundHTML = function(begin, end) {
    this.insertHTML(begin + this.getSelectionHTML() + end);
}

TextEditor.prototype.getSelectionHTML = function() {
    var range = this.getRange();
    
    if (this.isIE && this.getDocument().selection) {
        return range.htmlText;
    } else {
        var e = this.getDocument().createElement('body');
        
        if (range.cloneContents) {
            e.appendChild(range.cloneContents());
        } else if (typeof(range.item) != 'undefined' || typeof(range.htmlText) != 'undefined') {
            e.innerHTML = (range.item ? range.item(0).outerHTML : range.htmlText);
        } else {
            e.innerHTML = range.toString();
        }

        return e.innerHTML;
    }
}
