#!/usr/bin/env python

# Copyright 2009-2015 Jasper Poppe <jgpoppe@gmail.com>
#
# 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.


__author__ = 'Jasper Poppe <jgpoppe@gmail.com>'
__copyright__ = 'Copyright (c) 2009-2015 Jasper Poppe'
__credits__ = ''
__license__ = 'Apache License, Version 2.0'
__version__ = '2.0.0rc7'
__maintainer__ = 'Jasper Poppe'
__email__ = 'jgpoppe@gmail.com'
__status__ = 'production'

import fnmatch
import logging
import os

import utils


class Manage:
    """manage netboot images, ISO, syslinux and permissions files"""

    def __init__(self, cfg):
        """initialize class variables"""
        self.cfg = cfg
        self.temp = os.path.join(self.cfg['paths']['temp'], 'seedbank')

    def copy_dir_contents(self, src, dst):
        """find and copy all files from src to dst"""
        utils.make_dirs(dst)
        files = [os.path.join(root, file_name) for root, _, files in
            os.walk(src) if files for file_name in files]
        for src in files:
            utils.file_copy(src, dst)

    def _download(self, src, dst_path):
        """download a file"""
        src_file = os.path.basename(src)
        dst = os.path.join(dst_path, src_file)
        if os.path.isfile(dst):
            logging.info('"%s" already exists, download skipped', dst)
        else:
            utils.make_dirs(dst_path)
            utils.download(src, dst)

    def _extract(self, prefix, files, src, dst, target):
        """extract files to the seedbank temp directory and move those"""
        archive = os.path.join(dst, os.path.basename(src))
        files = (os.path.join(prefix, file_name) for file_name in files)
        temp_manage = os.path.join(self.temp, 'manage')
        if os.path.isdir(temp_manage):
            utils.rmtree(temp_manage)
        utils.make_dirs(temp_manage)
        utils.untar_files(archive, files, temp_manage)
        self.copy_dir_contents(temp_manage, target)
        utils.rmtree(temp_manage)

    def _extract_debs(self, directory):
        """extract files from all debian packages in a directory"""
        pattern = self.cfg['debian']['firmware_filter']
        os.chdir(directory)
        for file_name in os.listdir(directory):
            if fnmatch.fnmatch(file_name, pattern):
                result = utils.call(['dpkg', '-x', file_name, 'temp'])
                if result:
                    err = 'failed to extract package "%s"' % file_name
                    raise utils.FatalException(err)
                logging.info('extracted "%s"', file_name)

    def _pxe_default(self):
        """manage the pxelinux.cfg default file"""
        src = os.path.join(self.cfg['paths']['templates'], 'pxe_default')
        directory = os.path.join(self.cfg['paths']['tftpboot'], 'pxelinux.cfg')
        dst = os.path.join(directory, 'default')
        if os.path.isfile(dst):
            return
        logging.info('created default pxelinux.cfg file "%s"', dst)
        utils.make_dirs(directory)
        utils.file_copy(src, dst)

    def _debian_firmware(self, name):
        """integrate Debian non free firmware"""
        temp_initrd = os.path.join(self.temp, 'initrd')
        initrd = os.path.join(self.cfg['paths']['tftpboot'], 'seedbank', name,
            'initrd.gz')
        utils.make_dirs(temp_initrd)
        utils.initrd_extract(temp_initrd, initrd)
        dst = os.path.join(self.temp, 'initrd/lib/firmware')
        self._add_firmware(name, dst)
        utils.initrd_create(temp_initrd, initrd)
        utils.rmtree(temp_initrd)

    def _add_firmware(self, name, dst):
        """download, extract and copy Debian non free firmware"""
        distribution, release, _ = name.split('-')
        path = '-'.join(('firmware', distribution, release))
        archive_dst = os.path.join(self.cfg['paths']['archives'], path)
        temp_firmware = os.path.join(self.temp, 'firmware')
        archive = os.path.join(archive_dst, 'firmware.tar.gz')
        url = self.cfg[distribution]['url_firmware'].replace('${release}',
            release)
        self._download(url, archive_dst)
        utils.untar(archive, temp_firmware)
        self._extract_debs(temp_firmware)
        src = os.path.join(temp_firmware, 'temp', 'lib/firmware')
        utils.file_move(src, dst)
        utils.rmtree(temp_firmware)

    def syslinux(self):
        """download syslinux and extract required files"""
        dst = os.path.join(self.cfg['paths']['archives'], 'syslinux')
        files = ('core/pxelinux.0', 'com32/menu/menu.c32',