# Software selection text spoke
#
# Copyright (C) 2013  Red Hat, Inc.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions of
# the GNU General Public License v.2, or (at your option) any later version.
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY expressed or implied, including the implied warranties 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 Street, Fifth Floor, Boston, MA
# 02110-1301, USA.  Any Red Hat trademarks that are incorporated in the
# source code or documentation are not subject to the GNU General Public
# License and may only be used or replicated with the express permission of
# Red Hat, Inc.
#
# Red Hat Author(s): Samantha N. Bueno <sbueno@redhat.com>
#

from pyanaconda.flags import flags
from pyanaconda.ui.tui.spokes import NormalTUISpoke
from pyanaconda.ui.tui.simpleline import TextWidget, ColumnWidget, CheckboxWidget
from pyanaconda.threads import threadMgr, AnacondaThread
from pyanaconda.packaging import MetadataError, DependencyError
from pyanaconda.i18n import _

from pyanaconda.constants import THREAD_PAYLOAD, THREAD_PAYLOAD_MD
from pyanaconda.constants import THREAD_CHECK_SOFTWARE, THREAD_SOFTWARE_WATCHER
from pyanaconda.constants_text import INPUT_PROCESSED

__all__ = ["SoftwareSpoke"]


class SoftwareSpoke(NormalTUISpoke):
    """ Spoke used to read new value of text to represent source repo. """
    title = _("Software selection")
    category = "software"

    def __init__(self, app, data, storage, payload, instclass):
        NormalTUISpoke.__init__(self, app, data, storage, payload, instclass)
        self._ready = False
        self.errors = []
        self._tx_id = None
        # default to first selection (Gnome) in list of environments
        self._selection = 0
        self.environment = None

        # for detecting later whether any changes have been made
        self._origEnv = None

        # are we taking values (package list) from a kickstart file?
        self._kickstarted = flags.automatedInstall and self.data.packages.seen

    def initialize(self):
        NormalTUISpoke.initialize(self)
        threadMgr.add(AnacondaThread(name=THREAD_SOFTWARE_WATCHER, target=self._initialize))

    def _initialize(self):
        """ Private initialize. """
        threadMgr.wait(THREAD_PAYLOAD)

        if self._kickstarted:
            threadMgr.wait(THREAD_PAYLOAD_MD)
        else:
            try:
                self.payload.environments
            except MetadataError:
                self.errors.append(_("No installation source available"))
                return
        self.payload.release()

        self._ready = True

    @property
    def status(self):
        """ Where we are in the process """
        if self.errors:
            return _("Error checking software selection")
        if not self.ready:
            return _("Processing...")
        if not self.payload.baseRepo:
            return _("Installation source not set up")
        if not self.txid_valid:
            return _("Source changed - please verify")

        ## FIXME:
        # quite ugly, but env isn't getting set to gnome (or anything) by
        # default, and it really should be so we can maintain consistency
        # with graphical behavior
        if self._selection >= 0 and not self.environment \
                and not self._kickstarted:
            self.apply()

        if not self.environment:
            # Ks installs with %packages will have an env selected, unless
            # they did an install without a desktop environment. This should
            # catch that one case.
            if self._kickstarted:
                return _("Custom software selected")
            return _("Nothing selected")

        return self.payload.environmentDescription(self.environment)[0]

    @property
    def completed(self):
        """ Make sure our threads are done running and vars are set. """
        processingDone = not threadMgr.get(THREAD_CHECK_SOFTWARE) and \
                         not self.errors and self.txid_valid

        if flags.automatedInstall:
            return processingDone and self.payload.baseRepo and self.data.packages.seen
        else:
            return self.payload.baseRepo and self.environment is not None and processingDone

    def refresh(self, args=None):
        """ Refresh screen. """
        NormalTUISpoke.refresh(self, args)

        if not self.payload.baseRepo:
            message = TextWidget(_("Installation source needs to be set up first."))
            self._window.append(message)

            # add some more space below
            self._window.append(TextWidget(""))
            return True

        threadMgr.wait(THREAD_CHECK_SOFTWARE)

        # put a title above the list and some space below it
        self._window.append(TextWidget(_("Base environment")))
        self._window.append(TextWidget(""))

        environments = self.payload.environments

        displayed = []
        for env in environments:
            name = self.payload.environmentDescription(env)[0]

            displayed.append(CheckboxWidget(title="%s" % name, completed=(environments.index(env) == self._selection)))
        print(_("Base environment"))

        def _prep(i, w):
            """ Do some format magic for display. """
            num = TextWidget("%2d)" % (i + 1))
            return ColumnWidget([(4, [num]), (None, [w])], 1)

        # split list of DE's into two columns
        mid = len(environments) / 2
        left = [_prep(i, w) for i, w in enumerate(displayed) if i <= mid]
        right = [_prep(i, w) for i, w in enumerate(displayed) if i > mid]

        cw = ColumnWidget([(38, left), (38, right)], 2)
        self._window.append(cw)

        return True

    def input(self, args, key):
        """ Handle the input; this chooses the desktop environment. """
        try:
            keyid = int(key) - 1
        except ValueError:
            if key.lower() == "c" and 0 <= self._selection < len(self.payload.environments):
                self.apply()
                self.close()
                return INPUT_PROCESSED
            else:
                return key

        if 0 <= keyid < len(self.payload.environments):
            self._selection = keyid
        return INPUT_PROCESSED

    @property
    def ready(self):
        """ If we're ready to move on. """
        return (not threadMgr.get(THREAD_SOFTWARE_WATCHER) and
                not threadMgr.get(THREAD_PAYLOAD_MD) and
                not threadMgr.get(THREAD_CHECK_SOFTWARE))

    def apply(self):
        """ Apply our selections """
        self._apply()

        # no longer using values from kickstart
        self._kickstarted = False
        self.data.packages.seen = True

        threadMgr.add(AnacondaThread(name=THREAD_CHECK_SOFTWARE,
                                     target=self.checkSoftwareSelection))

    def _apply(self):
        """ Private apply. """
        self.environment = self.payload.environments[self._selection]
        if not self.environment:
            return

        if not self._origEnv:
            # nothing selected before, select the environment
            self.payload.selectEnvironment(self.environment)
        elif self._origEnv != self.environment:
            # environment changed, clear the list of packages and select the new
            # one
            self.payload.data.packages.groupList = []
            self.payload.selectEnvironment(self.environment)
        else:
            # no change
            return

        self._origEnv = self.environment

    def checkSoftwareSelection(self):
        """ Depsolving """
        try:
            self.payload.checkSoftwareSelection()
        except DependencyError:
            self._tx_id = None
        else:
            self._tx_id = self.payload.txID

    @property
    def txid_valid(self):
        """ Whether we have a valid yum tx id. """
        return self._tx_id == self.payload.txID