#-*- 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
import sys
from utils.common import getpathenv
from utils.files import runOsCommand, typeFile,process
import re
from os import path, R_OK
from operator import itemgetter

class varsShare:
    """Share methods and attributs for fill vars methods"""
    
    dictNetworkManagers = {"openrc":"sys-apps/openrc",
                           "networkmanager":"net-misc/networkmanager"}

    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)
        typeKernelFile = ftype(kernelfile)
        if typeKernelFile == None:
            return ""
        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 _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 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"
        names = ("lang","keymap","timezone",
                    "resolution","video","composite")
        # try get timezone from kernel calculate param
        try:
            if type(num) == str and not num.isdigit():
                name = num
                num = names.index(name)
            else:
                name = names[int(num)]
            for param in open(cmdLine,"r").read().split(" "):
                parname,op,value = param.partition("=")
                if parname == calculateParam and op == "=":
                    # new format
                    if ":" in value:
                        params = dict(
                                map(lambda x:x.partition(':')[0::2],
                                filter(lambda x:x,
                                value.split(','))))
                        return params.get(name,"").strip()
                    # old format
                    else:
                        values = value.split(",")
                        if len(values) > num and values[num].strip():
                            return values[num].strip()
        except (IOError,ValueError,IndexError),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 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

    def selectVar(self,selField,where="",eq=""):
        """Select value from matrix variables

        Example:
        selectVar("os_disk_dev",where="os_disk_mount",eq="/")"""
        res = filter(lambda x:x[1] == eq,
              zip(self.Get(selField),
                  self.Get(where))) or [("","")]
        return res[0][0]

