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

# Copyright 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 re
import sys
import time
from os import path
from StringIO import StringIO
from random import choice
import string
from time import sleep
from subprocess import PIPE,STDOUT
from shutil import copy2
from calculate.core.server.func import safetyWrapper
from calculate.lib.utils.files import (runOsCommand,pathJoin,scanDirectory,
                                       process,listDirectory,STDOUT,checkUtils)
from calculate.lib.utils.common import (appendProgramToEnvFile,
                        removeProgramToEnvFile, getTupleVersion,
                        cmpVersion,getUserPassword,
                        getSupportArch, getInstalledVideo )
from calculate.lib.utils.device import (detectDeviceForPartition,
                        getUdevDeviceInfo, getLvmPartitions, refreshLVM,
                        refreshUdev,countPartitions)
from calculate.lib.cl_vars_share import varsShare
from calculate.lib import cl_overriding
from calculate.lib.utils import ip
from calculate.lib.datavars import VariableError
from datavars import DataVarsInstall, __version__,__app__
from calculate.install.variables.autopartition import (AutopartitionError,
    AutoPartition)
from calculate.install.fs_manager import FileSystemManager

from cl_kernel_utils import KernelConfig,InitRamFs

from calculate.lib.variables.locale import Locale
from calculate.lib.cl_template import Template,TemplatesError,ProgressTemplate
from calculate.lib.datavars import DataVars
from calculate.lib.cl_print import color_print
from cl_distr import (PartitionDistributive,
                DistributiveError, ScratchPartitionDistributive,
                MultiPartitions, FlashDistributive, 
                Distributive)
from calculate.lib.utils.text import tableReport
from calculate.lib.server.utils import dialogYesNo
from subprocess import Popen,PIPE,STDOUT
from itertools import *

class InstallError(Exception):
    """Installation Error"""

from cl_migrate_users import migrate, currentUsers, MigrationError
from calculate.lib.encrypt import encrypt

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

class cltCopy(scanDirectory):
    """Copy clt files

    Example:
    cltCopier = cltCopy(target="/targetdir")
    # copy all clt files from etc directory to /targetdir/etc
    cltCopier.performCopy('/etc')
    """
    def __init__(self,target='/tmp'):
        self.target = target

    performCopy = scanDirectory.scanningDirectory

    def processingFile(self,pathname,prefix):
        try:
            if pathname.endswith(".clt"):
                targetDir = pathJoin(self.target,path.dirname(pathname))
                if not path.exists(targetDir):
                    os.makedirs(targetDir)
                copy2(pathname,pathJoin(self.target,pathname))
        except Exception,e:
            raise InstallError(_("Failed to copy '%(src)s' to '%(dst)s'")%
                    {'src':pathname,'dst':pathJoin(self.target,pathname)})
        return True

class otherfilesCopy(scanDirectory):
    """Copy some files

    Example:
    otherfilesCopier = otherfilesCopy(target="/targetdir")
    # copy need files from etc directory to /targetdir/etc
    otherfilesCopier.performCopy('/etc')
    """
    def __init__(self,target='/tmp',reTest=".*"):
        self.target = target
        self.reTest = re.compile(reTest,re.S)

    performCopy = scanDirectory.scanningDirectory

    def processingFile(self,pathname,prefix):
        try:
            if self.reTest.search(pathname):
                targetDir = pathJoin(self.target,path.dirname(pathname))
                if not path.exists(targetDir):
                    os.makedirs(targetDir)
                copy2(pathname,pathJoin(self.target,pathname))
        except Exception,e:
            raise InstallError(_("Failed to copy '%(src)s' to '%(dst)s'")%
                    {'src':pathname,'dst':pathJoin(self.target,pathname)})
        return True

class Install(color_print):
    """Primary class for templates appling and system installation"""

    def __init__(self):
        self.clVars = None
        self.clTempl = None
        self.listDisksOptions = []
        self.listBindsOptions = []
        self.listSwapsOptions = []
        self.startMessage = ""
        self.lenStartMessage = 0
        self.stdoutHide = None
        self.stderrHide = None
        # refresh information about LVM
        refreshLVM()
        # refresh information about device in udevadm info
        refreshUdev()

    def setNoColor(self):
        self.color = False

    def initVars(self,datavars=None):
        """Primary initialization of variables"""
        if not datavars:
            self.clVars = DataVarsInstall()
            self.clVars.importInstall()
            self.clVars.flIniFile()
        else:
            self.clVars = datavars

    def canInstallGrub2(self,target):
        """Check that system has grub2 in current and installed system"""
        if self.clVars.Get('os_grub2_path'):
            return bool(
                   filter(lambda x:x.startswith('grub-1.99'),
                   listDirectory('/var/db/pkg/sys-boot')))
        return False

    def prepareBoot(self,targetDistr):
        """Prepare system for boot"""
        if self.clVars.Get('os_install_root_type') == "flash":
            self.installSyslinuxBootloader(targetDistr)
        else:
            if self.canInstallGrub2(targetDistr):
                self.installGrub2Bootloader(targetDistr)
            else:
                self.installLegacyGrubBootloader(targetDistr)

    def closeClTemplate(self,error=None):
        if self.clTempl:
            if self.clTempl.cltObj:
                self.clTempl.cltObj.closeFiles()
            self.clTempl.closeFiles()
            self.clTempl = None

    def applyTemplatesStartup(self):
        """Apply templates for root of system."""
        #self.clVars.Set("cl_root_path","/", True)
        self.clVars.Set("cl_chroot_path","/", True)
        templates_locate = self.clVars.Get('cl_templates_locate')

#        cltObj = True if 'clt' in templates_locate else False
        dirs_list, files_list = ([],[])
        useClt = "clt" in templates_locate
        self.clVars.Set("cl_template_path",
            map(lambda x:x[1],
            filter(lambda x:x[0] in templates_locate,
            zip(self.clVars.Get('cl_template_location'),
                self.clVars.Get('cl_template_path')))),
            True)

        self.clTempl = ProgressTemplate(self.setProgress, self.clVars,
            cltObj=useClt,
            cltFilter=True if self.clVars.Get('cl_merge_set') == "on" \
                      else False,
            printSUCCESS=self.printSUCCESS,
            printWARNING=self.printWARNING,
            askConfirm=self.askConfirm,
            dispatchConf=self.dispatchConf,
            printERROR=self.printERROR)

        dirsFiles = self.clTempl.applyTemplates()
        try:
            if self.clTempl.getError():
                self.printERROR(self.clTempl.getError())
                return False
        except AttributeError:
            pass
        return dirsFiles

    def applyTemplatesFlash(self,directory):
        """Apply templates for root of system."""
        #self.clVars.Set("cl_root_path",directory, True)
        self.clVars.Set("cl_chroot_path","/", True)
        self.clVars.Set("cl_chroot_grub","/", True)
        self.clVars.Set("cl_root_path",directory, True)
        self.clTempl = ProgressTemplate(self.setProgress,self.clVars,
                                        cltObj=False,
                                        printSUCCESS=self.printSUCCESS,
                                        printWARNING=self.printWARNING,
                                        askConfirm=self.askConfirm,
                                        printERROR=self.printERROR)
        dirsFiles = self.clTempl.applyTemplates()
        if self.clTempl.getError():
            raise InstallError(self.clTempl.getError())
        else:
            return dirsFiles

    def applyTemplates(self,directory,grubDirectory):
        """Apply templates for root of system."""
        self.clVars.Set("cl_chroot_path",directory, True)
        self.clVars.Set("cl_chroot_grub",grubDirectory, True)
        clTemplateCltPath = \
            filter(lambda x:path.exists(x),
            map(lambda x:pathJoin(directory,x),
            self.clVars.Get('cl_template_clt_path')))
        self.clVars.Set('cl_template_clt_path',clTemplateCltPath,True)
        self.clTempl = ProgressTemplate(self.setProgress,self.clVars,
                                        cltFilter=False,
                                        printSUCCESS=self.printSUCCESS,
                                        printWARNING=self.printWARNING,
                                        askConfirm=self.askConfirm,
                                        printERROR=self.printERROR)
        dirsFiles = self.clTempl.applyTemplates()
        if self.clTempl.getError():
            raise InstallError(self.clTempl.getError())
        else:
            return dirsFiles

    def checkDuplicate(self,datalist,name,key=lambda x:x):
        """Check on duplicate and print error"""
        keydata = map(key,datalist)
        dupKey = set(filter(lambda x:keydata.count(x)>1, keydata))
        if dupKey:
            self.printERROR(_("Duplicated {keyname}: {keylist}").format(
                                keyname=name,keylist=",".join(dupKey)))
            return False
        return True

    def setVarList(self,varsList,matrix):
        """Set matrix to vars"""
        if not matrix:
            map(lambda x:self.clVars.Set(x,[],True),varsList)
        else:
            map(lambda x:self.clVars.Set(x[0],list(x[1]),True),
            zip(varsList,zip(*matrix)))

    def setDisks(self):
        """
        TODO: remove check grub2_path in disk variables
        """
        try:
            if not self.clVars.Get('os_grub2_path'):
                self.checkForLegacyGrub()
            else:
                self.checkForGrub2()
        except InstallError,e:
            error.append(e)
        return True

    def setUsers(self,listUsers,autologinUser):
        """Set users data (migration)"""
        if autologinUser == "none":
            autologinUser = ""
        if autologinUser or autologinUser == "":
            self.clVars.Set('cl_autologin', autologinUser, force=True)
        else:
            autologinUser = self.clVars.Get('cl_autologin')
        autologinUser = [autologinUser] if autologinUser else []
        listUsers = listUsers or []
        if listUsers or autologinUser:
            migrateUsers = list(set(listUsers+autologinUser))
            migrateUsers.sort()
            migrateUsers = ["root"] + filter(lambda x: x!="root", migrateUsers)
            self.clVars.Set('cl_migrate_user', migrateUsers, force=True)
        return True


    def setInstallOptions(self, listDisks, listBinds, listSwaps, listUsers,
                          autologinUser, brDisk):
        """Set install options (set users, disks and boot record"""
        try:
            if self.setUsers(listUsers,autologinUser) and \
                self.setDisks(listDisks,listBinds,listSwaps) and \
                self.setBR(brDisk):
                return self.createListOptions()
            else:
                return False
        except InstallError,e:
            self.printERROR(str(e).strip())
            return False

    def getDeviceByField(self,field,value, secondPrefix="os_disk"):
        """Get device by fields (install load format uuid grub part name)"""
        return self.getFieldByField('dev',field,value,
                                    secondPrefix=secondPrefix)

    def getFieldByField(self,resField,field,value, firstPrefix="os_disk",
                        secondPrefix="os_disk"):
        res = filter(lambda x: x[1] == value,
                zip(self.clVars.Get('%s_%s'%(firstPrefix,resField)),
                    self.clVars.Get('%s_%s'%(secondPrefix,field)))) or\
                    [("","")]
        return res[0][0]

    def getFieldByDevice(self,field,device):
        """Get value of field by device"""
        device_hash = self.clVars.Get('os_disk_hash')
        if device in device_hash and field in device_hash[device]:
            return device_hash[device][field]
        else:
            return ""

    def setActivePartition(self,partition):
        """Change partition id, specified by systemid,set active"""
        deviceName = detectDeviceForPartition(partition)
        if deviceName is None:
            raise DistributiveError(
                _("Failed to determine the parent device for %s")%partition)
        # device hasn't any partition
        elif deviceName == "":
            return True
        fdiskProg, gdiskProg, partedProg = checkUtils('/sbin/fdisk',
                    '/usr/sbin/gdisk','/usr/sbin/parted')

        disk = self.clVars.Select('os_install_disk_parent',
                                  where='os_install_disk_dev',eq=partition,
                                  limit=1)
        parttable = self.clVars.Select('os_device_table',where='os_device_dev',
                                  eq=disk,limit=1)
        partitionNumber = \
            getUdevDeviceInfo(name=partition).get('ID_PART_ENTRY_NUMBER','') or \
            getUdevDeviceInfo(name=partition).get('UDISKS_PARTITION_NUMBER','')

        devicePartitionCount = countPartitions(deviceName)
        if deviceName and not partitionNumber:
            raise DistributiveError(
                _("Failed to determine the partition number for %s")%partition)
        bootFlag = "boot" if parttable == "dos" else "legacy_boot"
        if parttable == "dos":
            fdisk = process(fdiskProg, "-l",deviceName)
            DEVICENUM,AFLAG = 0,1
            changeActive = \
                map(lambda x:x[DEVICENUM],
                filter(lambda x:x[DEVICENUM] != partitionNumber and \
                                x[AFLAG] == "*" or \
                                x[DEVICENUM] == partitionNumber and \
                                not x[AFLAG] == "*",
                list(map(lambda x:[str(x[0]),x[1][1].strip()],
                # enumerate partitions
                enumerate(filter(None,
                map(lambda x:x.split()[:2],
                # drop string before information about partitions
                dropwhile(lambda x:not x.lstrip().startswith("Device"),
                fdisk.readlines()))))))[1:]))
        else:
            parted = process(partedProg, "-m",deviceName,"print")
            DEVICENUM,FLAGS = 0,6
            changeActive = \
                map(lambda x:x[DEVICENUM],
                filter(lambda x:x[DEVICENUM] != partitionNumber and \
                                bootFlag in x[FLAGS].strip(';').split(', ') or \
                                x[DEVICENUM] == partitionNumber and \
                                not bootFlag in x[FLAGS].strip(';').split(', '),
                filter(lambda x:len(x)>=7,
                map(lambda x:x.split(':'),
                parted.readlines()[2:]))))
        if not changeActive:
            return True
        if parttable == "dos":
            pipe = Popen([fdiskProg,deviceName],
                stdin=PIPE, stdout=PIPE,stderr=PIPE)
            for partnum in changeActive:
                pipe.stdin.write("a\n%s\n"%partnum)
            pipe.stdin.write("w\n")
            pipe.stdin.close()
            pipe.wait()
        elif parttable == "gpt":
            pipe = Popen([gdiskProg,deviceName],
                stdin=PIPE, stdout=PIPE,stderr=PIPE)
            if devicePartitionCount > 1:
                pipe.stdin.write("x\n")
                for partnum in changeActive:
                    pipe.stdin.write("a\n%s\n2\n\n"%partnum)
                pipe.stdin.write("w\nY\n")
            else:
                pipe.stdin.write("x\na\n2\n\nw\nY\n")
            pipe.stdin.close()
            pipe.wait()
        for waittime in (0.1,0.2,0.5,1,2,4):
            if path.exists(partition):
                return True
            else:
                sleep(waittime)
        raise InstallError(
            _("Failed to find partition %s after changing the activity")%
                partition)

    def installSyslinuxBootloader(self,target):
        """Install boot loader by syslinux

        Perform syslinux installation to flash.
        """
        if not self.clVars.Get('os_install_mbr'):
            return
        ddProcess = process("/bin/dd","if=/usr/share/syslinux/mbr.bin",
                            "of=%s"%self.clVars.Get('os_install_mbr')[0],
                            stderr=STDOUT)
        if ddProcess.failed():
            raise DistributiveError(
                _("Failed to write the master boot record\n%s")%
                            ddProcess.read())
        target.close()
        installRootDev = self.clVars.Get('os_install_root_dev')
        syslinuxProcess = process("/usr/bin/syslinux",
                                  installRootDev, stderr=STDOUT)
        if syslinuxProcess.failed():
            raise DistributiveError(_("Failed to install syslinux\n%s")%
                            syslinuxProcess.read())
        # is partition active
        return self.setActivePartition(self.clVars.Get('os_install_root_dev'))

    def varSelect(self,selField,where="os_disk_dev",eq=""):
        """Select value from os_disk/device matrix"""
        res = filter(lambda x: x[1] == eq,
                zip(self.clVars.Get(selField),
                    self.clVars.Get(where))) or\
                    [("","")]
        return res[0][0]

    def installGrub2Bootloader(self,target):
        """
        Install grub2 boot loader
        """
        for bootPath in ("/boot","/"):
            bootDisk = self.clVars.Select("os_install_disk_dev",
                where="os_install_disk_mount",eq=bootPath,limit=1)
            if bootDisk:
                self.setActivePartition(bootDisk)
                break
        cmdGrubInstall = self.clVars.Get('os_grub2_path')
        if not cmdGrubInstall:
            raise DistributiveError(_("Failed to install the bootloader"))

        for mbrDisk in self.clVars.Get('os_install_mbr'):
            process("sync").success()
            if self.clVars.Get('os_install_scratch') == "on" and \
                self.clVars.Get('cl_action') != "system":
                prefixBoot = "/mnt/scratch"
            else:
                prefixBoot = "/"
            grubProcess = process(cmdGrubInstall,
                              "--boot-directory=%s"%pathJoin(prefixBoot,
                              target.getBootDirectory()),
                              mbrDisk, "-f", stderr=STDOUT,envdict=os.environ)
            if grubProcess.failed():
                raise DistributiveError(_("Failed to install the bootloader"))

    def installLegacyGrubBootloader(self,target):
        """
        Install legecy grub boot loader

        Perform grub installation to disk, which has root partition
        """
        cmdGrub = varsShare().getProgPath('/sbin/grub')
        if not cmdGrub:
            raise DistributiveError(_("Failed to install the bootloader"))
        grubProcess = process(cmdGrub,
               "--device-map=%s/boot/grub/device.map"%target.getDirectory(),
               "--batch",stderr=STDOUT)
        bootDisk = self.Select('os_install_disk_grub',
                              where='os_install_disk_mount',
                              _in=('/','/boot'),
                              sort='DESC',limit=1)
        if not bootDisk:
            raise DistributiveError(_("Failed to determine the boot disk"))
        self.setActivePartition(bootDisk)
        for mbrDisk in self.clVars.Get('os_install_mbr'):
            mbrDiskNum = self.Select("os_device_map",
                                     where="os_device_dev",
                                     eq=mbrDisk)
            if not mbrDiskNum and mbrDiskNum != 0:
                raise DistributiveError(_("Failed to determine mbr"))
            for line in ("root (hd%s)"%bootDisk,
                         "setup (hd%d)"%mbrDiskNum,
                         "quit"):
                grubProcess.write("%s\n"%line)
            if grubProcess.failed():
                raise DistributiveError(_("Failed to install the bootloader"))

    def setupOpenGL(self):
        """Setup opengl for current video driver"""
        defaultGL = "xorg-x11"
        pathGlModules = path.join(self.clVars.Get('cl_chroot_path'),
                                 'usr/lib/opengl')
        openGLenv = path.join(self.clVars.Get('cl_chroot_path'),
                                 'etc/env.d/03opengl')

        openGlMods = filter(lambda x:x != "global",
                               listDirectory(pathGlModules))
        mapGL_drivers = {'fglrx':"ati" if "ati" in openGlMods
                                 else defaultGL,
                         'nvidia':"nvidia" if "nvidia" in openGlMods
                                  else defaultGL}
        x11_driver = self.clVars.Get('os_install_x11_video_drv')
        if x11_driver in mapGL_drivers:
            newModuleName = mapGL_drivers[x11_driver]
        else:
            newModuleName = defaultGL
        curModuleName = map(lambda x:x.strip().rpartition('=')[-1].strip('"\''),
                   filter(lambda x: x.startswith("OPENGL_PROFILE="),
                          open(openGLenv,'r')))
        curModuleName = curModuleName[-1] if curModuleName else ""
        if curModuleName == newModuleName:
            return True
        res,errmes = runOsCommand('eselect opengl set %s'%newModuleName)
        if res == 0:
            return True
        else:
            return False

    def checkVideoDriver(self):
        """Check video driver and install nvidia driver"""
        binPackages = '/usr/portage/packages'
        nvidiaBinDrivers = path.join(binPackages,'x11-drivers')
        if self.clVars.Get('hr_video') != 'nvidia' or \
            not path.exists(nvidiaBinDrivers):
            return True
        maskFile = '/etc/portage/package.mask'
        nvidiaMaskFile = path.join(maskFile,'nvidia-drivers')
        # convert file package.mask to directory package mask
        if path.isfile(maskFile):
            os.rename(maskFile,maskFile+"2")
            os.mkdir(maskFile,mode=0755)
            os.rename(maskFile+"2",path.join(maskFile,"default"))
        if path.exists(nvidiaMaskFile):
            curNvidiaMask = open(nvidiaMaskFile,'r').read().strip()
        else:
            curNvidiaMask = ""

        maskNvidia = self.clVars.Get('os_nvidia_mask')
        if maskNvidia == curNvidiaMask:
            return True
        self.startTask(_("Driver installation for %s")%
            self.clVars.Get('hr_video'))
        open(nvidiaMaskFile,'w').write(maskNvidia)
        return True

    def cleanInitrd(self):
        """Clean initrd from needless modules"""
        # get path to initrd and initrd-install in new system
        # (/boot/initramfs-...-install,/boot/initramfs-...)
        chrootPath = path.join(self.clVars.Get('cl_chroot_path'),'boot')
        initrdPath = path.join(chrootPath,self.clVars.Get('os_install_initrd'))
        initrdInstallPath = path.join(chrootPath,
            self.clVars.Get('os_install_initrd_install'))
        if path.exists(initrdInstallPath):
            copy2(initrdInstallPath,initrdPath);
        return True

    def afterCopyHDDinstall(self,targetDistr):
        """Action performed after distributive copy for hdd install"""
        # copy clt files from current system
        self.startTask(_("Copying clt templates to the new system"))
        cltCpy = cltCopy(target=targetDistr.getDirectory())
        for directory in self.clVars.Get('cl_template_clt_path'):
            cltCpy.performCopy(directory)
        self.endTask()

        self.startTask(_("Copying configuration files to the new system"))
        fileMask = r"/etc/udev/rules\.d/70-persistent-net\.rules"
        if self.clVars.Get('os_root_type') != "livecd":
            fileMask = \
                "(%s|/etc/ssh/ssh_host_.*|/root/.ssh/(id_.*|known_hosts))"% \
                    fileMask
        fileCpy = otherfilesCopy(target=targetDistr.getDirectory(),
                                 reTest=fileMask)
        fileCpy.performCopy('/etc')
        if path.exists('/root/.ssh'):
            fileCpy.performCopy('/root/.ssh')
        self.endTask()

        # optimize initrd
        self.clVars.Set("cl_chroot_path",targetDistr.getDirectory(), True)
        self.startTask(_("Creating a new initrd file"))
        self.cleanInitrd()
        self.endTask("")

        self.remountNTFS()
        # join templates
        self.startTask(_("Updating the configuration"),progress=True)
        self.applyTemplates(targetDistr.getDirectory(),
                    targetDistr.getBootDirectory()[:-4])
        # mount bind mount points

        self.endTask()

        self.startTask(_("Post-install configuration"))
        targetDistr.postinstallMountBind()
        self.endTask()

        # migrate users
        self.startTask(_("Migrating users"))
        objMigrate = migrate(targetDistr.getDirectory())
        if not objMigrate.migrate(self.clVars.Get('cl_migrate_data'),
                          self.clVars.Get('cl_migrate_root_pwd'),[],[],):
            raise InstallError(_("Failed to migrate users onto the new system"))
        self.endTask()

    def setupVideo(self):
        """Setup video"""
        pathGlModules = path.join(self.clVars.Get('cl_chroot_path'),
                                 'usr/lib/opengl')
        self.startTask(_("Checking the video driver"))
        self.checkVideoDriver()
        self.endTask()
        if path.exists(pathGlModules):
            self.startTask(_("Configuring OpenGL"))
            self.setupOpenGL()
            self.endTask()
        oldXdrv = self.clVars.Get('os_x11_video_drv')
        newXdrv = self.clVars.Get('os_install_x11_video_drv')
        if oldXdrv != newXdrv:
            kmsDrv = ("radeon","i915","intel","nouveau","ati")
            self.defaultPrint("\n")
            if oldXdrv in kmsDrv or newXdrv in kmsDrv:
                self.printWARNING(
                    _("To apply the changes, reboot the system")
                    +".\n")
            else:
                self.printWARNING(
                    _("To apply the changes, restart the X server")
                    +".\n")

    @safetyWrapper(native_errors=(MigrationError, TemplatesError, InstallError,
                                  AutopartitionError, DistributiveError),
                   man_int= __("Configuration manually interrupted"),
                   post_action=closeClTemplate,
                   success_message=__("System configured!"))
    def setupSystem(self,variables):
        self.initVars(variables)
        target = None
        setupType = self.clVars.Get('cl_setup',humanreadable=True)

        if setupType:
            self.startTask((_("%s are being configured")%
                           setupType).capitalize(),progress=True)
        else:
            self.startTask(_("System configuration"),progress=True)
        refreshLVM()
        res = self.applyTemplatesStartup()
        self.endTask()
        if setupType and self.clVars.Get('cl_setup') == 'network':
            pass
        if not setupType or self.clVars.Get('cl_setup') == 'video':
            self.setupVideo()
        if setupType and self.clVars.Get('cl_setup') == 'users':
            pass
        if self.clVars.Get('cl_setup') == 'boot' and \
            self.clVars.Get('os_root_type') != 'livecd':
            target = self.clVars.Get('cl_image')
            if self.clVars.Get('os_install_mbr'):
                self.startTask(_("Installing the bootloader"))
                self.prepareBoot(target)
                self.endTask()
            root_dev = self.clVars.Select('os_disk_parent',
                                   where='os_disk_mount',
                                   eq='/',limit=1)
            if root_dev:
                self.startTask(_("Changing the I/O scheduler"))
                try:
                    schedpath = ("/sys%s/queue/scheduler"%
                      (getUdevDeviceInfo(name=root_dev).get('DEVPATH','')))
                    if path.exists(schedpath):
                        open(schedpath,'w').write(
                            self.clVars.Get('os_install_kernel_scheduler'))
                    self.endTask()
                except:
                    self.printERROR(_("Unable to change the I/O scheduler"))
                    pass
        return True

    def installPostAction(self,error):
        """
        Install post action
        """
        self.closeClTemplate()
        if self.sourceDistr and self.sourceDistr.childs:
            self.startTask(_("Letting go the source distribution"))
            self.sourceDistr.close()
            self.endTask()
        if self.targetDistr and self.targetDistr.childs:
            self.startTask(_("Unmounting the target system volume"))
            self.targetDistr.close()
            self.endTask()

    @safetyWrapper(native_errors=(MigrationError, TemplatesError, InstallError,
                                  AutopartitionError, DistributiveError),
                   man_int= __("Installation manually interrupted"),
                   post_action=installPostAction,
                   failed_message=__("Failed to install the system!"),
                   success_message=__("System successfully installed!"))
    def installSystem(self,variables):
        """install System by current variable enviroment"""
        self.initVars(variables)
        results = []
        #self.beginFrame()
        self.targetDistr = None
        self.sourceDistr = None
        #self.clVars.printVars()
        self.setTaskNumber(25)
        if self.clVars.Get('cl_autopartition_set') == 'on':
            self.startTask(_("Creating a new partition table"),
                           progress=True)
            ap = AutoPartition()
            devices = self.clVars.Get('cl_autopartition_device')
            ap.clearLvm(devices,self.clVars)
            ap.clearRaid(devices,self.clVars)
            ap.recreateSpace(
                self.clVars.Get('cl_autopartition_table'),
                devices,
                self.clVars.Get('cl_autopartition_disk_data'),
                self.clVars.GetBool('cl_autopartition_lvm_set'),
                self.clVars.Get('cl_autopartition_lvm_vgname'))
            self.endTask()
        self.targetDistr = self.clVars.Get('cl_target')
        self.sourceDistr = self.clVars.Get('cl_image')
        # cmd options
        if self.targetDistr.needFormat:
            self.startTask(_("Formatting the partitions"),progress=True)
            self.targetDistr.performFormat()
            self.endTask()
        # install distributive
        #raise InstallError("Manual stop")
        self.startTask(_("Unpacking the system image to the target"),
                       progress=True,num=18)
        self.clVars.Get('os_grub_conf')
        # set spinner flag
        filesnum = self.clVars.Get('os_install_linux_files')
        if filesnum.isdigit():
            filesnum = int(filesnum)
        else:
            filesnum = 0
        self.targetDistr.installFrom(self.sourceDistr,
            callbackProgress=self.setProgress,
            filesnum=filesnum)
        if self.clVars.Get('os_install_pxe') == 'off':
            self.targetDistr.convertToDirectory()
        self.endTask()

        self.clVars.processRefresh()
        if self.clVars.Get('os_install_root_type') != "flash" and \
            self.clVars.Get('os_install_pxe') == 'off':
            self.afterCopyHDDinstall(self.targetDistr)
        else:
            # join templates
            if self.clVars.Get('os_install_pxe') == 'on':
                self.startTask(
                    _("Configuring PXE install"),progress=True)
                self.applyTemplatesFlash('/')
            else:
                self.startTask(
                    _("Configuring Flash install"),progress=True)
                self.applyTemplatesFlash(self.targetDistr.getDirectory())
            self.endTask()
            self.closeClTemplate()
        # change boot config
        if self.clVars.Get('os_install_mbr') and \
            self.clVars.Get('os_install_pxe') == "off":
            self.startTask(_("Preparing the system for reboot"))
            self.prepareBoot(self.targetDistr)
        self.endTask()
        return True

    def rndString(self):
        """Get random string with len 8 char"""
        return "".join([choice(string.ascii_letters+string.digits)
                    for i in xrange(0,8)])

    def _getFreeDirectory(self,directory):
        """
        Get free directory name
        """
        newDirectoryName = directory
        while path.exists(newDirectoryName):
            newDirectoryName = "%s.%s"%(directory,self.rndString())
        return newDirectoryName

    def remountNTFS(self):
        """
        Remount NTFS partitions 
        """
        for disk in self.clVars.Select('os_disk_dev',
                                where='os_disk_format',like='ntfs'):
            mountDir = self._getFreeDirectory('/var/lib/calculate/mount.ntfs')
            try:
                os.mkdir(mountDir)
            except:
                continue
            if process('/bin/mount',disk,mountDir).success():
                for i in (0.2,0.5,1,2,4,5):
                    if process('/bin/umount',mountDir).success():
                        break
                else:
                    self.printWARNING(_("Unable to umount %s")%mountDir)
            try:
                os.rmdir(mountDir)
            except:
                self.printWARNING(_("Unable to remove directory %s")%mountDir)
