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

# Copyright 2008-2012 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 os
from os import path
import re
import platform
from calculate.lib.datavars import Variable,ReadonlyVariable,SimpleDataVars
from calculate.lib.utils.portage import isPkgInstalled
from calculate.lib.utils.files import countFiles,readFile
import calculate.lib.cl_template as cl_template

class Linux:
    dictLinuxName = {"CLD":"Calculate Linux Desktop",
                     "CLDX":"Calculate Linux Desktop",
                     "CLDG":"Calculate Linux Desktop",
                     "CDS":"Calculate Directory Server",
                     "CLS":"Calculate Linux Scratch",
                     "CSS":"Calculate Scratch Server",
                     "CMC":"Calculate Media Center",
                     "Gentoo":"Gentoo"}

    dictLinuxSubName = {"CLD":"KDE", "CLDX":"XFCE", "CLDG":"GNOME"}

    dictNameSystem = {'CDS':'server',
                      'CLD':'desktop',
                      'CLDG':'desktop',
                      'CLDX':'desktop',
                      'CLS':'desktop',
                      'CMC':'desktop',
                      'CSS':'server'}

    def getFullNameByShort(self,shortname):
        """Get full distributive name by short name"""
        subname = self.dictLinuxSubName.get(shortname,'')
        if subname: subname = " %s"%subname
        return "%s%s"%(self.dictLinuxName.get(shortname,''),subname)

    def getShortnameByMakeprofile(self,systemroot):
        """Get shortname by symlink of make.profile"""
        makeprofile = path.join(systemroot,'etc/make.profile')
        if path.exists(makeprofile):
            link = os.readlink(makeprofile)
            reMakeProfileLink = re.compile('/calculate/(desktop|server)/(%s)/'%
                        "|".join(self.dictLinuxName.keys()),re.S)
            shortnameSearch = reMakeProfileLink.search(link)
            if shortnameSearch:
                return shortnameSearch.groups()[1]
        return None

    def getShortnameByIni(self,systemroot):
        """Get shortname by calculate.ini file"""
        inifile = path.join(systemroot,'etc/calculate/calculate.ini')
        if path.exists(inifile):
            FD = open(inifile)
            data = FD.readlines()
            FD.close()
            shortNameList = filter(lambda y:y,
                                   map(lambda x:\
                                       len(x.split("="))==2 and\
                                       x.split("=")[0]=="calculate" and\
                                       x.split("=")[1].strip(), data))
            if shortNameList:
                return shortNameList[0]

    def detectOtherShortname(self,systemroot):
        """Detect other system. Now only Gentoo."""
        gentooFile = path.join(systemroot,"etc/gentoo-release")
        if path.exists(gentooFile):
            return "Gentoo"
        if all(map(lambda x:path.lexists(path.join(systemroot,x)),
            ['bin','var','lib','etc'])):
            return "Linux"
        return None

    def getVersionFromOverlay(self,systemroot):
        """
        Get version from overlay calculate-release
        """
        overlayPath = 'var/lib/layman/calculate'
        releaseFile = 'profiles/calculate-release'
        return readFile(path.join(systemroot,overlayPath,releaseFile))

    def getVersionFromMetapackage(self,systemroot,shortname):
        """Get version from meta package"""
        for pkg in ("app-misc/calculate-meta","app-misc/%s-meta"%shortname):
            calcMeta = isPkgInstalled(pkg,systemroot)
            if calcMeta:
                return calcMeta[0]['PV']
        return None

    def getVersionFromCalculateIni(self,systemroot):
        """Get version from calculate ini"""
        pathname = path.join(systemroot,
                      'etc/calculate/calculate.ini')
        if path.exists(pathname):
            FD = open(pathname)
            data = FD.readlines()
            FD.close()
            verList = filter(lambda y:y,
                                   map(lambda x:\
                                       len(x.split("="))==2 and\
                                       x.split("=")[0]=="linuxver" and\
                                       x.split("=")[1].strip(), data))
            if verList:
                reVer=re.compile("^(\d+\.)*\d$",re.S)
                reRes = filter(reVer.search,verList)
                if reRes:
                    return reRes[0]

    def getVersionFromGentooFiles(self,systemroot):
        """Get version from gentoo files"""
        gentooFile = path.join(systemroot,"etc/gentoo-release")
        systemVersion = ""
        flagGentoo = False
        reVer=re.compile("^(\d+\.)*\d+$",re.S)
        if path.exists(gentooFile):
            gentooLink = path.join(systemroot,"etc/make.profile")
            if path.islink(gentooLink):
                vers = filter(reVer.search,
                              os.readlink(gentooLink).split('/'))
                if vers:
                    return vers[-1]

    def getVersionFromUname(self):
        """Get version from uname"""
        reVer=re.search("^(\d+\.)*\d",platform.release(),re.S)
        if reVer:
            return reVer.group()

class VariableOsLinuxShortname(Variable,Linux):
    """
    Short system name (Example:CLD)
    """
    systemRoot = "/"

    def get(self):
        return self.getShortnameByMakeprofile(self.systemRoot) or \
               self.getShortnameByIni(self.systemRoot) or \
               self.detectOtherShortname(self.systemRoot) or \
               "Linux"

class VariableOsLinuxName(Variable,Linux):
    """
    Full system name
    """
    source_variable = "os_linux_shortname"

    def get(self):
        linuxShortName = self.Get(self.source_variable)
        return self.dictLinuxName.get(linuxShortName,"Linux")

class VariableOsLinuxSubname(Variable,Linux):
    """
    Subname of linux (KDE, GNOME, XFCE and etc)
    """
    source_variable = "os_linux_shortname"
    
    def get(self):
        linuxShortName = self.Get(self.source_variable)
        return self.dictLinuxSubName.get(linuxShortName,"")

class VariableOsLinuxSystem(Variable,Linux):
    """
    System of linux (desktop or server)
    """
    source_variable = "os_linux_shortname"

    def get(self):
        shortName = self.Get(self.source_variable)
        return self.dictNameSystem.get(shortName,"")

class VariableOsLinuxVer(Variable,Linux):
    """
    Version of system (get by metapackage,calculate.ini,gentoo files or 0)
    """
    systemRoot = "/"

    def get(self):
        """Get system version"""
        linuxShortName = self.Get("os_linux_shortname")
        return self.getVersionFromOverlay(self.systemRoot) or \
            self.getVersionFromMetapackage(self.systemRoot,
                                              linuxShortName) or \
            self.getVersionFromCalculateIni(self.systemRoot) or \
            self.getVersionFromGentooFiles(self.systemRoot) or \
            self.getVersionFromUname() or "0"

class VariableOsLinuxBuild(Variable,Linux):
    """
    Build of system
    """

class VariableOsLinuxFilesnum(Variable,Linux):
    systemRoot = "/"

    def get(self):
        """Depricated variable which contains count files.
        Get files count. Count files discard because it to long
        operation. This value is already count by calculate-builder and
        is placed in calculate3.env"""
        return str(0)
        #return str(countFiles(self.systemRoot))

class VariableOsLinuxFiles(Variable,Linux):
    systemRoot = "/"

    def get(self):
        """Get files count. Count files discard because it to long
        operation. This value is already count by calculate-builder and
        is placed in calculate3.env"""
        return self.Get('os_linux_filesnum')
        #return str(countFiles(self.systemRoot))


class LinuxDataVars(SimpleDataVars):
    def __init__(self,systemRoot="/"):
        self.systemRoot = systemRoot
        SimpleDataVars.__init__(self,
            VariableOsLinuxShortname(systemRoot=systemRoot),
            VariableOsLinuxName(systemRoot=systemRoot),
            VariableOsLinuxSubname(systemRoot=systemRoot),
            VariableOsLinuxFilesnum(systemRoot=systemRoot),
            VariableOsLinuxFiles(systemRoot=systemRoot),
            VariableOsLinuxSystem(systemRoot=systemRoot),
            VariableOsLinuxVer(systemRoot=systemRoot),
            VariableOsLinuxBuild(systemRoot=systemRoot))
        makeprofile = path.join(systemRoot,'etc/make.profile')
        if os.path.exists(makeprofile):
            inifile = path.join(systemRoot,'etc',
                os.readlink(path.join(systemRoot,'etc/make.profile')))
            self.flIniFileFrom(inifile)
        inifile = "etc/calculate/calculate.env"
        self.flIniFileFrom(path.join(systemRoot,inifile))
        iniFile = "etc/calculate/calculate3.env"
        self.flIniFileFrom(path.join(systemRoot,iniFile))
        iniFile = "etc/calculate/calculate2.env"
        self.flIniFileFrom(path.join(systemRoot,iniFile))
