# Copyright (C) 2009 Canonical Ltd
#
# This program 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 2 of the License, or
# (at your option) any later version.
#
# This program 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 this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA

from PyQt4 import QtCore, QtGui

from bzrlib.plugins.explorer.lib import (
    html_report_view,
    status_report,
    view_submit,
    )
from bzrlib.plugins.explorer.lib.i18n import gettext, N_
from bzrlib.plugins.explorer.lib.filesystemwatcher import QFileSystemWatcher
from bzrlib import urlutils, osutils
from bzrlib.errors import LockContention, NotLocalUrl


class WorkingTreeView(QtCore.QObject):
    """The default view for branches & checkouts with working trees."""

    def __init__(self, model, action_callback):
        QtCore.QObject.__init__(self)
        self.model = model
        self.action_callback = action_callback
        self.status_view = _StatusView(model, action_callback)

        # Decide which detail panels to display.
        # It may be a useful to define some preferences and to
        # leave it up to the user as to which detail panels get displayed.
        # In the short term though, the goal is simply to provide high
        # value ones which everyone ought to want. :-)
        self.detail_views = []
        branch = self.model.branch
        # Display the delta versus the submit or parent branch iff one is
        # defined and it's local. Unfortunately though, merging a feature
        # branch into trunk sets the merged-from branch as the submit
        # branch which means we see a "silly" submit delta panel for trunk.
        # To work around that, we show the parent location instead of the
        # submit location for a bound branch.
        if branch.get_bound_location() is None:
            submit_url = branch.get_submit_branch()
            if submit_url:
                target = 'submit'
                name = gettext('Submit delta')
            else:
                submit_url = branch.get_parent()
                target = 'parent'
                name = gettext('Parent delta')
        else:
            target = 'parent'
            name = gettext('Parent delta')
            submit_url = branch.get_parent()

        if submit_url and submit_url.startswith("file:"):
            self.detail_views.append(
                (view_submit.SubmitView(model, action_callback, target),
                    name),
                )

        # TODO: add other panels to show what's on the shelf, etc.

        self.file_watcher = QFileSystemWatcher()
        self.file_watcher.directoryChanged.connect(
                                                self._branch_directory_changed)
        self._add_file_watcher_paths()
        self.refresh_lock = False

    def ui(self):
        # Build the details panel
        count = len(self.detail_views)
        if count == 0:
            details = None
        elif count == 1:
            view, label = self.detail_views[0]
            details = view.ui()
        else:
            details = QtGui.QTabWidget()
            for view, label in self.detail_views:
                details.addTab(view.ui(), label)

        # Build the overall view
        status = self.status_view.ui()
        if details is None:
            return status
        else:
            # Status view above the details with 25% allocated to the latter
            splitter = QtGui.QSplitter()
            splitter.setOrientation(QtCore.Qt.Vertical)
            splitter.addWidget(status)
            splitter.addWidget(details)
            splitter.setStretchFactor(0, 3)
            splitter.setStretchFactor(1, 1)
            return splitter

    def _add_file_watcher_paths(self):
        """Recursively find directories and add to file_watcher.
        :param root: the directory to start looking from
        :return: list of directories within root
        """
        try:
            root = self.model.branch.user_transport.local_abspath(".")
        except NotLocalUrl:
            return []
        result = []
        for (dir_info, dir_entries) in osutils._walkdirs_utf8(root):
            utf8_relpath, system_path = dir_info
            if system_path not in self.file_watcher.directories():
                result.append(system_path)
        if len(result) > 0:
           self.file_watcher.addPaths(result)
        return result

    def _branch_directory_changed(self):
        """refresh view after short delay, called by the QFileSystemWatcher"""
        # more reliable to delay refresh a bit else the external change
        # may not have completed
        QtCore.QTimer.singleShot(500, self.refresh_view)

    def refresh_view(self):
        if self.refresh_lock:
            return
        self.refresh_lock = True
        try:
            self.status_view.refresh_view()
        except LockContention as e:
            self.refresh_lock = False
            return
        for view, label in self.detail_views:
            view.refresh_view()
        #update paths to watch incase of new directories
        self._add_file_watcher_paths()
        self.refresh_lock = False


class _StatusView(html_report_view.HtmlReportView):
    """The status view showing what's about to be committed."""

    def report_text(self):
        model = self._model
        report = status_report.StatusReport(model.branch, model.tree,
            model.relpath)
        return report.full_report()
