#-*- 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
import re
from os import path
from calculate.lib.datavars import Variable,VariableError,ReadonlyVariable
from calculate.lib.utils.portage import isPkgInstalled
from calculate.lib.utils.files import process,STDOUT,getProgPath
from calculate.lib.utils.common import (getVideoFromXorgLog,
                getVideoFromXorgConf, getVideoFromCmdLine,
                getAvailableVideo, getValueFromCmdLine,
                getCompositeFromXorgconf, getVideoFromModules,
                getVideoFromVendor,getInstalledVideo)

from calculate.lib.cl_lang import setLocalTranslate
setLocalTranslate('cl_install3',sys.modules[__name__])

class VideoVariable(Variable):
    """
    Video variables not using for flash installation
    """
    xorg_need = True

    def uncompatible(self):
        """
        Video setting up unavailable for flash installation
        """
        if self.Get('os_install_root_type') == 'flash':
            return \
                _("Video configuration unavailable for Flash install")
        if self.Get('os_install_x11_server_set') == 'no' and self.xorg_need:
            return \
                _("This distribution does not provide a Xorg server")
        return ""

class ResolutionVariable(VideoVariable):
    """
    Abstract resolution variable
    """
    fbres = False
    def choice(self):
        resolutions = ["640x480", "800x480", "800x600", "1024x576", "1024x600",
                       "1024x768", "1200x800", "1280x800", "1280x720",
                       "1280x768", "1280x1024", "1360x768", "1366x768",
                       "1368x768", "1400x1050", "1440x900", "1680x945",
                       "1680x1050", "1920x1080", "1920x1200", "1600x768",
                       "1600x900", "1600x1200", "2048x1152", "2560x1440",
                       "2560x1600"]
        if self.fbres:
            return map(lambda x:"%s-32"%x,
                   resolutions)
        else:
            return resolutions

    def check(self,value):
        """
        Check resolution format 1234x567
        """
        if not re.match('^\d+x\d+(-\d+(@\d+)?)?$',value):
            raise VariableError(
                _("Wrong resolution {resolution} {example}").format(
                resolution=value,
                example="(%s:%s)"%(_("Example"),"1024x768")))

class VariableOsInstallX11Resolution(ResolutionVariable):
    """
    X.org resolution
    """
    type = 'choiceedit'
    opt = ['-X']
    metavalue = "<width>x<height>"

    def init(self):
        self.help = _("set the Xorg resolution")
        self.label = _("Screen resolution")

    def get(self):
        # get resolution from xorg.log
        res = self.Get('os_x11_resolution')
        if res or self.Get('os_install_root_type') in ('livecd','usb-hdd'):
            return res
        else:
            return self.choice()[-1]

class VariableOsInstallX11VideoAvailable(VideoVariable):
    """
    Get available (already installed or installable drivers
    """
    type = "list"
    supported = ["nvidia","vboxvideo","sis","nv",
                 "fglrx","nouveau","intel","ati","radeon"]

    def get(self):
        image = self.Get('cl_image')
        if image:
            with image as distr:
                distrPath = image.getDirectory()
                if isPkgInstalled('xorg-server',prefix=distrPath):
                    return sorted(filter(self.supported.__contains__,
                           getAvailableVideo(prefix=distrPath)))+['other']
        return []

class VariableOsInstallX11VideoDrv(VideoVariable):
    """
    Video driver used by xorg
    """
    type = 'choiceedit'
    opt = ['--video']
    metavalue = "VIDEODRV"

    def init(self):
        self.help = _("set the video driver")
        self.label = _("{0} video driver").format("Xorg")

    def choice(self):
        """Get available (already installed or installable drivers"""
        return self.Get('os_install_x11_video_available')

    def get(self):
        # get available videodriver list from install or configure distributive
        list_video = self.Choice('os_install_x11_video_drv')
        if not list_video:
            return "other"
        # if type system is usb-hdd then get detect video driver
        if self.Get('os_install_root_type') == 'usb-hdd':
            methods = ((getVideoFromModules,()),
                       (getVideoFromCmdLine,()),
                       (getVideoFromVendor,(self.Get('hr_video'),list_video)))
        else:
            # test current video driver for install system
            methods = ((getVideoFromXorgLog,('/',list_video)),
                       (getVideoFromXorgConf,('/',)),
                       (getVideoFromModules,()),
                       (getVideoFromCmdLine,()),
                       (getVideoFromVendor,(self.Get('hr_video'),list_video)))
        for func,args in methods:
            drv = func(*args)
            if drv in list_video:
                return drv
        return "other"

    pkgDrvMap = {'nvidia':('NVidia','x11-drivers/nvidia-drivers'),
                 'fglrx':('ATI','x11-drivers/ati-drivers'),
                 'vboxdrv':('VirtualBox','x11-drivers/xf86-video-virtualbox')}

    def check(self,value):
        if self.Get('cl_action') == 'system':
            availDrvs = self.Get('os_install_x11_video_available')
            if not value in availDrvs:
                raise VariableError(_("Only %s drivers are available")%
                        ",".join(availDrvs))
        else:
            if not value in getInstalledVideo(prefix="/") and \
                not value in ("auto","other"):
                error =_("video driver %s is unavailable")%value
                if value in self.pkgDrvMap:
                    error += ". " + (_("Install driver %s with:")
                                        %self.pkgDrvMap[value][0])
                    error += "\n" + ("emerge %s"%self.pkgDrvMap[value][1])
                raise VariableError(error)

class VariableHrVideoId(ReadonlyVariable):
    """
    BusID of video card
    TODO: need realization
    """
    value = ""

class VariableOsInstallX11Composite(VideoVariable):
    """
    on/off composite
    """
    type = 'bool'
    opt = ['--composite']

    def init(self):
        self.help = _("toggle composite")
        self.label = _("Composite")

    def get(self):
        """On/off composite"""
        defaultCompositeOn = ("nvidia","intel","fglrx","nouveau","radeon")
        composite = getValueFromCmdLine("calculate",5)
        videodrv = getValueFromCmdLine("calculate",4)
        if videodrv != "auto":
            composite = {'nocomposite':'off',
                         'off':'off',
                         'on':'on',
                         'composite':'on'}.get(composite)
        else:
            composite = None

        if self.Get('os_install_x11_video_drv') in defaultCompositeOn:
            defaultComposite = "on"
        elif self.Get('hr_virtual') == 'vmware':
            defaultComposite = "on"
        else:
            defaultComposite = "off"
        if self.Get('os_install_x11_video_drv') == self.Get('os_x11_video_drv'):
            state = getCompositeFromXorgconf()
        else:
            state = None
        return composite or state or defaultComposite

class VariableOsInstallFbResolution(ResolutionVariable):
    """
    Framebuffer resolution
    """
    type = 'choiceedit'
    opt = ['--fb']
    metavalue = "<width>x<height>"
    xorg_need = False
    fbres = True

    def init(self):
        self.help = _("set the framebuffer resolution")
        self.label = _("Framebuffer resolution")

    def get(self):
        """Get current framebuffer resolution"""
        resolution = ""
        fbres = getProgPath('/sbin/fbres')
        if fbres:
            processFbres = process(fbres,stderr=STDOUT)
            textLines = processFbres.readlines()
            if textLines:
                cxx11,cyx11 = \
                    self.Get('os_install_x11_resolution').partition('x')[0::2]
                cxfb, cyfb = textLines[0].partition('x')[0::2]
                if not filter(lambda x:not x.isdigit(),
                       [cxfb,cyfb,cxx11,cyx11])and \
                    int(cxx11) >= int(cxfb) and int(cyx11) >= int(cyfb):
                    resolution = "%s-32"%textLines[0]
        return resolution or "1024x768-32"

class VariableOsInstallX11ServerSet(ReadonlyVariable):
    """
    Is install xorg-server
    """
    type = "bool"

    def get(self):
        image = self.Get('cl_image')
        if image:
            with image as distr:
                distrPath = image.getDirectory()
                if isPkgInstalled('xorg-server',prefix=distrPath):
                    return "yes"
        return "no"
