# 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

"""Miscellaneous stuff that might move into bzrlib or qbzr one day.

In some cases, the code is already in bzrlib but in a later version
than the minimum version required.
"""

from PyQt4 import QtCore, QtGui

from bzrlib.config import ConfigObj
from bzrlib.osutils import joinpath, splitpath


def reload_config_obj(cfg, filename):
    """Reload a Bazaar Config object from a file."""
    try:
        stream = open(filename, 'r')
    except IOError:
        lines = []
    else:
        lines = stream.readlines()
        stream.close()
    new_config_obj = ConfigObj(lines, encoding='utf-8')
    try:
        cfg.store._config_obj = new_config_obj
    except AttributeError: # bzr < 2.6
        cfg._parser = new_config_obj


def parent_directories(filename):
    """Return the list of parent directories, deepest first.
    
    For example, parent_directories("a/b/c") -> ["a/b", "a"].
    """
    parents = []
    parts = splitpath(dirname(filename))
    while parts:
        parents.append(joinpath(parts))
        parts.pop()
    return parents


def build_combo_with_labels(data_label_tuples):
    """Build a combo-box with labelled data value."""
    combo = QtGui.QComboBox()
    for data, label in data_label_tuples:
        combo.addItem(label, QtCore.QVariant(data))
    return combo


def wrap_widget_in_group_box(widget, title):
    group = QtGui.QGroupBox()
    layout = QtGui.QVBoxLayout()
    layout.addWidget(widget)
    group.setLayout(layout)
    group.setTitle(title)
    return group


def get_tree_expansion(tree, only_expanded=False):
    """Return the rows currently expanded and collapsed in a QTreeView.
    
    Rows are identified by sequences of integers. That makes restoration
    of expansion information easy but it's obviously quite fragile
    vs remembering sequences of paths. YMMV.

    :param tree: the QTreeView widget
    :param only_expanded: if True, collapsed data isn't collected
    :return: expanded, collapsed where both are lists of row identifiers
    """
    if tree is None:
        return [], []
    model = tree.model()
    if model is None:
        return [], []
    expanded = []
    collapsed = []
    def walk_row(parent, context):
        for row in range(0, model.rowCount(parent)):
            index = model.index(row, 0, parent)
            if tree.isExpanded(index):
                context = context[:] + [row]
                expanded.append(context)
                walk_row(index, context)
            elif only_expanded:
                continue
            elif model.hasChildren(index):
                context = context[:] + [row]
                collapsed.append(context)
    root = QtCore.QModelIndex()
    walk_row(root, [])
    return expanded, collapsed


def set_tree_expansion(tree, expand_list, collapse_list):
    """Expand and collapse items in a QTreeView.
    
    The parameters are lists of row identifiers where each identifier
    is a sequence of "child indexes" based from 0, e.g. [1] means
    to expand the 2nd child at the root level while [1, 3] means to
    expand the 4th child within that one.
    """
    if tree is None:
        return
    model = tree.model()
    if model is None:
        return
    def index_for_item(item):
        parent = QtCore.QModelIndex()
        for child in item:
            parent = model.index(child, 0, parent)
        return parent
    # NOTE: Basic sequences seem to work fine. More complex ones
    # struggle though. I can't see anything obviously wrong with
    # the logic so perhaps it's a Qt bug. Processing the lists in
    # reverse order don't give better results fwiw.
    if expand_list:
        for item in expand_list:
            index = index_for_item(item)
            tree.setExpanded(index, True)
    if collapse_list:
        for item in collapse_list:
            index = index_for_item(item)
            tree.setExpanded(index, False)


def plural(n, singular, multiple):
    """Return singular if n is 1, otherwise multiple."""
    if n == 1:
        return singular
    else:
        return multiple
