# vim: ai ts=4 sts=4 et sw=4
#
# Copyright (C) 2010, 2011, 2012, 2013, 2014 Intel, Inc.
#
#    This program is free software; you can redistribute it and/or
#    modify it under the terms of the GNU General Public License
#    as published by the Free Software Foundation; version 2 of the License.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#

"""
This module takes care of handling/generating/parsing of build.xml
"""

import re
import os

from subprocess import check_output, CalledProcessError
from collections import OrderedDict
from xml.dom import minidom

class ImageDataError(Exception):
    """Custom ImgData exception."""
    pass

class ImageData(object):
    """Class for handling image data."""

    # fixing of buggy xml.dom.minidom.toprettyxml
    XMLTEXT_RE = re.compile(r'>\n\s+([^<>\s].*?)\n\s+</', re.DOTALL)

    def __init__(self):
        self.images = OrderedDict()
        self.ksi = OrderedDict()

    def load(self, xml):
        """Load image data from xml."""

        def get_elem(node, name):
            """Helper: get first element by tag name."""
            try:
                return node.getElementsByTagName(name)[0]
            except IndexError:
                raise ImageDataError("Error: <%s><%s> not found" % \
                                     (node.nodeName, name))

        dom = minidom.parseString(xml)

        # Keep compatible with old repo structure,
        images = get_elem(dom, "image-configs")

        for image in images.getElementsByTagName("config"):
            img = {}
            for field in ('name', 'description', 'path', 'arch', 'ks',
                    'buildtarget'):
                try:
                    img[field] = str(get_elem(image, field).firstChild.data)
                except ImageDataError:
                    img[field] = ''

            self.images[img['name']] = img

    def to_xml(self, hreadable=True):
        """Format image data as xml."""
        content = '<?xml version="1.0" ?><image-configs>'

        for image in self.images.itervalues():
            content += '<config>'
            for field, value in image.iteritems():
                content += '<%s>%s</%s>' % (field, value, field)
            content += '</config>'
        content += '</image-configs>'

        # make it human readable
        if hreadable:
            dom = minidom.parseString(content)
            content = self.XMLTEXT_RE.sub(r'>\g<1></',
                                          dom.toprettyxml(indent='  '))

        return content

    def save(self, path, hreadable=True):
        """
        Save image data to xml file and save ks files to
        image-configuration dir
        """
        if not os.path.isdir(os.path.join(path,
                                          'image-configurations')):
            os.makedirs(os.path.join(path,
                                     'image-configurations'))
        # Write content down
        with open(os.path.join(path,
                               'images.xml'), 'w') as out:
            out.write(self.to_xml(hreadable))

        for ksname, kscontent in self.ksi.items():
            with open(os.path.join(path,
                                   'image-configurations',
                                   ksname), 'w') as out:
                out.write(kscontent)

    def extract_image_conf(self, rpm):
        """Extract ks files and image data from rpm."""
        try:
            output = check_output("rpm2cpio %s |cpio -t" % rpm, shell=True)
        except CalledProcessError, err:
            raise ImageDataError("Can't get content of %s: %s" % (rpm, err))

        for path in output.split():
            if path.endswith('.ks'):
                try:
                    content = check_output('rpm2cpio %s |cpio -i --quiet '\
                                           '--to-stdout %s' % (rpm, path),
                                           shell=True)
                except CalledProcessError, err:
                    raise ImageDataError("Can't extract %s from %s: %s" % \
                                         (path, rpm, err))
                # Change baseurl
                if os.getenv('ENABLED_REPLACE_BASEURL'):
                    content = content.replace(os.getenv('ENABLED_REPLACE_BASEURL').split(',')[0],
                                              os.getenv('ENABLED_REPLACE_BASEURL').split(',')[1])
                self.ksi[os.path.basename(path)] = content
            if path.endswith('.xml'):
                try:
                    content = check_output('rpm2cpio %s |cpio -i --quiet '\
                                           '--to-stdout %s' % (rpm, path),
                                           shell=True)
                except CalledProcessError, err:
                    raise ImageDataError("Can't extract %s from %s: %s" % \
                                         (path, rpm, err))
                self.load(content)
