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

# Copyright 2008-2010 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
import sys
from cl_utils import getpathenv, runOsCommand, typeFile
import re
from os import path, R_OK
try:
    from cl_ldap import ldapUser
except ImportError:
    ldapUser = None
from operator import itemgetter

class clLocale:
    lang = {
    #Belarussian
    'be_BY' : {
                'locale':'be_BY.UTF-8',
                'keymap':'by',
                'dumpkeys_charset': 'koi8-u',
                'consolefont':'Cyr_a8x16',
                'xkblayout':'us,by',
                'language':'be',
        },
    #Bulgarian
    'bg_BG' : {
                'locale':'bg_BG.UTF-8',
                'keymap':'bg_bds-utf8',
                'dumpkeys_charset': '',
                'consolefont':'ter-m14n',
                'xkblayout':'us,bg',
                'language':'bg',
        },
    #Belgian
    'fr_BE' : {
                'locale':'fr_BE.UTF-8',
                'keymap':'be-latin1',
                'dumpkeys_charset':'',
                'consolefont':'lat9w-16',
                'xkblayout':'us,be',
                'language':'fr',
        },
    #Brazilian Portuguese
    'pt_BR' : {
                'locale':'pt_BR.UTF-8',
                'keymap':'br-abnt2',
                'dumpkeys_charset':'',
                'consolefont':'lat9w-16',
                'xkblayout':'pt,us',
                'language':'pt',
        },
    #Canadian French
    'fr_CA' : {
                'locale':'fr_CA.UTF-8',
                'keymap':'cf',
                'dumpkeys_charset':'',
                'consolefont':'default8x16',
                'xkblayout':'us,ca_enhanced',
                'language':'fr',
        },
    #Danish
    'da_DK' : {
                'locale':'da_DK.UTF-8',
                'keymap':'dk-latin1',
                'dumpkeys_charset':'',
                'consolefont':'lat0-16',
                'xkblayout':'us,dk',
                'language':'da',
        },
    #French
    'fr_FR' : {
                'locale':'fr_FR.UTF-8',
                'keymap':'fr-latin9',
                'dumpkeys_charset':'',
                'consolefont':'lat0-16',
                'xkblayout':'fr,us',
                'language':'fr',
        },
    #German
    'de_DE' : {
                'locale':'de_DE.UTF-8',
                'keymap':'de-latin1',
                'dumpkeys_charset':'',
                'consolefont':'lat9w-16',
                'xkblayout':'de,us',
                'language':'de',
        },
    #Icelandic
    'is_IS' : {
                'locale':'is_IS.UTF-8',
                'keymap':'is-latin1',
                'dumpkeys_charset':'',
                'consolefont':'cp850-8x16',
                'xkblayout':'us,is',
                'language':'is',
        },
    #Italian
     'it_IT' : {
                'locale':'it_IT.UTF-8',
                'keymap':'it',
                'dumpkeys_charset':'',
                'consolefont':'default8x16',
                'xkblayout':'us,it',
                'language':'it',
        },
    #Norwegian
    'nn_NO' : {
                'locale':'nn_NO.UTF-8',
                'keymap':'no-latin1',
                'dumpkeys_charset':'',
                'consolefont':'lat9w-16',
                'xkblayout':'us,no',
                'language':'nn',
        },
    #Polish
    'pl_PL' : {
                'locale':'pl_PL.UTF-8',
                'keymap':'pl',
                'dumpkeys_charset':'',
                'consolefont':'lat2-16',
                'xkblayout':'us,pl',
                'language':'pl',
        },
    #Russian
    'ru_RU' : {
                'locale':'ru_RU.UTF-8',
                'keymap':'-u ruwin_cplk-UTF-8',
                'dumpkeys_charset':'',
                'consolefont':'ter-k14n',
                'xkblayout':'us,ru(winkeys)',
                'language':'ru',
        },
    #Spanish
    'es_ES' : {
                'locale':'es_ES.UTF-8',
                'keymap':'es euro2',
                'dumpkeys_charset':'',
                'consolefont':'lat0-16',
                'xkblayout':'es,us',
                'language':'es',
        },
    #Swedish
    'sv_SE' : {
                'locale':'sv_SE.UTF-8',
                'keymap':'sv-latin1',
                'dumpkeys_charset':'',
                'consolefont':'lat0-16',
                'xkblayout':'us,se',
                'language':'sv',
        },
    #Ukrainian
    'uk_UA' : {
                'locale':'uk_UA.UTF-8',
                'keymap':'ua-utf',
                'dumpkeys_charset':'koi8-u',
                'consolefont':'ter-v14n',
                'xkblayout':'us,ua(winkeys)',
                'language':'uk',
        },
    #United Kingdom/British
    'en_GB' : {
                'locale':'en_GB.UTF-8',
                'keymap':'uk',
                'dumpkeys_charset':'',
                'consolefont':'LatArCyrHeb-16',
                'xkblayout':'us,gb',
                'language':'en',
        },
    #United State/English
    'en_US' : {
                'locale':'en_US.UTF-8',
                'keymap':'us',
                'dumpkeys_charset':'',
                'consolefont':'LatArCyrHeb-16',
                'xkblayout':'us',
                'language':'en',
        }
    }

    def getLangs(self):
        return self.lang.keys()

    def getLanguages(self):
        return map(lambda x:self.lang[x]['language'],
                   self.lang.keys())

    def isLangExists(self,lang):
        return lang in self.lang.keys()

    def isValueInFieldExists(self,field,value):
        return value in map(lambda x:self.lang[x][field],self.lang.keys())

    def getFields(self,field):
        return [ l[1][field] for l in self.lang.items() ]

    def getFieldByLang(self,field,lang):
        return self.lang.get(lang, self.lang['en_US'])[field]

    def getFieldByKeymap(self,field,keymap):
        return self.lang.get(self.getLangByField('keymap',keymap),
                                self.lang['en_US'])[field]

    def getLangByField(self,field,value):
        langs = [lang[0] for lang in self.lang.items() 
                    if lang[1][field] == value ]
        if not langs:
            return 'en_US'
        else:
            return langs[0]


class varsShare:
    """Share methods and attributs for fill vars methods"""
    
    ipdig = "[%s-9]|(?:1[0-9]|[1-9])[0-9]|2[0-4][0-9]|25[0-%s]"
    ipnet = "[1-9]|[12][0-9]|3[012]"
    ipdigs = { 'dig1_254' : ipdig % (1,4), 'dig0_254' : ipdig % (0,4),
               'dig0_255' : ipdig % (0,5), }
    ipaddr = "(%(dig1_254)s)\.(%(dig0_254)s)\.(%(dig0_254)s)\.(%(dig1_254)s)"%\
                ipdigs
    ipaddr_net = "%(ipaddr)s/(%(ipnet)s)"%{'ipaddr':ipaddr,'ipnet':ipnet}

    dictNetworkManagers = {"openrc":"sys-apps/openrc",
                           "networkmanager":"net-misc/networkmanager"}

    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'}

    # data object from LDAP
    _ldapUserObject = False
    # user data from LDAP
    _ldapUserData = {}

    reFindVer = re.compile(
        "(?<=version )(\d+\.?\d*\.?\d*\.?\d*)([^\d* ])*(\d*)")

    def getFilesByType(self,pathname,descr):
        """Get files from "pathname" has "descr" in descriptions"""
        filelist = map(lambda x:path.join(pathname,x),os.listdir(pathname))
        ftype = typeFile(magic=0x4).getMType
        filesWithType = map(lambda x:(x,ftype(x)), filelist)
        return filter(lambda x:descr in x[1],filesWithType)

    def getInitrd(self,arch,shortname,chroot,kernel,suffix="",notsuffix=""):
        """Get initrd for kernel"""
        reInitrdVer = re.compile("(initrd|initramfs)-(.+?)(-install)?$",re.S)
        def initrd_version_by_name(filename):
            resInitrdVer = reInitrdVer.search(filename)
            if resInitrdVer:
                return resInitrdVer.groups()[1]
            return ""

        ftype = typeFile(magic=0x4).getMType
        kernelfile = path.join(chroot,'boot',kernel)
        resKernelVer = self.reFindVer.search(ftype(kernelfile))
        if resKernelVer:
            kernelVersion = "%s-%s-%s"% \
               (resKernelVer.group().replace('-calculate',''),
                arch, shortname)
            origKernelVer = resKernelVer.group()

            bootdir = path.join(chroot,'boot')
            initramfsFiles = self.getFilesByType(bootdir,"ASCII cpio archive")
            initramfsWithVer = \
                    filter(lambda x: (kernelVersion in x[1] or 
                              origKernelVer in x[1]) and \
                              x[0].endswith(suffix) and \
                              (not notsuffix or not x[0].endswith(notsuffix)),
                           map(lambda x:(x[0],initrd_version_by_name(x[0])),
                           initramfsFiles))
            if initramfsWithVer:
                return path.split(min(initramfsWithVer,
                                     key=itemgetter(0))[0])[-1]
        return ""

    def getDirList(self,pathname):
        """Get directory list by pathname"""
        dirs = []
        if path.exists(pathname):
            dirs = filter(lambda x: path.isdir(path.join(pathname,x)),
                          os.listdir(pathname))
        return dirs

    def getUserInfo(self):
        """Get information about user from LDAP in dict format"""
        userName = self.Get('ur_login')
        if userName:
            if userName in self._ldapUserData:
                return self._ldapUserData[userName]
            elif not ldapUser is None:
                ldapObj = self.getLdapUserObject()
                if ldapObj:
                    userInfo = ldapObj.getUserLdapInfo(userName)
                    if userInfo:
                        self._ldapUserData[userName] = userInfo
                        return userInfo
        return {}

    def getLdapUserObject(self):
        """Get data obejct from LDAP"""
        if not self._ldapUserObject:
            self._ldapUserObject = ldapUser()
        return self._ldapUserObject

    def _runos(self, cmd, env={}):
        """Return result of os command perform"""
        if not env:
            env.update(os.environ.items() + [("PATH",getpathenv())] +\
                       env.items())
        retCode, programOut = runOsCommand(cmd, None, env_dict=env)
        if not retCode:
            return programOut
        return False

    def get_composite_from_xorgconf(self,chroot="/"):
        """Get composite value from xorg.conf"""
        xorgConfig = path.join(chroot,
                                  "etc/X11/xorg.conf")
        try:
            confLines = open(xorgConfig,"r").readlines()
        except:
            return None

        flagStartExtensions = False
        lineCompositeTmp = ""
        lineComposite = ""
        for line in confLines:
            if flagStartExtensions:
                if 'EndSection' in line:
                    lineComposite = lineCompositeTmp
                    break
                elif 'Section' in line:
                    break
                if 'Option' in line and '"Composite"' in line:
                    lineCompositeTmp = line
            else:
                if '"Extensions"' in line and 'Section' in line:
                    flagStartExtensions = True
        if lineComposite:
            listOpt = filter(lambda x: x.strip(), lineComposite.split('"'))
            if len(listOpt) == 3:
                ret = listOpt[2].lower()
                if ret in ("on","true","yes","1"):
                    return "on"
                elif ret in ("off","false","no","0"):
                    return "off"
        return None

    def getValueFromCmdLine(self,option,num):
        """Get value of parameter from boot params
        
        Parameters:
        option      param name
        num         number part of value parameter (, split)
        """
        cmdLine = "/proc/cmdline"
        calculateParam = "calculate"
        # try get timezone from kernel calculate param
        try:
            for param in open(cmdLine,"r").read().split(" "):
                parname,op,value = param.partition("=")
                if parname == calculateParam and op == "=":
                    values = value.split(",")
                    if len(values) > num and values[num].strip():
                        return values[num].strip()
        except IOError,e:
            return ""

    def getValueFromConfig(self,config,name):
        """Get value of parameter from bash type file
        
        Parameters:
        config      config file name
        name        param name
        """
        reMatch = re.compile("^%s\s*=\s*\"?(.*?)(\"\s*)?$"%name, re.I)
        try:
            if path.exists(config):
                for line in open(config,"r").readlines():
                    match = reMatch.match(line)
                    if match:
                        return match.groups()[0].strip()
        except:
            pass
        return False

    def getX11Resolution(self):
        """Return current screen resolution (width, height), X must be ran"""
        lines=self._runos("xdpyinfo")
        if not lines:
            return ""
        reRes = re.compile("dimensions:\s+(\d+)x(\d+)\s+pixels")
        searchRes=False
        for line in lines:
            searchRes = reRes.search(line)
            if searchRes:
                break
        if searchRes:
            return (searchRes.group(1), searchRes.group(2))
        else:
            return ""

    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"
        return None

    def getVersionFromMetapackage(self,systemroot,shortname):
        """Get version from meta package"""
        pkgInfoDir = path.join(systemroot,'var/db/pkg/app-misc/')
        if not os.access(pkgInfoDir,os.R_OK):
            return None
        metaPkgs = sorted(filter(lambda x:"calculate-meta" in x or \
                                 "%s-meta"%shortname.lower() in x,
                          os.listdir(pkgInfoDir)))
        if metaPkgs:
            reFindVer = re.compile("(?<=\-)\d+\.?\d*\.?\d*")
            findVer = reFindVer.search(metaPkgs[0])
            if findVer:
                return findVer.group()
        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"""
        textLines = self._runos("uname -r")
        reVer=re.compile("^(\d+\.)*\d",re.S)
        kernelVersion = ""
        if textLines:
            kernelVersion = textLines[0]
        if kernelVersion:
            reRes = reVer.search(kernelVersion)
            if reRes:
                return reRes.group()

    def isChroot(self,pid):
        """Detect chroot mode by different mountinfo"""
        if not os.access('/proc/self/mountinfo',R_OK) or \
            not os.access('/proc/1/mountinfo',R_OK):
            return False
        return open('/proc/1/mountinfo','r').read() != \
               open('/proc/self/mountinfo','r').read()

    def getProgPath(self,progname):
        """Get full path of program or False"""
        baseprogname = os.path.basename(progname)
        env = {"LANG":"C"}
        env.update(os.environ.items() + [("PATH",getpathenv())] +\
                   env.items())
        res = self._runos("which %s"%progname,env=env)
        if res:
            return res[0].strip()
        elif os.path.isabs(progname) and os.path.exists(progname):
            return progname
        else:
            return False
