/**
 * a generic Rich Text Editor used in ClearSpace
 * @param domID: the id of the textarea to replace with a RTE
 */
jive.rte.RTE = function(control, domID, settings_id){
    var that = this;
    var textonly = false;
    var tinyText = $(domID);
    var textbox = document.createElement('TEXTAREA');
    textbox.style.display = "none";
    tinyText.parentNode.insertBefore(textbox, tinyText);

    if(!$def(settings_id)){
        settings_id = 0;
    }

    var settings = jive.rte.settings(settings_id);
    settings.mode = "exact";
    settings.elements = domID;
    settings.images_enabled = window._images_enabled;
    try{
        if(!settings.jive_image_picker_url && _jive_image_picker_url){
            settings.jive_image_picker_url = _jive_image_picker_url;
        }
    }catch(e){ }
    if(typeof(tinyMCE) == "undefined"){
        // safari 2!
        textonly = true;
        textbox.style.display = "none";
        tinyText.style.display = "block";
        tinyText.style.height = "200px";
    }else{
        try{
        tinyMCE.init(settings);
        }catch(e){
            textonly = true;
            textbox.style.display = "none";
            tinyText.style.display = "block";
            tinyText.style.height = "200px";
        }
    }

    this.isTextOnly = function(){
        return textonly;
    }


    var my_editor = null;
    var ignore_change = true;

    // true if the spell checker is running
    var is_spelling = false;

    /**
     * returns the tinymce editor
     *
     * this function is private for a reason, and
     * the tinymce editor shouldn't be exposed outside
     * of this class.
     */
    var ignoreResize = true;

    function getEditor(){
        if(!that.isTextOnly() && my_editor == null){
            my_editor = tinyMCE.getInstanceById(domID);
            if(!$def(my_editor) || my_editor == null){
                return null;
            }
            my_editor.getContainer().childNodes[0].style.width = "";
            my_editor.onKeyUp.add(function(ed, e){ that.notifyOnKeyUp(e.keyCode); });
            my_editor.onChange.add(function(ed, e){ that.notifyOnChange(e.keyCode); });
            my_editor.onInit.add(function(that){ return function(ed, e){
                if(ed.id == domID) that.notifyInitFinished();
            }}(that));
            my_editor.onBeginSpelling.add( function(){ is_spelling = true; });
            my_editor.onEndSpelling.add(function(){ is_spelling = false; });
            my_editor.theme.onResize.add(function(){
                if(ignoreResize){
                    ignoreResize = false;
                    that.resizeTo(that.getHeight()+that.getToolbarHeight()+1);
                    my_editor.theme.onResize.dispatch();
                }else{
                    ignoreResize = true;
                    that.notifyResized();
                }
            });
            my_editor.plugins.html.registerToggleFunction(that.toggleEditorMode);
            //
            // sometimes the onInit() event doesn't fire from tinymce,
            // so this is our backup
            window.setTimeout(function() {
                that.notifyInitFinished();
            }, 5000);


            if(window.autoSave){
                var list = {
                    navigateAway : function(){
                        if(window && window.autoSave && that.restoreNavigateAway){
                            window.autoSave.confirmation = that.restoreNavigateAway;
                            that.restoreNavigateAway = false;
                        }
                    }
                }
                window.autoSave.addListener(list);
            }
        }

        return my_editor;
    }

    this.isSpellChecking = function(){
        return is_spelling;
    }

    this.toggleSpellChecker = function(){
        getEditor().execCommand("mceSpellCheck");
    }

    this.closeAllDialogs = function(){
        var windows = getEditor().windowManager.windows;
        var keys = Object.keys(windows);
        for(var i=0;i<keys.length;i++){
            getEditor().windowManager.close(null, windows[keys[i]].id);
        }
        return windows;
    }

    /**
     * adds a macro to the RTE w/ the default paramset
     * @param macro
     * @param paramset a parameter set. these can be created w/ the jive.rte.ParamSet class
     */
    this.addMacro = function(macro, paramset){
        var ed = getEditor();
        var collapsed = ed.selection.isCollapsed();
        var pre = ed.plugins.jivemacros.insertMacro(macro);
        ed.plugins.jivemacros.applyParameterSet(pre, macro, paramset);
        if(collapsed){
            pre.setAttribute("id", "__sel_me__");
            ed.selection.setNode(pre);
            pre = ed.getDoc().getElementById("__sel_me__");
            pre.removeAttribute("id");
        }
        ed.nodeChanged();
        return pre;
    }

    /**
     * destroys an editor
     * @param str
     * @param def
     */
    this.destroy = function(){
        tinyMCE.remove(domID);
        textbox.parentNode.removeChild(textbox);
        getEditor().getContainer().parentNode.removeChild(my_editor.getContainer());
    }

    /**
     * returns the i18n value for the input string, or returns the default if none
     * @param str
     * @param def
     */
    this.getLang = function(str, def){
        return getEditor().getLang(str, def);
    }

    /**
     *  returns true if the editor has been fully loaded
     *  returns false otherwise
     *
     * don't count on any other functions working until this
     * guy returns true...
     */
    this.isReady = function(){
        if(that.isTextOnly()) return true;
        var ed = getEditor();
        return ed != null;
    }


    /**
     * returns the DOM container for this editor
     */
    this.getDOM = function(){
        return getEditor().getContainer();
    }

    /**
     * returns the ID of the DOM that this editor was initialized with
     * @param html
     */
    this.getID = function(){
        return domID;
    }

    /**
     * sets the XHTML data for this editor
     * @param html
     */
    this.setHTML = function(html){
        if(that.isTextOnly()){
            return tinyText.value = html;
        }
        textbox.value = html;
        return getEditor().setContent(html);
    }

    /**
     * returns the XHTML data from this editor
     */
    this.getHTML = function(){
        if(that.isTextOnly()){
            return tinyText.value;
        }
        if(this.isHidden()){
            this.setHTML(textbox.value);
        }
        var body = getEditor().getContent();

        if((this.trim(body).length > 0) && body.indexOf("<body") != 0){
            body = "<body>" + body + "</body>";
        }
        while(body.indexOf("  ") >= 0){
            body = body.replace("  ", "&nbsp; ");
        }
        return body;
    }

    /**
     * returns the trimmed string
     */

    this.trim = function(input){
        var	str = input.replace(/^\s\s*/, '');
        var ws = /\s/;
        var i = str.length;
        while (ws.test(str.charAt(--i)));
        return str.slice(0, i + 1);
    }


    /**
     * shows the editor in the page if it's hidden
     */
    this.show = function(){
        getEditor().show();
        that.notifyShowing();
    }

    /**
     *  returns the window object that this RTE is
     *  inside of
     */
    this.getWindow = function(){
        return getEditor().getWin();
    }

    /**
     * returns the document body of which this
     * RTE is a part
     */
    this.getBody = function(){
        return getEditor().getBody();
    }

    /**
     * focuses the cursor in the RTE
     */
    this.focus = function(){
        try{
            if(this.isHidden()){
                textbox.focus();
            }else{
                getEditor().focus();
            }
        }catch(e){ }
    }

    /**
     * collapse the editor's cursor to a point
     */
    this.collapseSelection = function(){
        var ed = getEditor();
        ed.selection.select(ed.selection.getNode());
        ed.selection.collapse();
    }

    /**
     * hides the RTE from view
     */
    this.hide = function(){
        getEditor().hide();
    }

    /**
     * returns true of the RTE is hidden from view
     */
    this.isHidden = function(){
        return textbox.style.display == "block";
    }

    /**
     * resize the editor to the input height
     * @param height
     */
    this.resizeTo = function(height){
        var contain = getEditor().getContainer();
        var table = contain.firstChild;
        if(table.nodeName.toLowerCase() != "table") table = table.childNodes[0]; // IE 6
        var h = jive.ext.x.xHeight(table.rows[0].cells[0]);
        if(table.rows.length > 2){
            h += jive.ext.x.xHeight(table.rows[table.rows.length-1].cells[0]);
        }
        var box = getEditor().getContentAreaContainer();
        var ifr = getEditor().getContentAreaContainer().firstChild;
        tinymce.DOM.setStyle(ifr, 'height', height-h); // Resize iframe
//        tinymce.DOM.setStyle(box, 'height', height-h); // Resize td around the iframe
        tinymce.DOM.setStyle(table, 'height', height); // Resize table
    }

    /**
     * returns the height in px of the editor
     */
    this.getHeight = function(){
        var ifr = getEditor().getContentAreaContainer().firstChild;
        return jive.ext.x.xHeight(ifr);
    }

    this.getToolbarHeight = function(){
        var contain = getEditor().getContainer();
        var table = contain.firstChild;
        if(table.nodeName.toLowerCase() != "table") table = table.childNodes[0]; // IE 6
        var h = jive.ext.x.xHeight(table.rows[0].cells[0]);
        if(table.rows.length > 2){
            h += jive.ext.x.xHeight(table.rows[table.rows.length-1].cells[0]);
        }
        return h;
    }

    /**
     * toggles the editor between rich and raw html
     */
    this.toggleEditorMode = function(edid){
        if(edid == domID){
            if(window && window.autoSave){
                that.restoreNavigateAway = window.autoSave.confirmation;
                window.autoSave.confirmation = false;
            }
            var tiny = $(domID + '_parent');
            if(that.isHidden()){
                var h = jive.ext.x.xHeight(textbox);
                textbox.style.display = "none";
                that.show();
                that.setHTML(textbox.value);
                that.focus();
                that.resizeTo(h);
                getEditor().plugins.jivemacros.removeDuplicateMacros(getEditor(), getEditor().getBody());
            }else{
                var tinyt = $(domID + '_tbl');
                var h = jive.ext.x.xHeight(tinyt);
                textbox.value = that.getHTML(true);
                that.hide();
                textbox.style.display = "block";
                // never show tinyMCE's text box to the user
                // only show our own text box
                tinyText.style.display = "none";
                jive.ext.x.xHeight(textbox,h);
                that.focus();
            }
            that.notifyDoneTogglingMode();
        }
    }


    /******************************************
     * listener functions
     ******************************************/
    this.addListener = function(list){
        if($def(list.onShow)) list.onShow();
        listeners.push(list);
    }

    var listeners = new Array();
    var listener_actions = new Array();
    /**
     * act must be a thunk (a function without arguments)
     * it will be executed after either
     * notifyLoadFinish or notifyLoadFail
     */
    this.addListenerAction = function(act){
        listener_actions.push(act);
    }

    /**
     * private
     * executes all the listener actions
     */
    this.executeListenerActions = function(){
        while(listener_actions.length > 0){
            listener_actions[0]();
            listener_actions.splice(0,1);
        }
    }

    this.removeListener = function(list){
        for(var i=0;i<listeners.length;i++){
            if(listeners[i] == list){
                listeners.splice(i, 1);
            }
        }
    }

    this.initted = false;
    this.notifyInitFinished = function(){
        if(!that.initted){
            that.initted = true;
            for(var i=0;i<listeners.length;i++){
                listeners[i].initFinished();
            }
            that.executeListenerActions();
        }
    }

    this.notifyOnKeyUp = function(keyCode){
        // the user typed a key!
        for(var i=0;i<listeners.length;i++){
            listeners[i].onKeyUp(keyCode);
        }
        that.executeListenerActions();
    }

    this.notifyOnChange = function(){
        if(ignore_change){
            ignore_change = false;
            return;
        }
        // the user typed a key!
        for(var i=0;i<listeners.length;i++){
            listeners[i].onChange();
        }
        that.executeListenerActions();
    }

    this.notifyResized = function(){
        // the user typed a key!
        for(var i=0;i<listeners.length;i++){
            listeners[i].onResize();
        }
        that.executeListenerActions();
    }

    this.notifyShowing = function(){
        // the user typed a key!
        for(var i=0;i<listeners.length;i++){
            listeners[i].onShow();
        }
        that.executeListenerActions();
    }

    this.notifyDoneTogglingMode = function(){
        // the user typed a key!
        for(var i=0;i<listeners.length;i++){
            listeners[i].doneTogglingMode();
        }
        that.executeListenerActions();
    }
}
