"""Buffer class."""

__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"

from .interpreter import Interpreter
import types
import os
import sys

from . import document


class Buffer:
    """Buffer class."""

    id = 0

    def __init__(self, filename=None):
        """Create a Buffer instance."""
        Buffer.id += 1
        self.id = Buffer.id
        self.interp = Interpreter(locals={})
        self.name = ''
        self.editors = {}
        self.editor = None
        self.modules = list(sys.modules)
        self.syspath = sys.path[:]
        while True:
            try:
                self.syspath.remove('')
            except ValueError:
                break
        while True:
            try:
                self.syspath.remove('.')
            except ValueError:
                break
        self.open(filename)

    def addEditor(self, editor):
        """Add an editor."""
        self.editor = editor
        self.editors[editor.id] = editor

    def hasChanged(self):
        """Return True if text in editor has changed since last save."""
        if self.editor:
            return self.editor.hasChanged()
        else:
            return False

    def new(self, filepath):
        """New empty buffer."""
        if not filepath:
            return
        if os.path.exists(filepath):
            self.confirmed = self.overwriteConfirm(filepath)
        else:
            self.confirmed = True

    def open(self, filename):
        """Open file into buffer."""
        self.doc = document.Document(filename)
        self.name = self.doc.filename or ('Untitled:' + str(self.id))
        self.modulename = self.doc.filebase
        # XXX This should really make sure filedir is first item in syspath.
        # XXX Or maybe this should be moved to the update namespace method.
        if self.doc.filedir and self.doc.filedir not in self.syspath:
            # To create the proper context for updateNamespace.
            self.syspath.insert(0, self.doc.filedir)
        if self.doc.filepath and os.path.exists(self.doc.filepath):
            self.confirmed = True
        if self.editor:
            text = self.doc.read()
            self.editor._setBuffer(buffer=self, text=text)

    def overwriteConfirm(self, filepath):
        """Confirm overwriting an existing file."""
        return False

    def save(self):
        """Save buffer."""
        filepath = self.doc.filepath
        if not filepath:
            return  # XXX Get filename
        if not os.path.exists(filepath):
            self.confirmed = True
        if not self.confirmed:
            self.confirmed = self.overwriteConfirm(filepath)
        if self.confirmed:
            self.doc.write(self.editor.getText())
            if self.editor:
                self.editor.setSavePoint()

    def saveAs(self, filename):
        """Save buffer."""
        self.doc = document.Document(filename)
        self.name = self.doc.filename
        self.modulename = self.doc.filebase
        self.save()

    def updateNamespace(self):
        """Update the namespace for autocompletion and calltips.

        Return True if updated, False if there was an error."""
        if not self.interp or not hasattr(self.editor, 'getText'):
            return False
        syspath = sys.path
        sys.path = self.syspath
        text = self.editor.getText()
        text = text.replace('\r\n', '\n')
        text = text.replace('\r', '\n')
        name = self.modulename or self.name
        module = types.ModuleType(name)
        newspace = module.__dict__.copy()
        try:
            try:
                code = compile(text, name, 'exec')
            except:
                raise
#                return False
            try:
                exec(code, newspace)
            except:
                raise
#                return False
            else:
                # No problems, so update the namespace.
                self.interp.locals.clear()
                self.interp.locals.update(newspace)
                return True
        finally:
            sys.path = syspath
            for m in sys.modules:
                if m not in self.modules:
                    del sys.modules[m]
