"""
A rich text editor using FCKeditor.

Pass "-j fckeditor/fckeditor.js" to build.py in order to include the
FCKeditor javascript.
"""

from BoundMethod import BoundMethod
from pyjamas import logging
from pyjamas import DOM
from pyjamas import Window
from pyjamas.ui.Widget import Widget
from __pyjamas__ import JS

log = logging.getAppendLogger(__name__, logging.DEBUG, logging.PLAIN_FORMAT)


def createFCK(name):
    JS("""
       return new @{{!FCKeditor}}(@{{name}});
    """)

JS("""
   $wnd.FCKeditor_OnComplete = function(editorInstance )
   {
       var pyjsObject = $doc.getElementById(editorInstance.Name.substr(3)).__listener;
       if(pyjsObject)
           pyjsObject.onFCKLoaded(editorInstance);
   }
""")


class RichTextEditor(Widget):

    def __init__(self, initialValue="", target="", method="POST", 
                        basePath=None, **kwargs):

        self.id = "rte" + str(hash(self))

        self.setElement(DOM.createForm())
        DOM.setAttribute(self.element, "method", method)
        DOM.setAttribute(self.element, "target", target)

        if not kwargs.has_key('ID'): kwargs['ID'] = self.id
        if not kwargs.has_key('StyleName'): kwargs['StyleName'] = "gwt-RichTextEditor"
        if not kwargs.has_key('Height'): kwargs['Height'] = "600px"
        if not kwargs.has_key('Width'): kwargs['Width'] = "100%"
        Widget.__init__(self, **kwargs)

        JS("""
           var rte = this;
           this.element.onsubmit = function() {
               $wnd.setTimeout(function() { rte.onSave.call(rte) }, 0);
               return false;
           }
        """)

        if basePath is None:
            basePath = "fckeditor/"
        if not basePath.endswith("/"):
            basePath += "/"
        fck = createFCK("fck" + self.id)
        fck.Height = self.getHeight()
        fck.Width = self.getWidth()
        fck.Value = initialValue
        fck.BasePath = basePath
        fck.Config.CustomConfigurationsPath = "../../fckconfig.js"
        fck.pyjsObject = self

        self.loaded = False
        self.saveListeners = []
        self.pendingHTML = None

        html = fck.CreateHtml()
        DOM.setInnerHTML(self.getElement(), html)

    def addSaveListener(self, listener):
        """
        When the user clicks the save button, your listener will be
        notified.

        Either pass a function (e.g. a BoundMethod) or an object with
        an onSave() method. Either will be passed the RichtTextEditor
        instance.
        """
        self.saveListeners.append(listener)

    def removeSaveListener(self, listener):
        """
        Remove a previously added listener.
        """
        self.saveListeners.remove(listener)

    def onFCKLoaded(self, fck):
        """
        Called when the FCK editor has loaded, and it is ready for use.
        """
        self.loaded = True
        self.fck = fck
        fck.Events.AttachEvent('OnSelectionChange',
                               BoundMethod(self, self.onSelectionChange))
        fck.Events.AttachEvent('OnBlur', BoundMethod(self, self.onBlur))
        fck.Events.AttachEvent('OnFocus', BoundMethod(self, self.onFocus))
        fck.Events.AttachEvent('OnPaste', BoundMethod(self, self.onPaste))
        if self.pendingHTML:
            fck.SetHTML(self.pendingHTML)
            self.pendingHTML = None

    def onSelectionChange(self, sender):
        pass#log.debug("onSelectionChange!")

    def onBlur(self, sender):
        pass#log.debug("onBlur!")

    def onFocus(self, sender):
        pass#log.debug("onFocus!")

    def onPaste(self, sender):
        pass#log.debug("onPaste!")

    def onSave(self):
        """
        Handle the save click and pass it onto the listeners.
        """
        log.debug("onSave() in %s", Window.getLocation().getHref())
        for listener in self.saveListeners:
            if hasattr(listener, "onSave"):
                listener.onSave(self)
            else:
                listener(self)
        return False

    def setHTML(self, html):
        """
        Call this to change the html showing in the editor.
        """
        if self.loaded:
            self.fck.SetHTML(html)
        else:
            self.pendingHTML = html

    def getHTML(self):
        """
        Call this to retrieve the HTML showing in the editor (e.g. to
        save/preview it).
        """
        return self.fck.GetXHTML(True)

    def getDOM(self):
        return self.fck.EditorDocument()

    def getWindow(self):
        return self.fck.EditorWindow()
