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

import os
import shutil
import sys
import subprocess
from stat import ST_SIZE
from tails_installer import _
from tails_installer.releases import releases
from tails_installer.config import config
from tails_installer.utils import (_to_unicode, _dir_size, iso_is_live_system,
                           unicode_to_utf8, unicode_to_filesystemencoding,
                           _set_liberal_perms_recursive,
                           underlying_physical_device)

class SourceError(Exception):
    """ A generic error message that is thrown by the Source classes """

class Source(object):
    def clone(self, destination):
        raise NotImplementedError

class LocalIsoSource(Source):
    def __init__(self, path):
        self.path = os.path.abspath(_to_unicode(path))
        self.size = os.stat(self.path)[ST_SIZE]
        if not iso_is_live_system(self.path):
            raise SourceError(_("Unable to find LiveOS on ISO"))
        self.dev  = None
        # This can fail for devices not supported by UDisks such as aufs mounts
        try:
            self.dev = underlying_physical_device(self.path)
        except Exception, e:
            print >> sys.stderr, _("Could not guess underlying block device: %s"
                                   % e.args[0])
            pass

    def clone(self, destination):
        cmd = ['7z', 'x', self.path,
               '-x![BOOT]', '-y', '-o%s' % (destination)]
        cmd_decoded = u' '.join(cmd)
        cmd_bytes = [ unicode_to_filesystemencoding(el) for el in cmd ]
        proc = subprocess.Popen(cmd_bytes, stdout=subprocess.PIPE,
                                stderr=subprocess.PIPE)
        out, err = proc.communicate()
        out = out.decode('utf-8')
        err = err.decode('utf-8')
        if proc.returncode:
            raise SourceError(_("There was a problem executing `%s`.\n"
                                "%s\n%s" % (cmd_decoded, out, err)))
        _set_liberal_perms_recursive(destination)

    def get_release(self):
        """ If the ISO is for a known release, return it. """
        isoname = os.path.basename(self.path)
        for release in releases:
            if os.path.basename(release['url']) == isoname:
                return release

class RunningLiveSystemSource(Source):
    def __init__(self, path):
        if not os.path.exists(path):
            raise SourceError(_("'%s' does not exist") % path)
        if not os.path.isdir(path):
            raise SourceError(_("'%s' is not a directory") % path)
        self.path = path
        self.size = _dir_size(self.path)
        self.dev  = underlying_physical_device(self.path)
    def clone(self, destination):
        for f in config['liveos_toplevel_files']:
            src = os.path.join(self.path, f)
            dst = os.path.join(destination, f)
            if os.path.isfile(src):
                if src.lower().endswith('.iso'):
                    print >> sys.stderr, _("Skipping '%(filename)s'" % {
                        'filename': src
                    })
                else:
                    shutil.copy(src, dst)
            elif os.path.islink(src):
                linkto = os.readlink(src)
                os.symlink(linkto, dst)
            elif os.path.isdir(src):
                shutil.copytree(src, dst)
        _set_liberal_perms_recursive(destination)
