# -*- coding: utf-8 -*-

# Copyright (c) 2015 - 2018 Detlev Offenbach <detlev@die-offenbachs.de>
#

"""
Module implementing a dialog to enter data for a Push operation.
"""

from __future__ import unicode_literals

from PyQt5.QtCore import pyqtSlot, Qt
from PyQt5.QtWidgets import QDialog, QTreeWidgetItem, QComboBox

from .Ui_GitPushDialog import Ui_GitPushDialog


class GitPushDialog(QDialog, Ui_GitPushDialog):
    """
    Class implementing a dialog to enter data for a Push operation.
    """
    PushColumn = 0
    LocalBranchColumn = 1
    RemoteBranchColumn = 2
    ForceColumn = 3
    
    def __init__(self, vcs, repodir, parent=None):
        """
        Constructor
        
        @param vcs reference to the git object
        @param repodir directory name of the local repository (string)
        @param parent reference to the parent widget (QWidget)
        """
        super(GitPushDialog, self).__init__(parent)
        self.setupUi(self)
        
        self.__vcs = vcs
        self.__repodir = repodir
        
        remoteUrlsList = self.__vcs.gitGetRemoteUrlsList(self.__repodir)
        self.__repos = {name: url for name, url in remoteUrlsList}
        
        remoteBranches = self.__vcs.gitGetBranchesList(self.__repodir,
                                                       remotes=True)
        self.__remotes = {}
        for remoteBranch in remoteBranches:
            repo, branch = remoteBranch.rsplit("/", 2)[-2:]
            if repo not in self.__remotes:
                self.__remotes[repo] = []
            self.__remotes[repo].append(branch)
        
        self.__localBranches = self.__vcs.gitGetBranchesList(self.__repodir,
                                                             withMaster=True)
        
        self.remotesComboBox.addItems(sorted(self.__repos.keys()))
        
        for localBranch in self.__localBranches:
            itm = QTreeWidgetItem(self.branchesTree, ["", localBranch, "", ""])
            combo = QComboBox()
            combo.setEditable(True)
            combo.setSizeAdjustPolicy(QComboBox.AdjustToContents)
            self.branchesTree.setItemWidget(
                itm, GitPushDialog.RemoteBranchColumn, combo)
        
        self.__resizeColumns()
        
        self.branchesTree.header().setSortIndicator(
            GitPushDialog.LocalBranchColumn, Qt.AscendingOrder)
        
        self.forceWarningLabel.setVisible(False)
        
        index = self.remotesComboBox.findText("origin")
        if index == -1:
            index = 0
        self.remotesComboBox.setCurrentIndex(index)
    
    def __resizeColumns(self):
        """
        Private slot to adjust the column sizes.
        """
        for col in range(self.branchesTree.columnCount()):
            self.branchesTree.resizeColumnToContents(col)
    
    @pyqtSlot(str)
    def on_remotesComboBox_currentTextChanged(self, txt):
        """
        Private slot to handle changes of the selected repository.
        
        @param txt current text of the combo box (string)
        """
        self.remoteEdit.setText(self.__repos[txt])
        
        for row in range(self.branchesTree.topLevelItemCount()):
            itm = self.branchesTree.topLevelItem(row)
            localBranch = itm.text(GitPushDialog.LocalBranchColumn)
            combo = self.branchesTree.itemWidget(
                itm, GitPushDialog.RemoteBranchColumn)
            combo.clear()
            combo.addItems([""] + sorted(self.__remotes[txt]))
            index = combo.findText(localBranch)
            if index != -1:
                combo.setCurrentIndex(index)
                itm.setCheckState(GitPushDialog.PushColumn, Qt.Checked)
            else:
                itm.setCheckState(GitPushDialog.PushColumn, Qt.Unchecked)
            itm.setCheckState(GitPushDialog.ForceColumn, Qt.Unchecked)
        
        self.__resizeColumns()
    
    @pyqtSlot(QTreeWidgetItem, int)
    def on_branchesTree_itemChanged(self, item, column):
        """
        Private slot handling changes of a branch item.
        
        @param item reference to the changed item (QTreeWidgetItem)
        @param column changed column (integer)
        """
        if column == GitPushDialog.PushColumn:
            # step 1: set the item's remote branch, if it is empty
            if item.checkState(GitPushDialog.PushColumn) == Qt.Checked and \
                (self.branchesTree.itemWidget(
                    item,
                    GitPushDialog.RemoteBranchColumn)
                    .currentText() == ""):
                self.branchesTree.itemWidget(
                    item, GitPushDialog.RemoteBranchColumn).setEditText(
                    item.text(GitPushDialog.LocalBranchColumn))
            
            # step 2: count checked items
            checkedItemsCount = 0
            for row in range(self.branchesTree.topLevelItemCount()):
                itm = self.branchesTree.topLevelItem(row)
                if itm.checkState(GitPushDialog.PushColumn) == Qt.Checked:
                    checkedItemsCount += 1
            if checkedItemsCount == len(self.__localBranches):
                self.selectAllCheckBox.setCheckState(Qt.Checked)
            elif checkedItemsCount == 0:
                self.selectAllCheckBox.setCheckState(Qt.Unchecked)
            else:
                self.selectAllCheckBox.setCheckState(Qt.PartiallyChecked)
        
        elif column == GitPushDialog.ForceColumn:
            forceItemsCount = 0
            for row in range(self.branchesTree.topLevelItemCount()):
                itm = self.branchesTree.topLevelItem(row)
                if itm.checkState(GitPushDialog.ForceColumn) == Qt.Checked:
                    forceItemsCount += 1
            self.forceWarningLabel.setVisible(forceItemsCount > 0)
    
    @pyqtSlot(int)
    def on_selectAllCheckBox_stateChanged(self, state):
        """
        Private slot to select/deselect all branch items.
        
        @param state check state of the check box (Qt.CheckState)
        """
        if state != Qt.PartiallyChecked:
            for row in range(self.branchesTree.topLevelItemCount()):
                itm = self.branchesTree.topLevelItem(row)
                if itm.checkState(GitPushDialog.PushColumn) != state:
                    itm.setCheckState(GitPushDialog.PushColumn, state)
    
    def getData(self):
        """
        Public method to get the entered data.
        
        @return remote name, list of branches to be pushed,
            a flag indicating to push tags as well, a flag indicating
            to set tracking information and the push method for submodules
        @rtype tuple of (str, list of str, bool, bool, str)
        """
        refspecs = []
        for row in range(self.branchesTree.topLevelItemCount()):
            itm = self.branchesTree.topLevelItem(row)
            force = itm.checkState(GitPushDialog.ForceColumn) == Qt.Checked
            if itm.checkState(GitPushDialog.PushColumn) == Qt.Checked:
                localBranch = itm.text(GitPushDialog.LocalBranchColumn)
                remoteBranch = self.branchesTree.itemWidget(
                    itm, GitPushDialog.RemoteBranchColumn).currentText()
                refspecs.append("{0}{1}:{2}".format(
                    "+" if force else "", localBranch, remoteBranch))
        
        # submodule stuff (--recurse-submodules=)
        if self.submodulesOnDemandButton.isChecked():
            submodulesPush = "on-demand"
        elif self.submodulesCheckButton.isChecked():
            submodulesPush = "check"
        elif self.submodulesOnlyButton.isChecked():
            submodulesPush = "only"
        else:
            submodulesPush = "no"
        
        return (
            self.remotesComboBox.currentText(),
            refspecs,
            self.tagsCheckBox.isChecked(),
            self.trackingCheckBox.isChecked(),
            submodulesPush,
        )
