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

# Copyright 2011-2016 Mir Calculate. http://www.calculate-linux.org
#
#  Licensed under the Apache License, Version 2.0 (the "License");
#  you may not use this file except in compliance with the License.
#  You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0 #
#  Unless required by applicable law or agreed to in writing, software
#  distributed under the License is distributed on an "AS IS" BASIS,
#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#  See the License for the specific language governing permissions and
#  limitations under the License.

from calculate.lib.datavars import Variable, VariableError
import sys
import os
from os import path

from calculate.lib.cl_lang import setLocalTranslate
import pwd

_ = lambda x: x
setLocalTranslate('cl_core3', sys.modules[__name__])

from calculate.lib.utils.files import listDirectory
from calculate.lib.utils.portage import (isPkgInstalled, getPkgSlot,
    getInstalledAtom)
from calculate.lib.utils.text import formatListOr
from calculate.lib.utils.common import getTupleVersion
from calculate.lib.variables.user import VariableUrLogin
from itertools import *
import glob


class VariableClCorePkgName(Variable):
    """
    Package name
    """
    type = "choiceedit"
    opt = ["--pkg-name"]
    metavalue = "PN"
    untrusted = True

    def init(self):
        self.label = _("Package name")
        self.help = _("package name")

    def check(self, value):
        if not value:
            raise VariableError(_("Please choose a package"))
        if not os.environ.get(
                "EBUILD_PHASE", "") and value not in self.choice():
            raise VariableError(_("Package not found"))

    def choice(self):
        if self.Get('cl_ebuild_phase'):
            return [""]
        return [""] + ["all"] + sorted(
            set(chain(*map(lambda x: map(
                lambda y: (y[0].rpartition('-')[0]
                           if y[2].startswith('r') else y[0]),
                imap(lambda y: y.rpartition('-'),
                     listDirectory(x))),
                           listDirectory('/var/db/pkg', onlyDir=True,
                                         fullPath=True)))))


class VariableClCorePkgVersionOpt(Variable):
    """
    Package version
    """
    type = "choiceedit"
    opt = ["--pkg-version"]
    metavalue = "PVR"
    untrusted = True

    def init(self):
        self.label = _("Package version")
        self.help = _("package version number with the revision")

    def get(self):
        return "all"

    def choice(self):
        pkg = getInstalledAtom("%s/%s" % (self.Get('cl_core_pkg_category'),
                                        self.Get('cl_core_pkg_name')))
        pkg = list(sorted(pkg))
        if pkg:
            return ["all"] + [x['PVR'] for x in pkg]
        return ["all"]

    def check(self, value):
        pkg_name = self.Get('cl_core_pkg_name')
        if not value and pkg_name and pkg_name != "all":
            raise VariableError(_("Please choose the version"))
        if value != "all":
            pkg_name = self.Get('cl_core_pkg_name')
            if not value and pkg_name and pkg_name != "all":
                raise VariableError(_("Please choose the version"))

            if self.Get('cl_action') != "patch":
                pkgs = getInstalledAtom("%s/%s" % (self.Get('cl_core_pkg_category'),
                                                self.Get('cl_core_pkg_name')))
                pkgs = list(sorted(pkgs))
                if pkgs:
                    versions = [x['PVR'] for x in pkgs]
                else:
                    versions = []
                if value not in versions and pkg_name and pkg_name != "all":
                    raise VariableError(_("Please choose the version") + _(": ") +
                        formatListOr(versions))


class VariableClCorePkgVersion(Variable):
    """
    Package version
    """
    type = "choiceedit"
    opt = ["--pkg-version"]
    metavalue = "PVR"
    untrusted = True

    def init(self):
        self.label = _("Package version")
        self.help = _("package version number with the revision")

    def get(self):
        vers = self.Get('cl_core_pkg_version_opt')
        if vers != "all":
            return vers
        pkg = isPkgInstalled("%s/%s" % (self.Get('cl_core_pkg_category'),
                                        self.Get('cl_core_pkg_name')))
        if pkg:
            return sorted(pkg,
                          key=lambda x: getTupleVersion(x['PVR']))[-1]['PVR']
        return ""

    def check(self, value):
        pkg_name = self.Get('cl_core_pkg_name')
        if not value and pkg_name and pkg_name != "all":
            raise VariableError(_("Please choose the version"))


class VariableClCorePkgSlot(Variable):
    """
    Package Slot
    """
    type = "choiceedit"
    opt = ["--pkg-slot"]
    metavalue = "SLOT"
    untrusted = True

    def init(self):
        self.label = _("Package slot")
        self.help = _("package slot")

    def get(self):
        slot = self.Get('cl_core_pkg_slot_opt')
        if slot != "all":
            return slot
        pkg = getPkgSlot("%s/%s" % (self.Get('cl_core_pkg_category'),
                                    self.Get('cl_core_pkg_name')))
        if pkg:
            return sorted(pkg)[-1]
        return ""

    def check(self, value):
        pkg_name = self.Get('cl_core_pkg_name')
        if not value and pkg_name and pkg_name != "all":
            raise VariableError(_("Please choose the slot"))

class VariableClCorePkgSlotOpt(Variable):
    """
    Selected Package Slot
    """
    type = "choiceedit"
    opt = ["--pkg-slot"]
    metavalue = "SLOT"
    untrusted = True

    def init(self):
        self.label = _("Package slot")
        self.help = _("package slot")

    def get(self):
        veropt = self.Get('cl_core_pkg_version_opt')
        if veropt != 'all':
            pkgs = getInstalledAtom(
                "=%s/%s-%s" % (self.Get('cl_core_pkg_category'),
                self.Get('cl_core_pkg_name'), veropt))
            pkgs = list(pkgs)
            if pkgs:
                return pkgs[0]["SLOTONLY"]
        elif self.Get('cl_action') == 'config':
            pkgs = getInstalledAtom(
                "%s/%s" % (self.Get('cl_core_pkg_category'),
                self.Get('cl_core_pkg_name')))
            pkgs = list(pkgs)
            if len(pkgs) == 1:
                return pkgs[0]["SLOTONLY"]
            return ""
        return "all"

    def choice(self):
        veropt = self.Get('cl_core_pkg_version_opt')
        if veropt != "all":
            pkg = getInstalledAtom("=%s/%s-%s" % (self.Get('cl_core_pkg_category'),
                                            self.Get('cl_core_pkg_name'),
                                            veropt))
        else:
            pkg = getInstalledAtom("%s/%s" % (self.Get('cl_core_pkg_category'),
                                            self.Get('cl_core_pkg_name')))
        pkg = list(sorted(pkg))
        if self.Get('cl_action') == 'config':
            allvalue = []
        else:
            allvalue = ["all"]
        if pkg:
            return allvalue + [x['SLOTONLY'] for x in pkg]
        return allvalue


    def check(self, value):
        if self.Get('cl_action') == 'config' and value == "all":
            raise VariableError(_("Please choose the slot"))
        if value != "all":
            pkg_name = self.Get('cl_core_pkg_name')
            if not value and pkg_name and pkg_name != "all":
                raise VariableError(_("Please choose the slot"))
            veropt = self.Get('cl_core_pkg_version_opt')
            if veropt == 'all':
                pkgs = getInstalledAtom(
                    "=%s/%s" % (self.Get('cl_core_pkg_category'),
                                   self.Get('cl_core_pkg_name')))
                slots = [x["SLOTONLY"] for x in sorted(pkgs)]
            else:
                pkgs = getInstalledAtom(
                    "=%s/%s-%s" % (self.Get('cl_core_pkg_category'),
                                   self.Get('cl_core_pkg_name'), veropt))
                slots = [x["SLOTONLY"] for x in sorted(pkgs)]
            if self.Get('cl_action') != "patch" and \
                value not in slots and pkg_name and pkg_name != "all":
                raise VariableError(_("Please choose the slot") + _(": ") +
                    formatListOr(slots))


class VariableClCorePkgCategory(Variable):
    """
    Package category
    """
    type = "choiceedit"
    opt = ["--pkg-category"]
    metavalue = "CATEGORY"
    untrusted = True
    pkgCategories = {}

    def init(self):
        self.label = _("Package category")
        self.help = _("package category name")

    def choice(self):
        if self.Get('cl_ebuild_phase'):
            return []
        pkgname = self.Get('cl_core_pkg_name')
        if pkgname not in self.pkgCategories:
            self.pkgCategories[pkgname] = \
                glob.glob('/usr/portage/*/%s' % pkgname)
        return map(lambda x: path.split(path.split(x)[0])[1],
                   self.pkgCategories[pkgname])

    def get(self):
        category = isPkgInstalled(self.Get('cl_core_pkg_name'))
        if category:
            if type(category[0]) == dict:
                category = ""
            else:
                category = category[0].rpartition('/')[2]
        else:
            choice = self.choice()
            if len(choice) == 1:
                return choice[0]
            else:
                category = ""
        return category

    def check(self, value):
        pkg_name = self.Get('cl_core_pkg_name')
        if not value and pkg_name and pkg_name != "all":
            raise VariableError(_("Please choose the category"))


class VariableClCorePkgPath(Variable):
    """
    Package configure path
    """

    value = "/"
    opt = ["--pkg-path"]
    metavalue = "PATH"

    def init(self):
        self.label = _("Path for configuration")
        self.help = _("root path for saving the updated configuration files")

    def check(self, value):
        if not path.isdir(value):
            raise VariableError(_("Directory %s not found") % value)


class VariableClCorePkgSystemSet(Variable):
    """
    Package configure system
    """

    type = "bool"
    value = "on"
    opt = ["--system"]
    metavalue = "ON/OFF"

    def init(self):
        self.label = _("Configure the system")
        self.help = _("updating system configuration files")


class VariableClCorePkgDesktopSet(Variable):
    """
    Package configure desktop
    """

    type = "bool"
    opt = ["--desktop"]
    metavalue = "ON/OFF"

    def get(self):
        if self.Get('cl_templates_locate') == ["clt"]:
            return "off"
        return "on"

    def check(self, value):
        if self.Get('cl_templates_locate') == ["clt"] and value == "on":
            raise VariableError(
                _("You must not choose only clt location "
                  "for desktop templates"))

    def init(self):
        self.label = _("Configure users")
        self.help = _("updating desktop (user) configuration files")


class VariableClCorePkgRootSet(Variable):
    """
    Other packages (specified by merge=) will configured in /
    """
    type = "bool"
    value = "on"
    metavalue = "ON/OFF"

    opt = ["--depend-in-root"]

    def init(self):
        self.label = _("Configure dependent packages in root")
        self.help = _("configure the dependent packages in the same "
                      "directory as the specified package, instead of root")


class VariableUrCoreLogin(VariableUrLogin):
    """
    User Login
    """
    opt = ["--login"]
    alias = "ur_login"

    def check(self, value):
        """Пользователь существует"""
        try:
            pwd.getpwnam(value).pw_gid
        except Exception:
            raise VariableError(_("User %s does not exist") % value)

    def get(self):
        return self.Get('ur_login')


class VariableClCoreArchMachine(Variable):
    """
    Архитектура для настройки пакета
    """
    type = 'choice'
    opt = ['--march']
    metavalue = "ARCH"
    available_arch = ["i686", "x86_64"]

    def init(self):
        self.label = _("Machine architecture")
        self.help = _("set machine architecture")

    def get(self):
        return self.Get('os_arch_machine')

    def choice(self):
        return [(x, x) for x in self.available_arch]
