import os
import tempfile

class CouldNotEdit(RuntimeError):
    pass

class TextualEditor:
    """This class is an abstract superclass for editing text
    in an external editor. It has an overridable method for retrieving
    text, and a method for saving the text back (when the editor
    returned a succesful exis code.
    @editors is a list of editors to try. If it is empty, $EDITOR
    will be used. (BUG we could try some internal QT TextEdit modal
    widget as well...)"""
    def __init__(self, editors):
        if not editors:
            from coral import configuration
            config = configuration.getCoralConfiguration()
            editors = config.dGet(["GUI", "external_text_editors"])
            if not editors:
                editors = []
            else:
                editors = editors.split(":")
        # Try $EDITOR first
        e = os.getenv("EDITOR")
        if e:
            editors.insert(0, e)

        if not editors:
            editors = [ "emacs", "xemacs" ]

        self.__editors = editors
        succ, ls = self.__runEditor()
        if not succ:
            raise CouldNotEdit()
        self._set(ls)

    def __runEditor(self):
        ls = self._get()
        (f, name) = tempfile.mkstemp("", "coral-tmp-")
        try:
            try:
                for i in ls:
                    if isinstance(i, unicode):
                        i = i.encode("UTF-8")
                    os.write(f, i + "\n")
                for ed in self.__editors:
                    # This hangs coral until the editor exits.
                    exitcode = os.spawnvp(os.P_WAIT, ed, [ ed, name] )
                    # UNIX: 127 means we could not launch the
                    # program. Try next editor.
                    if exitcode == 127:
                        continue
                    # Unsuccessful exit, don't update
                    if exitcode != 0:
                        return False, [];
                    lst = []
                    fl = file(name, "r")
                    try:
                        ls = []
                        for line in fl:
                            line = line.rstrip("\n")
                            ls.append(unicode(line, "UTF-8"))
                        return True, ls
                    finally:
                        fl.close()
                return False, []
            finally:
                os.close(f)
        finally:
            os.unlink(name)

    def _get(self):
        """Retrieves a list of strings to be shown initially to the user."""
        assert 0

    def _set(self, ls):
        """Sets the values based on a list of strings @ls. After this
        @self should not be used."""
        assert 0

