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

from Plugins.Extensions.NeoBoot.__init__ import _
import os
import time
from Tools.Directories import fileExists, pathExists
from Tools.CList import CList
from Components.SystemInfo import SystemInfo
from Components.Console import Console
from Plugins.Extensions.NeoBoot.files import Task
if fileExists('/usr/lib/python2.7'):
    import Task
else:
    from Components import Task
try:
    from Task import LoggingTask
except:
    from Components.Task import LoggingTask
from Screens.Screen import Screen
from Components.ActionMap import ActionMap
from Components.MenuList import MenuList
from Components.Label import Label
from Components.Pixmap import Pixmap
from Screens.MessageBox import MessageBox


def readFile(filename):
    file = open(filename)
    data = file.read().strip()
    file.close()
    return data


def getProcMounts():
    try:
        mounts = open('/proc/mounts', 'r')
    except IOError as ex:
        print(("[Harddisk] Failed to open /proc/mounts"), ex)
        return []

    result = [line.strip().split(' ') for line in mounts]
    for item in result:
        item[1] = item[1].replace('\\040', ' ')

    return result


def getNonNetworkMediaMounts():
    return [x[1] for x in getProcMounts() if x[1].startswith('/media/') and not x[0].startswith('//')]


def isFileSystemSupported(filesystem):
    try:
        for fs in open('/proc/filesystems', 'r'):
            if fs.strip().endswith(filesystem):
                return True

        return False
    except Exception as ex:
        print(("[Harddisk] Failed to read /proc/filesystems:'"), ex)


def findMountPoint(path):
    path = os.path.abspath(path)
    while not os.path.ismount(path):
        path = os.path.dirname(path)

    return path


DEVTYPE_UDEV = 0
DEVTYPE_DEVFS = 1


class Harddisk():

    def __init__(self, device, removable=False):
        self.device = device
        if os.access('/dev/.udev', 0):
            self.type = DEVTYPE_UDEV
        elif os.access('/dev/.devfsd', 0):
            self.type = DEVTYPE_DEVFS
        else:
            print("[Harddisk] Unable to determine structure of /dev")
            self.type = -1
            self.card = False
        self.max_idle_time = 0
        self.idle_running = False
        self.last_access = time.time()
        self.last_stat = 0
        self.timer = None
        self.is_sleeping = False
        self.dev_path = ''
        self.disk_path = ''
        self.mount_path = None
        self.mount_device = None
        self.phys_path = os.path.realpath(self.sysfsPath('device'))
        self.removable = removable
        self.internal = 'pci' in self.phys_path or 'ahci' in self.phys_path or 'sata' in self.phys_path
        try:
            data = open('/sys/block/%s/queue/rotational' % device, 'r').read().strip()
            self.rotational = int(data)
        except:
            self.rotational = True

        if self.type == DEVTYPE_UDEV:
            self.dev_path = '/dev/' + self.device
            self.disk_path = self.dev_path
            self.card = 'sdhci' in self.phys_path
        elif self.type == DEVTYPE_DEVFS:
            tmp = readFile(self.sysfsPath('dev')).split(':')
            s_major = int(tmp[0])
            s_minor = int(tmp[1])
            for disc in os.listdir('/dev/discs'):
                dev_path = os.path.realpath('/dev/discs/' + disc)
                disk_path = dev_path + '/disc'
                try:
                    rdev = os.stat(disk_path).st_rdev
                except OSError:
                    continue

                if s_major == os.major(rdev) and s_minor == os.minor(rdev):
                    self.dev_path = dev_path
                    self.disk_path = disk_path
                    break

            self.card = self.device[:2] == 'hd' and 'host0' not in self.dev_path
        print("[Harddisk] new device"), self.device, '->', self.dev_path, '->', self.disk_path
        if not removable and not self.card:
            self.startIdle()
        return

    def __lt__(self, ob):
        return self.device < ob.device

    def partitionPath(self, n):
        if self.type == DEVTYPE_UDEV:
            if self.dev_path.startswith('/dev/mmcblk0'):
                return self.dev_path + 'p' + n
            else:
                return self.dev_path + n
        elif self.type == DEVTYPE_DEVFS:
            return self.dev_path + '/part' + n

    def sysfsPath(self, filename):
        return os.path.join('/sys/block/', self.device, filename)

    def stop(self):
        if self.timer:
            self.timer.stop()
            self.timer.callback.remove(self.runIdle)

    def bus(self):
        ret = _('External')
        if self.type == DEVTYPE_UDEV:
            type_name = ' (SD/MMC)'
        elif self.type == DEVTYPE_DEVFS:
            type_name = ' (CF)'
        if self.card:
            ret += type_name
        else:
            if self.internal:
                ret = _('Internal')
            if not self.rotational:
                ret += ' (SSD)'
        return ret

    def diskSize(self):
        cap = 0
        try:
            line = readFile(self.sysfsPath('size'))
            cap = int(line)
            return cap / 1000 * 512 / 1000
        except:
            dev = self.findMount()
            if dev:
                try:
                    stat = os.statvfs(dev)
                    cap = int(stat.f_blocks * stat.f_bsize)
                    return cap / 1000 / 1000
                except:
                    pass

        return cap

    def capacity(self):
        cap = self.diskSize()
        if cap == 0:
            return ''
        if cap < 1000:
            return _('%03d MB') % cap
        return _('%d.%03d GB') % (cap / 1000, cap % 1000)

    def model(self):
        try:
            if self.device[:2] == 'hd':
                return readFile('/proc/ide/' + self.device + '/model')
            if self.device[:2] == 'sd':
                vendor = readFile(self.sysfsPath('device/vendor'))
                model = readFile(self.sysfsPath('device/model'))
                return vendor + '(' + model + ')'
            if self.device.startswith('mmcblk0'):
                return readFile(self.sysfsPath('device/name'))
            raise (Exception, ("[Harddisk] no hdX or sdX or mmcX"))
        except Exception as e:
            print("[Harddisk] Failed to get model:"), e
            return '-?-'

    def free(self):
        dev = self.findMount()
        if dev:
            try:
                stat = os.statvfs(dev)
                return stat.f_bfree / 1000 * (stat.f_bsize / 1024)
            except:
                pass

        return -1

    def numPartitions(self):
        numPart = -1
        if self.type == DEVTYPE_UDEV:
            try:
                devdir = os.listdir('/dev')
            except OSError:
                return -1

            for filename in devdir:
                if filename.startswith(self.device):
                    numPart += 1

        elif self.type == DEVTYPE_DEVFS:
            try:
                idedir = os.listdir(self.dev_path)
            except OSError:
                return -1

            for filename in idedir:
                if filename.startswith('disc'):
                    numPart += 1
                if filename.startswith('part'):
                    numPart += 1

        return numPart

    def mountDevice(self):
        for parts in getProcMounts():
            if os.path.realpath(parts[0]).startswith(self.dev_path):
                self.mount_device = parts[0]
                self.mount_path = parts[1]
                return parts[1]

        return None

    def enumMountDevices(self):
        for parts in getProcMounts():
            if os.path.realpath(parts[0]).startswith(self.dev_path):
                yield parts[1]

    def findMount(self):
        if self.mount_path is None:
            return self.mountDevice()
        else:
            return self.mount_path

    def unmount(self):
        dev = self.mountDevice()
        if dev is None:
            return 0
        else:
            cmd = 'umount ' + dev
            print("[Harddisk]"), cmd
            res = os.system(cmd)
            return res >> 8

    def createPartition(self):
        cmd = 'printf "8,\n;0,0\n;0,0\n;0,0\ny\n" | sfdisk -f -uS ' + self.disk_path
        res = os.system(cmd)
        return res >> 8

    def mkfs(self):
        return 1

    def mount(self):
        if self.mount_device is None:
            dev = self.partitionPath('1')
        else:
            dev = self.mount_device
        try:
            fstab = open('/etc/fstab')
            lines = fstab.readlines()
            fstab.close()
        except IOError:
            return -1

        for line in lines:
            parts = line.strip().split(' ')
            fspath = os.path.realpath(parts[0])
            if fspath == dev:
                print("[Harddisk] mounting:"), fspath
                cmd = 'mount -t auto ' + fspath
                res = os.system(cmd)
                return res >> 8

        res = -1
        if self.type == DEVTYPE_UDEV:
            res = os.system('hdparm -z ' + self.disk_path)
            from time import sleep
            sleep(3)
        return res >> 8

    def fsck(self):
        return 1

    def killPartitionTable(self):
        zero = 512 * '\x00'
        h = open(self.dev_path, 'wb')
        for i in range(9):
            h.write(zero)

        h.close()

    def killPartition(self, n):
        zero = 512 * '\x00'
        part = self.partitionPath(n)
        h = open(part, 'wb')
        for i in range(3):
            h.write(zero)

        h.close()

    def createInitializeJob(self):
        job = Task.Job(_('Initializing storage device...'))
        size = self.diskSize()
        print("[HD] size: %s MB") % size
        task = UnmountTask(job, self)
        task = Task.PythonTask(job, _('Removing partition table'))
        task.work = self.killPartitionTable
        task.weighting = 1
        task = Task.LoggingTask(job, _('Rereading partition table'))
        task.weighting = 1
        task.setTool('hdparm')
        task.args.append('-z')
        task.args.append(self.disk_path)
        task = Task.ConditionTask(job, _('Waiting for partition'), timeoutCount=20)
        task.check = lambda: not os.path.exists(self.partitionPath('1'))
        task.weighting = 1
        if os.path.exists('/usr/sbin/parted'):
            use_parted = True
        elif size > 2097151:
            addInstallTask(job, 'parted')
            use_parted = True
        else:
            use_parted = False
        task = Task.LoggingTask(job, _('Creating partition'))
        task.weighting = 5
        if use_parted:
            task.setTool('parted')
            if size < 1024:
                alignment = 'min'
            else:
                alignment = 'opt'
            if size > 2097151:
                parttype = 'gpt'
            else:
                parttype = 'msdos'
            task.args += ['-a',
             alignment,
             '-s',
             self.disk_path,
             'mklabel',
             parttype,
             'mkpart',
             'primary',
             '0%',
             '100%']
        else:
            task.setTool('sfdisk')
            task.args.append('-f')
            task.args.append('-uS')
            task.args.append(self.disk_path)
            if size > 128000:
                print("[HD] Detected >128GB disk, using 4k alignment")
                task.initial_input = '8,,L\n;0,0\n;0,0\n;0,0\ny\n'
            else:
                task.initial_input = ',,L\n;\n;\n;\ny\n'
        task = Task.ConditionTask(job, _('Waiting for partition'))
        task.check = lambda: os.path.exists(self.partitionPath('1'))
        task.weighting = 1
        task = MkfsTask(job, _('Creating filesystem'))
        big_o_options = ['dir_index']

###__blokada hash dla ext4 >>>
#        if isFileSystemSupported('ext4'):
#            task.setTool('mkfs.ext4')
#            if size > 20000:
#                try:
#                    version = map(int, open('/proc/version', 'r').read().split(' ', 4)[2].split('.', 2)[:2])
#                    if version[0] > 3 or version[0] > 2 and version[1] >= 2:
#                        task.args += ['-C', '262144']
#                        big_o_options.append('bigalloc')
#                except Exception as ex:
#                    print 'Failed to detect Linux version:', ex
#        else:
#            task.setTool('mkfs.ext3')

        task.setTool('mkfs.ext3')
        if size > 250000:
            task.args += ['-T',
             'largefile',
             '-N',
             '262144']
            big_o_options.append('sparse_super')
        elif size > 16384:
            task.args += ['-T', 'largefile']
            big_o_options.append('sparse_super')
        elif size > 2048:
            task.args += ['-T',
             'largefile',
             '-N',
             str(size * 32)]
        task.args += ['-m0',
         '-O',
         ','.join(big_o_options),
         self.partitionPath('1')]
        task = MountTask(job, self)
        task.weighting = 3
        task = Task.ConditionTask(job, _('Waiting for mount'), timeoutCount=20)
        task.check = self.mountDevice
        task.weighting = 1
        return job

    def initialize(self):
        return -5

    def check(self):
        return -5

    def createCheckJob(self):
        job = Task.Job(_('Checking filesystem...'))
        if self.findMount():
            UnmountTask(job, self)
            dev = self.mount_device
        else:
            dev = self.partitionPath('1')
        task = Task.LoggingTask(job, 'fsck')
        task.setTool('fsck.ext3')
        task.args.append('-f')
        task.args.append('-p')
        task.args.append(dev)
        MountTask(job, self)
        task = Task.ConditionTask(job, _('Waiting for mount'))
        task.check = self.mountDevice
        return job

    def getDeviceDir(self):
        return self.dev_path

    def getDeviceName(self):
        return self.disk_path

    def readStats(self):
        try:
            l = open('/sys/block/%s/stat' % self.device).read()
        except IOError:
            return (-1, -1)

        data = l.split(None, 5)
        return (int(data[0]), int(data[4]))

    def startIdle(self):
        from enigma import eTimer
        if self.bus() == _('External'):
            Console().ePopen(('sdparm',
             'sdparm',
             '--set=SCT=0',
             self.disk_path))
        else:
            Console().ePopen(('hdparm',
             'hdparm',
             '-S0',
             self.disk_path))
        self.timer = eTimer()
        self.timer.callback.append(self.runIdle)
        self.idle_running = True
        self.setIdleTime(self.max_idle_time)

    def runIdle(self):
        if not self.max_idle_time:
            return
        t = time.time()
        idle_time = t - self.last_access
        stats = self.readStats()
        l = sum(stats)
        if l != self.last_stat and l >= 0:
            self.last_stat = l
            self.last_access = t
            idle_time = 0
            self.is_sleeping = False
        if idle_time >= self.max_idle_time and not self.is_sleeping:
            self.setSleep()
            self.is_sleeping = True

    def setSleep(self):
        if self.bus() == _('External'):
            Console().ePopen(('sdparm',
             'sdparm',
             '--flexible',
             '--readonly',
             '--command=stop',
             self.disk_path))
        else:
            Console().ePopen(('hdparm',
             'hdparm',
             '-y',
             self.disk_path))

    def setIdleTime(self, idle):
        self.max_idle_time = idle
        if self.idle_running:
            if not idle:
                self.timer.stop()
            else:
                self.timer.start(idle * 100, False)

    def isSleeping(self):
        return self.is_sleeping


class Partition():

    def __init__(self, mountpoint, device=None, description='', force_mounted=False):
        self.mountpoint = mountpoint
        self.description = description
        self.force_mounted = mountpoint and force_mounted
        self.is_hotplug = force_mounted
        self.device = device

    def __str__(self):
        return 'Partition(mountpoint=%s,description=%s,device=%s)' % (self.mountpoint, self.description, self.device)

    def stat(self):
        if self.mountpoint:
            return os.statvfs(self.mountpoint)
        raise (OSError, "Device %s is not mounted") % self.device

    def free(self):
        try:
            s = self.stat()
            return s.f_bavail * s.f_bsize
        except OSError:
            return None

        return None

    def total(self):
        try:
            s = self.stat()
            return s.f_blocks * s.f_bsize
        except OSError:
            return None

        return None

    def tabbedDescription(self):
        if self.mountpoint.startswith('/media/net') or self.mountpoint.startswith('/media/autofs'):
            return self.description
        return self.description + '\t' + self.mountpoint

    def mounted(self, mounts=None):
        if self.force_mounted:
            return True
        else:
            if self.mountpoint:
                if mounts is None:
                    mounts = getProcMounts()
                for parts in mounts:
                    if self.mountpoint.startswith(parts[1]):
                        return True

            return False

    def filesystem(self, mounts=None):
        if self.mountpoint:
            if mounts is None:
                mounts = getProcMounts()
            for fields in mounts:
                if self.mountpoint.endswith('/') and not self.mountpoint == '/':
                    if fields[1] + '/' == self.mountpoint:
                        return fields[2]
                elif fields[1] == self.mountpoint:
                    return fields[2]

        return ''


def addInstallTask(job, package):
    task = Task.LoggingTask(job, 'update packages')
    task.setTool('opkg')
    task.args.append('update')
    task = Task.LoggingTask(job, 'Install ' + package)
    task.setTool('opkg')
    task.args.append('install')
    task.args.append(package)


class HarddiskManager():

    def __init__(self):
        self.hdd = []
        self.cd = ''
        self.partitions = []
        self.devices_scanned_on_init = []
        self.on_partition_list_change = CList()
        self.enumerateBlockDevices()
        p = (('/media/hdd', _('Hard disk')),
         ('/media/card', _('Card')),
         ('/media/cf', _('Compact flash')),
         ('/media/mmc1', _('MMC card')),
         ('/media/net', _('Network mount')),
         ('/media/net1', _('Network mount %s') % '1'),
         ('/media/net2', _('Network mount %s') % '2'),
         ('/media/net3', _('Network mount %s') % '3'),
         ('/media/ram', _('Ram disk')),
         ('/media/usb', _('USB stick')),
         ('/media/usb1', _('USB1 stick')),
         ('/media/usb2', _('USB2 stick')),
         ('/', _('Internal flash')))
        known = set([os.path.normpath(a.mountpoint) for a in self.partitions if a.mountpoint])
        for m, d in p:
            if m not in known and os.path.ismount(m):
                self.partitions.append(Partition(mountpoint=m, description=d))

    def getBlockDevInfo(self, blockdev):
        HasMMC = fileExists('/proc/cmdline') and 'root=/dev/mmcblk' in open('/proc/cmdline', 'r').read()
        devpath = '/sys/block/' + blockdev
        error = False
        removable = False
        blacklisted = False
        is_cdrom = False
        partitions = []
        try:
            if os.path.exists(devpath + '/removable'):
                removable = bool(int(readFile(devpath + '/removable')))
            if os.path.exists(devpath + '/dev'):
                dev = int(readFile(devpath + '/dev').split(':')[0])
            else:
                dev = None
            blacklisted = dev in [1,
             7,
             31,
             253,
             254] + (['HasMMC'] and [179] or [])
            if blockdev[0:2] == 'sr':
                is_cdrom = True
            if blockdev[0:2] == 'hd':
                try:
                    media = readFile('/proc/ide/%s/media' % blockdev)
                    if 'cdrom' in media:
                        is_cdrom = True
                except IOError:
                    error = True

            if not is_cdrom and os.path.exists(devpath):
                for partition in os.listdir(devpath):
                    if partition[0:len(blockdev)] != blockdev:
                        continue
                    partitions.append(partition)

            else:
                self.cd = blockdev
        except IOError:
            error = True

        medium_found = True
        try:
            open('/dev/' + blockdev).close()
        except IOError as err:
            if err.errno == 159:
                medium_found = False

        return (error,
         blacklisted,
         removable,
         is_cdrom,
         partitions,
         medium_found)

    def enumerateBlockDevices(self):
        print("[Harddisk] enumerating block devices...")
        for blockdev in os.listdir('/sys/block'):
            error, blacklisted, removable, is_cdrom, partitions, medium_found = self.addHotplugPartition(blockdev)
            if not error and not blacklisted and medium_found:
                for part in partitions:
                    self.addHotplugPartition(part)

                self.devices_scanned_on_init.append((blockdev,
                 removable,
                 is_cdrom,
                 medium_found))

    def getAutofsMountpoint(self, device):
        r = self.getMountpoint(device)
        if r is None:
            return '/media/' + device
        else:
            return r

    def getMountpoint(self, device):
        dev = '/dev/%s' % device
        for item in getProcMounts():
            if item[0] == dev:
                return item[1]

        return None

    def addHotplugPartition(self, device, physdev=None):
        if not physdev:
            dev, part = self.splitDeviceName(device)
            try:
                physdev = os.path.realpath('/sys/block/' + dev + '/device')[4:]
            except OSError:
                physdev = dev
                print(("couldn't determine blockdev physdev for device"), device)

        error, blacklisted, removable, is_cdrom, partitions, medium_found = self.getBlockDevInfo(device)
        if not blacklisted and medium_found:
            description = self.getUserfriendlyDeviceName(device, physdev)
            p = Partition(mountpoint=self.getMountpoint(device), description=description, force_mounted=True, device=device)
            self.partitions.append(p)
            if p.mountpoint:
                self.on_partition_list_change('add', p)
            l = len(device)
            if l and (not device[l - 1].isdigit() or device == 'mmcblk0'):
                self.hdd.append(Harddisk(device, removable))
                self.hdd.sort()
                SystemInfo['Harddisk'] = True
        return (error,
         blacklisted,
         removable,
         is_cdrom,
         partitions,
         medium_found)

    def addHotplugAudiocd(self, device, physdev=None):
        if not physdev:
            dev, part = self.splitDeviceName(device)
            try:
                physdev = os.path.realpath('/sys/block/' + dev + '/device')[4:]
            except OSError:
                physdev = dev
                print(("couldn't determine blockdev physdev for device"), device)

        error, blacklisted, removable, is_cdrom, partitions, medium_found = self.getBlockDevInfo(device)
        if not blacklisted and medium_found:
            description = self.getUserfriendlyDeviceName(device, physdev)
            p = Partition(mountpoint='/media/audiocd', description=description, force_mounted=True, device=device)
            self.partitions.append(p)
            self.on_partition_list_change('add', p)
            SystemInfo['Harddisk'] = False
        return (error,
         blacklisted,
         removable,
         is_cdrom,
         partitions,
         medium_found)

    def removeHotplugPartition(self, device):
        for x in self.partitions[:]:
            if x.device == device:
                self.partitions.remove(x)
                if x.mountpoint:
                    self.on_partition_list_change('remove', x)

        l = len(device)
        if l and not device[l - 1].isdigit():
            for hdd in self.hdd:
                if hdd.device == device:
                    hdd.stop()
                    self.hdd.remove(hdd)
                    break

            SystemInfo['Harddisk'] = len(self.hdd) > 0

    def HDDCount(self):
        return len(self.hdd)

    def HDDList(self):
        list = []
        for hd in self.hdd:
            hdd = hd.model() + ' - ' + hd.bus()
            cap = hd.capacity()
            if cap != '':
                hdd += ' (' + cap + ')'
            list.append((hdd, hd))

        return list

    def getCD(self):
        return self.cd

    def getMountedPartitions(self, onlyhotplug=False, mounts=None):
        if mounts is None:
            mounts = getProcMounts()
        parts = [x for x in self.partitions if (x.is_hotplug or not onlyhotplug) and x.mounted(mounts)]
        devs = set([x.device for x in parts])
        for devname in devs.copy():
            if not devname:
                continue
            dev, part = self.splitDeviceName(devname)
            if part and dev in devs:
                devs.remove(dev)

        return [x for x in parts if not x.device or x.device in devs]

    def splitDeviceName(self, devname):
        dev = devname[:3]
        part = devname[3:]
        for p in part:
            if not p.isdigit():
                return (devname, 0)

        return (dev, part and int(part) or 0)

    def getUserfriendlyDeviceName(self, dev, phys):
        dev, part = self.splitDeviceName(dev)
        description = _('External Storage %s') % dev
        try:
            description = readFile('/sys' + phys + '/model')
        except IOError as s:
            print(("couldn't read model: "), s)

        if part and part != 1:
            description += _(' (Partition %d)') % part
        return description

    def addMountedPartition(self, device, desc):
        for x in self.partitions:
            if x.mountpoint == device:
                return

        self.partitions.append(Partition(mountpoint=device, description=desc))

    def removeMountedPartition(self, mountpoint):
        for x in self.partitions[:]:
            if x.mountpoint == mountpoint:
                self.partitions.remove(x)
                self.on_partition_list_change('remove', x)

    def setDVDSpeed(self, device, speed=0):
        ioctl_flag = int(21282)
        if not device.startswith('/'):
            device = '/dev/' + device
        try:
            from fcntl import ioctl
            cd = open(device)
            ioctl(cd.fileno(), ioctl_flag, speed)
            cd.close()
        except Exception as ex:
            print("[Harddisk] Failed to set %s speed to %s") % (device, speed), ex


class UnmountTask(Task.LoggingTask):

    def __init__(self, job, hdd):
        Task.LoggingTask.__init__(self, job, _('Unmount'))
        self.hdd = hdd
        self.mountpoints = []

    def prepare(self):
        try:
            dev = self.hdd.disk_path.split('/')[-1]
            open('/dev/nomount.%s' % dev, 'wb').close()
        except Exception as e:
            print("ERROR: Failed to create /dev/nomount file:"), e

        self.setTool('umount')
        self.args.append('-f')
        for dev in self.hdd.enumMountDevices():
            self.args.append(dev)
            self.postconditions.append(Task.ReturncodePostcondition())
            self.mountpoints.append(dev)

        if not self.mountpoints:
            print("UnmountTask: No mountpoints found?")
            self.cmd = 'true'
            self.args = [self.cmd]

    def afterRun(self):
        for path in self.mountpoints:
            try:
                os.rmdir(path)
            except Exception as ex:
                print("Failed to remove path '%s':") % path, ex


class MountTask(Task.LoggingTask):

    def __init__(self, job, hdd):
        Task.LoggingTask.__init__(self, job, _('Mount'))
        self.hdd = hdd

    def prepare(self):
        try:
            dev = self.hdd.disk_path.split('/')[-1]
            os.unlink('/dev/nomount.%s' % dev)
        except Exception as e:
            print("ERROR: Failed to remove /dev/nomount file:"), e

        if self.hdd.mount_device is None:
            dev = self.hdd.partitionPath('1')
        else:
            dev = self.hdd.mount_device
        fstab = open('/etc/fstab')
        lines = fstab.readlines()
        fstab.close()
        for line in lines:
            parts = line.strip().split(' ')
            fspath = os.path.realpath(parts[0])
            if os.path.realpath(fspath) == dev:
                self.setCmdline('mount -t auto ' + fspath)
                self.postconditions.append(Task.ReturncodePostcondition())
                return

        if self.hdd.type == DEVTYPE_UDEV:
            self.setCmdline('sleep 2; hdparm -z ' + self.hdd.disk_path)
            self.postconditions.append(Task.ReturncodePostcondition())
        return


class MkfsTask(Task.LoggingTask):

    def prepare(self):
        self.fsck_state = None
        return

    def processOutput(self, data):
        print("[Mkfs]"), data
        if 'Writing inode tables:' in data:
            self.fsck_state = 'inode'
        elif 'Creating journal' in data:
            self.fsck_state = 'journal'
            self.setProgress(80)
        elif 'Writing superblocks ' in data:
            self.setProgress(95)
        elif self.fsck_state == 'inode':
            if '/' in data:
                try:
                    d = data.strip(' \x08\r\n').split('/', 1)
                    if '\x08' in d[1]:
                        d[1] = d[1].split('\x08', 1)[0]
                    self.setProgress(80 * int(d[0]) / int(d[1]))
                except Exception as e:
                    print("[Mkfs] E:"), e

                return
        self.log.append(data)


###########################__From HarddiskSetup_################################
class HarddiskSetup(Screen):

    def __init__(self, session, hdd, action, text, question):
        Screen.__init__(self, session)
        self.action = action
        self.question = question
        self.setTitle(_('Setup hard disk'))
        self['model'] = Label(_('Model: ') + hdd.model())
        self['capacity'] = Label(_('Capacity: ') + hdd.capacity())
        self['bus'] = Label(_('Bus: ') + hdd.bus())
        self['key_red'] = Label(_('Cancel'))
        self['key_green'] = Label(text)
        self['actions'] = ActionMap(['OkCancelActions'], {'ok': self.hddQuestion,
         'cancel': self.close})
        self['shortcuts'] = ActionMap(['ShortcutActions'], {'red': self.close,
         'green': self.hddQuestion})

    def hddQuestion(self):
        message = self.question + '\n' + _('You can continue watching TV etc. while this is running.')
        self.session.openWithCallback(self.hddConfirmed, MessageBox, message)

    def hddConfirmed(self, confirmed):
        if not confirmed:
            return
        try:
            from Task import job_manager
        except:
            from Components.Task import job_manager
        try:
            job = self.action()
            job_manager.AddJob(job, onSuccess=job_manager.popupTaskView)
            from Screens.TaskView import JobView
            self.session.open(JobView, job, afterEventChangeable=False)
        except Exception as ex:
            self.session.open(MessageBox, str(ex), type=MessageBox.TYPE_ERROR, timeout=10)

        self.close()


class HarddiskSelection(Screen):
    def __init__(self, session):
        Screen.__init__(self, session)
        self.setTitle(_('Select hard disk'))
        self.skinName = 'HarddiskSelection'
        if harddiskmanager.HDDCount() == 0:
            tlist = []
            tlist.append((_('no storage devices found'), 0))
            self['hddlist'] = MenuList(tlist)
        else:
            self['hddlist'] = MenuList(harddiskmanager.HDDList())
        self['key_red'] = Label(_('Cancel'))
        self['key_green'] = Label(_('Select'))
        self['actions'] = ActionMap(['OkCancelActions'], {'ok': self.okbuttonClick,
         'cancel': self.close})
        self['shortcuts'] = ActionMap(['ShortcutActions'], {'red': self.close,
         'green': self.okbuttonClick})

    def doIt(self, selection):
        self.session.openWithCallback(self.close, HarddiskSetup, selection, action=selection.createInitializeJob, text=_('Initialize'), question=_('Do you really want to initialize the device?\nAll data on the disk will be lost!'))

    def okbuttonClick(self):
        selection = self['hddlist'].getCurrent()
        if selection[1] != 0:
            self.doIt(selection[1])


class HarddiskFsckSelection(HarddiskSelection):

    def doIt(self, selection):
        self.session.openWithCallback(self.close, HarddiskSetup, selection, action=selection.createCheckJob, text=_('Check'), question=_('Do you really want to check the filesystem?\nThis could take lots of time!'))
###########################__end HarddiskSetup_################################


harddiskmanager = HarddiskManager()


def isSleepStateDevice(device):
    ret = os.popen('hdparm -C %s' % device).read()
    if 'SG_IO' in ret or 'HDIO_DRIVE_CMD' in ret:
        return None
    elif 'drive state is:  standby' in ret or 'drive state is:  idle' in ret:
        return True
    elif 'drive state is:  active/idle' in ret:
        return False
    else:
        return None


def internalHDDNotSleeping(external=False):
    state = False
    if harddiskmanager.HDDCount():
        for hdd in harddiskmanager.HDDList():
            if hdd[1].internal or external:
                if hdd[1].idle_running and hdd[1].max_idle_time and not hdd[1].isSleeping():
                    state = True

    return state


harddiskmanager = HarddiskManager()
SystemInfo['ext4'] = isFileSystemSupported('ext4') or isFileSystemSupported('ext3')
