# -*- coding: utf-8 -*-
#
# This file is part of NINJA-IDE (http://ninja-ide.org).
#
# NINJA-IDE is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# any later version.
#
# NINJA-IDE is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with NINJA-IDE; If not, see <http://www.gnu.org/licenses/>.

import os
import shutil
from PyQt4.QtCore import QObject, QFile, QIODevice, QTextStream, SIGNAL

from ninja_ide import translations
#FIXME: Obtain these form a getter
from ninja_ide.core import settings
from ninja_ide.tools.utils import SignalFlowControl
from file_manager import NinjaIOException, NinjaNoFileNameException, \
get_file_encoding, get_basename, get_file_extension

from ninja_ide.tools.logger import NinjaLogger
logger = NinjaLogger('ninja_ide.core.file_handling.nfile')
DEBUG = logger.debug

"""
How to continue:
    We need to have a filesystem representation object, said object, registers
    himself into the IDE on its __init__.py, thus avoiding all kinds of
    circular imports, this way all objects should start registering themselves
    and fail individually if they cant.
    So, to this object, whoever creates new NFiles should ask for a it, this
    way it keeps record of the files and can do closing when receives
    terminate from the ide, and decides to call a changed callback from each
    file when the watched, that should deppend on it notifies a change.
"""


class NFile(QObject):
    """
    """

    def __init__(self, path=None):
        """
        """
        self._file_path = path
        self.__created = False
        super(NFile, self).__init__()
        if not self._exists():
            self.__created = True

    @property
    def file_name(self):
        """"Returns filename of nfile"""
        file_name = None
        if self._file_path is None:
            file_name = translations.TR_NEW_DOCUMENT
        else:
            file_name = get_basename(self._file_path)
        return file_name

    @property
    def display_name(self):
        """Returns a pretty name to be displayed by tabs"""
        display_name = self.file_name
        if not self._file_path is None and not self.has_write_permission():
            display_name += translations.TR_READ_ONLY
        return display_name

    @property
    def file_ext(self):
        """"Returns extension of nfile"""
        if self._file_path is None:
            return ''
        return get_file_extension(self._file_path)

    @property
    def file_path(self):
        """"Returns file path of nfile"""
        return self._file_path

    def has_write_permission(self):
        if not self._exists():
            return True
        return os.access(self._file_path, os.W_OK)

    def _exists(self):
        """
        Check if we have been created with a path and if such path exists
        In case there is no path, we are most likely a new file.
        """
        file_exists = False
        if self._file_path and os.path.exists(self._file_path):
            file_exists = True
        return file_exists

    def save(self, content, path=None, copy=False):
        """
        Write a temprorary file with .tnj extension and copy it over the
        original one.
        .nsf = Ninja Swap File
        #FIXME: Where to locate addExtension, does not fit here
        """
        save_path = path and path or self._file_path
        if not copy:
            self._file_path = save_path

        if not save_path:
            raise NinjaNoFileNameException("I am asked to write a "
                                "file but no one told me where")
        swap_save_path = u"%s.nsp" % save_path

        flags = QIODevice.WriteOnly | QIODevice.Truncate
        f = QFile(swap_save_path)
        if settings.use_platform_specific_eol():
            flags |= QIODevice.Text

        if not f.open(flags):
            raise NinjaIOException(f.errorString())

        stream = QTextStream(f)
        encoding = get_file_encoding(content)
        if encoding:
            stream.setCodec(encoding)

        encoded_stream = stream.codec().fromUnicode(content)
        f.write(encoded_stream)
        f.flush()
        f.close()
        #SIGNAL: Will save (temp, definitive) to warn folder to do something
        self.emit(SIGNAL("willSave(QString, QString)"), swap_save_path,
                                                        save_path)
        shutil.move(swap_save_path, save_path)
        if not (path and copy):
            self.reset_state()

    def reset_state(self):
        """
        #FIXE: to have a ref to changed I need to have the doc here
        """
        self._created = False

    def read(self, path=None):
        """
        Read the file or fail
        """
        open_path = path and path or self._file_path
        self._file_path = open_path
        if not self._file_path:
            raise NinjaNoFileNameException("I am asked to read a "
                                    "file but no one told me from where")
        try:
            with open(open_path, 'rU') as f:
                content = f.read()
        except IOError as reason:
            raise NinjaIOException(reason)
        return content

    def move(self, new_path):
        """
        Phisically move the file
        """
        if self._exists():
            signal_handler = SignalFlowControl()
            #SIGNALL: WILL MOVE TO, to warn folder to exist
            self.emit(SIGNAL("willMove(Qt_PyQtObject, QString, QString)"),
                                                            signal_handler,
                                                            self._file_path,
                                                            new_path)
            if signal_handler.stopped():
                return
            if os.path.exists(new_path):
                signal_handler = SignalFlowControl()
                self.emit(
                    SIGNAL("willOverWrite(Qt_PyQtObject, QString, QString)"),
                                    signal_handler, self._file_path, new_path)
                if signal_handler.stopped():
                    return

            shutil.move(self._file_path, new_path)
        self._file_path = new_path
        return

    def copy(self, new_path):
        """
        Copy the file to a new path
        """
        raise NotImplementedError("Have not yet found use for this")

    def delete(self, force=False):
        """
        This deletes the object and closes the file.
        """
        #if created but exists this file migth to someone else
        self.close()
        if ((not self._created) or force) and self._exists():
            DEBUG("Deleting our own NFile %s" % self._file_path)
            signal_handler = SignalFlowControl()
            self.emit(SIGNAL("willDelete(PyQt_PyObject, PyQt_PyObject)"),
                                                        signal_handler, self)
            if not signal_handler.stopped():
                os.remove(self._file_path)

    def close(self):
        """
        Lets let people know we are going down so they can act upon
        As you can see close does nothing but let everyone know that we are
        not saved yet
        """
        DEBUG("About to close NFile")
        if self._created:
            self.emit(SIGNAL("neverSavedFileClosing(QString)"),
                        self._file_path)
        else:
            self.emit(SIGNAL("fileClosing(QString)"), self._file_path)
Contents © 2013 NINJA-IDE - Powered by Nikola and Documentor