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

# Copyright 2015 Calculate Ltd. 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.

import sys
import os
from os import path
import re
from calculate.install import distr
from calculate.install.distr import DistributiveError
from calculate.lib.datavars import ReadonlyVariable, SimpleDataVars, \
    VariableError, ReadonlyTableVariable, FieldValue
from calculate.lib.utils.files import pathJoin
from calculate.lib.utils.portage import Layman
from calculate.lib.utils.tools import ignore
from calculate.lib.variables import linux
from calculate.lib.variables import env
from calculate.update.variables import update
from calculate.lib.variables import system, linux
from .action import Actions

from calculate.lib.cl_lang import setLocalTranslate
import datetime
import profiles

setLocalTranslate('cl_builder3', sys.modules[__name__])


class BuilderLinux(ReadonlyVariable):
    # variable for get current system info (example: os_linux_shortname)
    variable = ""

    def get(self):
        try:
            dv = self.Get('cl_builder_linux_datavars')
        except VariableError:
            return ""
        if dv:
            return dv[self.variable]
        else:
            return ""

class DataVarsBuilderLinux(linux.LinuxDataVars):
    """
    Упрощенная модель переменных для собираемого образа
    """
    def variables(self):
        l = super(DataVarsBuilderLinux, self).variables()
        return l + [linux.VariableClProfileSystem(),
                    env.VariableClRepositoryData(),
                    env.VariableClRepositoryName(),
                    env.VariableClRepositoryLocation(),
                    env.VariableClTemplateLocation(),
                    env.VariableClTemplatePath(),
                    env.VariableClPkgdir(),
                    env.VariableClDistdir(),
                    env.VariableClEmergeConfig(systemRoot=self.systemRoot),
                    env.VariableClFeatures(),
                    env.VariableClEnvLocation(),
                    env.VariableClEnvData(),
                    env.VariableClEnvPath(),
                    update.VariableClUpdateRepData(section="update"),
                    update.VariableClUpdateRepPath(section="update"),
                    update.VariableClUpdateRepName(section="update"),
                    update.VariableClUpdateRepUrl(section="update"),
                    update.VariableClUpdateRep(section="update"),
                    update.VariableClUpdateRepRev(section="update"),
                    update.VariableClUpdateBranch(section="update"),
                    update.VariableClUpdateBranchName(section="update"),
                    update.VariableClUpdateLaymanConfig(section="update"),
                    update.VariableClUpdateLaymanStorage(section="update"),
                    update.VariableClProfileRepository(section="update"),
                    update.VariableClUpdateBinhost(section="update"),
                    update.VariableClUpdateBinhostData(section="update"),
                    update.VariableClUpdateBinhostHost(section="update"),
                    update.VariableClUpdateBinhostRecheckSet(section="update"),
                    update.VariableClUpdateBinhostRevisions(section="update"),
                    update.VariableClUpdateBinhostTime(section="update"),
                    update.VariableClUpdateBinhostTimeout(section="update"),
                    update.VariableClUpdateBinhostList(section="update"),
                    update.VariableClUpdateBinhostTimestampPath(section="update"),
                    update.VariableClUpdateBinhostRevisionPath(section="update"),
                    system.VariableOsArchMachineGentoo()]

    @classmethod
    def StageInformation(cls, fn):
        re_stage = re.compile("stage(\d)-(amd64|x86)-(\d{8}).tar.\w+")
        m = re_stage.search(fn)
        if m:
            map_arch = {'amd64': 'x86_64', 'x86': 'i686'}
            c = {'os_linux_build': m.group(3),
                 'os_arch_machine':map_arch[m.group(2)],
                 'os_linux_shortname': 'Gentoo',
                 'os_linux_subname': "Stage%s"%m.group(1),
                 'cl_profile_name': 'Gentoo profile',
                 'os_linux_name': 'Gentoo'}
        else:
            c = {}
        obj = cls(cache=c)
        for vn in obj.allVars.keys():
            if vn not in obj.cache:
                obj.cache[vn] = ''
        return obj

    def flCalculateEnv(self, systemRoot):
        for inifile in self.Get('cl_env_path'):
            self.flIniFileFrom(pathJoin(systemRoot, inifile),
                               system_root=systemRoot)

    def __repr__(self):
        return "Builder variables"

class VariableClBuilderBinarySet(ReadonlyVariable):
    """
    Собираемый дистрибутив - бинарный FEATURES="getbinpkg"
    """
    def get(self):
        dv = self.Get('cl_builder_linux_datavars')
        if dv:
            if "getbinpkg" in dv.Get('cl_features'):
                return "on"
        return "off"

class VariableClBuilderLinuxDatavars(ReadonlyVariable):
    """
    Переменные дистрибутива
    """
    def source_data(self):
        image = self.Get('cl_builder_source')
        image_fn = self.Get('cl_builder_source_filename')
        return self.get_data(image, image_fn=image_fn)

    def get_data(self, image, image_fn=None):
        if image:
            if isinstance(image, distr.ArchiveDistributive):
                return DataVarsBuilderLinux.StageInformation(image_fn)
            with image:
                with ignore(DistributiveError):
                    distr_dn = image.getDirectory()
                    dvbl = DataVarsBuilderLinux(systemRoot=distr_dn)
                    dvbl['cl_update_binhost_recheck_set'] = \
                        self.Get('update.cl_update_binhost_recheck_set')
                    dvbl.prepare_all()
                    return dvbl
        else:
            return ""

    def target_data(self):
        image = self.Get('cl_builder_target')
        return self.get_data(image, image_fn=None)

    def get(self):
        """Get by distroinfo or current info"""
        if self.Get('cl_action') in Actions.NewAssemble:
            return self.source_data()
        elif self.Get('cl_action') in Actions.WorkAssemble:
            return self.target_data()
        return ""


class VariableOsBuilderLinuxShortname(BuilderLinux):
    """Shortname of system"""
    variable = "os_linux_shortname"

    def init(self):
        self.label = _("Building short name")


class VariableOsBuilderLinuxVer(BuilderLinux):
    """Shortname of system"""
    variable = "os_linux_ver"

    def init(self):
        self.label = _("Building system version")

class VariableOsBuilderLinuxBuild(BuilderLinux):
    """Shortname of system"""
    variable = "os_linux_build"

    def init(self):
        self.label = _("Build version")

    def get(self):
        action = self.Get('cl_action')
        if action == Actions.Image:
            curdate = datetime.datetime.now()
            return "%04d%02d%02d" % (curdate.year, curdate.month, curdate.day)
        else:
            return BuilderLinux.get(self)


class VariableOsBuilderArchMachine(BuilderLinux):
    """Shortname of system"""
    variable = "os_arch_machine"


class VariableOsBuilderLinuxFiles(BuilderLinux):
    """Shortname of system"""
    variable = "os_linux_files"


class VariableOsBuilderLinuxName(BuilderLinux):
    """
    Install distro name
    """
    variable = "os_linux_name"

    def init(self):
        self.label = _("System name")


class VariableClBuilderProfileSystem(BuilderLinux):
    variable = "cl_profile_system"

    #def get(self):
    #    action = self.Get('cl_action')
    #    if action == 'create':
    #        shortname = self.Get('cl_builder_profile_system_shortname')
    #        profile = self.Select('cl_builder_profile_path',
    #                              where="cl_builder_profile_shortname",
    #                              eq=shortname, limit=1)
    #        if profile:
    #            return profile
    #    return ""


class VariableOsBuilderLinuxSystem(BuilderLinux):
    """
    Install system name
    """
    def init(self):
        self.label = _("System type")

    variable = "os_linux_system"

class VariableOsBuilderLinuxFullname(ReadonlyVariable):
    """
    Полное название системы
    """
    fullname_format = "{name} {ver}{subname} {arch} {build}"

    def init(self):
        self.label = _("System")

    def get(self):
        name = self.Get('os_builder_linux_name')
        subname = self.Get('os_builder_linux_subname')
        if subname:
            subname = " %s" % subname
        ver = self.Get('os_builder_linux_ver')
        build = self.Get('os_builder_linux_build')
        arch = self.Get('os_builder_arch_machine')
        return self.fullname_format.format(
            name=name, ver=ver, subname=subname, arch=arch, build=build)

class VariableOsBuilderLinuxSubname(BuilderLinux):
    """
    Install subname
    """
    variable = "os_linux_subname"

    def init(self):
        self.label = _("Subname")

    def humanReadable(self):
        return self.Get() or _("no")

class VariableClBuilderPortdirOverlay(ReadonlyVariable):
    """
    Пути оверлеев в собираемом образе относительно точки монтирования
    """
    def get(self):
        return [location
                for name, location in
                    filter(None,self.Get('builder.cl_builder_repository_data'))
                if name not in ("portage", "gentoo")]

class VariableClBuilderOtherRepData(update.VariableClUpdateOtherRepData):
    """
    Информация о прочих репозиториях
    """
    source = ['builder.cl_builder_other_rep_name',
              'builder.cl_builder_other_rep_path']

    portdir_overlay = "builder.cl_builder_portdir_overlay"

class VariableClBuilderOtherRepName(FieldValue,ReadonlyVariable):
    """
    Список имен прочих репозиториев
    """
    type = "list"
    source_variable = "builder.cl_builder_other_rep_data"
    column = 0

class VariableClBuilderOtherRepPath(FieldValue,ReadonlyVariable):
    """
    Список путей до прочих репозиториев
    """
    type = "list"
    source_variable = "builder.cl_builder_other_rep_data"
    column = 1


class VariableClBuilderRepositoryData(ReadonlyTableVariable):
    """
    """
    source = ["cl_repository_name", "cl_repository_location"]

    def get(self):
        try:
            dv = self.Get('cl_builder_linux_datavars')
            if dv:
                return dv.Get('cl_repository_data')
        except VariableError:
            pass
        return [[]]

class VariableClBuilderRepositoryName(FieldValue,ReadonlyVariable):
    """
    """
    type = "list"
    source_variable = "cl_builder_repository_data"
    column = 0

class VariableClBuilderRepositoryLocation(FieldValue,ReadonlyVariable):
    """
    """
    type = "list"
    source_variable = "cl_builder_repository_data"
    column = 1

class VariableClBuilderSyncOverlayRep(ReadonlyVariable):
    """
    Обновляемые репозитории (исключая portage)
    """
    type = "list"

    def get(self):
        action = self.Get('cl_action')
        if action in Actions.ChangeProfile:
            dv = self.Get('cl_builder_profile_datavars')
        else:
            dv = self.Get('cl_builder_linux_datavars')
        if dv:
            return filter(lambda x: x not in ("portage", "gentoo"),
                          dv.Get('cl_repository_name'))
        else:
            return []

class VariableClBuilderLinuxDistdir(ReadonlyVariable):
    """
    Полный путь до DISTDIR собираемой системы относительно текущего корня
    """
    def get(self):
        fallback_distdir = '/var/calculate/remote/distfiles'
        dv = self.Get('cl_builder_linux_datavars')
        builder_path = self.Get('cl_builder_path')
        if dv:
            return pathJoin(builder_path, dv.Get('cl_distdir'))
        return pathJoin(builder_path, fallback_distdir)

class VariableClBuilderLinuxPkgdir(ReadonlyVariable):
    """
    Полный путь до PKGDIR собираемой системы относительно текущего корня
    """
    def get(self):
        fallback_pkgdir = '/var/calculate/remote/packages'
        dv = self.Get('cl_builder_linux_datavars')
        builder_path = self.Get('cl_builder_path')
        if dv:
            return pathJoin(builder_path, dv.Get('cl_pkgdir'))
        return pathJoin(builder_path, fallback_pkgdir)
