#!/usr/bin/python
# Anas Nashif <anas.nashif@intel.com>
import yaml,  sys
import re, os
from kickstart import kickstart

import copy
import time
import optparse
from time import gmtime, strftime
import errno
try:
  from lxml import etree
except ImportError:
  try:
    # Python 2.5
    import xml.etree.cElementTree as etree
  except ImportError:
    try:
      # Python 2.5
      import xml.etree.ElementTree as etree
    except ImportError:
      try:
        # normal cElementTree install
        import cElementTree as etree
      except ImportError:
        try:
          # normal ElementTree install
          import elementtree.ElementTree as etree
        except ImportError:
          print("Failed to import ElementTree from any known place")

def mkdir_p(path):
    try:
        os.makedirs(path)
    except OSError as exc: # Python >2.5
        if exc.errno == errno.EEXIST:
            pass
        else: raise


class KSWriter():
    def __init__(self,  im, rep, out):
        self.image_filename = im
        self.repo_filename = rep
        self.outdir = out
        self.image_stream = file(self.image_filename, 'r')
        self.repo_stream = file(self.repo_filename, 'r')
        self.extra = {}
        pass
    def merge(*input):
        return list(reduce(set.union, input, set()))

    def dump(self):
        print yaml.dump(yaml.load(self.stream))

    def parse(self, img):
        conf = copy.copy(image_meta['Default'])
        plat = copy.copy(image_meta[img['Platform']])
        conf.update(plat)
        conf.update(img)
        lval = ['Repos', 'Groups', 'PostScripts', 'NoChrootScripts', 'RemovePackages', 'ExtraPackages']
        lvald = {}
        for l in lval:
            full = []
            if image_meta['Default'].has_key(l) and image_meta['Default'][l]:
                full = full + image_meta['Default'][l]
            if plat.has_key(l) and plat[l]:
                full = full + plat[l]
            if img.has_key(l) and img[l]:
                full = full + img[l]
            lvald[l] = sorted(set(full), key=full.index)
            #print full
        conf.update(lvald)
        #print conf
        postscript = ""
        for scr in conf['PostScripts']:
            if os.path.exists('./custom/scripts/%s.post' %scr):
                f = open('./custom/scripts/%s.post' %scr, 'r')
                postscript += f.read()
                postscript += "\n"
                f.close()
            else:
                print './custom/scripts/%s.post not found, skipping.' %scr

        nochrootscript = ""
        for scr in conf['NoChrootScripts']:
            if os.path.exists('./custom/scripts/%s.nochroot' %scr):
                f = open('./custom/scripts/%s.nochroot' %scr, 'r')
                nochrootscript += f.read()
                nochrootscript += "\n"
                f.close()
            else:
                print './custom/scripts/%s.nochroot not found, skipping.' %scr

        ptab = ""
        for g in [ plat, img ]:
            if g.has_key("Part"):
                f = open("./custom/part/%s" %g['Part'] )
                ptab = f.read()
                f.close()

        conf['Part'] = ptab
        conf['Post'] = postscript
        conf['NoChroot'] = nochrootscript
        return conf

    def process_files(self,  meta,  repos):
        new_repos = []
        #print repos
        #print meta
        if meta.has_key("Architecture") and  meta['Architecture']:
            for repo in repos:
                r = {}
                r['Name'] = repo['Name']
                if repo.has_key('Options'):
                    r['Options'] = repo['Options']
                r['Url'] = repo['Url'].replace("@ARCH@", meta['Architecture'])
                r['Url'] = r['Url'].replace("@RELEASE@", meta['Baseline'])
                new_repos.append(r)
        else:
            new_repos = repos

        nameSpace = {'metadata': meta,  'repos': new_repos}
        t = kickstart(searchList=[nameSpace])
        a = str(t)
        if meta.has_key('FileName') and meta['FileName']:
            f = None
            if meta.has_key("Baseline"):
                mkdir_p(meta['Baseline'])
                f = open("%s/%s/%s.ks" %( self.outdir, meta['Baseline'],  meta['FileName'] ), 'w')
            else:
                f = open("%s/%s.ks" %( self.outdir, meta['FileName'] ), 'w')
            f.write(a)
            f.close()


def image_xml(root, img):
    s = etree.Element("config")
    c = etree.Element('name')
    c.text = "%s.ks" %img['FileName']
    s.append(c)
    cc = etree.Element('path')
    cc.text = "image-configs/%s.ks" %img['FileName']
    s.append(cc)
    cc = etree.Element('description')
    cc.text = "%s" %img['Name']
    s.append(cc)

    if img.has_key('Architecture'):
        cc = etree.Element('arch')
        cc.text = "%s" %img['Architecture']
        s.append(cc)

    cc = etree.Element('md5')
    cc.text = ""
    s.append(cc)

    cc = etree.Element('schedule')
    if img.has_key('Schedule'):
        cc.text = img['Schedule']
    s.append(cc)
    root.append(s)

def create_xml(image_meta):
    root = etree.Element("image-configs")
    if image_meta.has_key('Configurations'):
        for img in image_meta['Configurations']:
            image_xml(root,img)
    for path in image_meta['ExternalConfigs']:
        for f in os.listdir(path):
            if f.endswith('.yaml'):
                fp = file('%s/%s' %(path, f), 'r')
                local = yaml.load(fp)
                conf = ks.parse(local)
                if conf.has_key('Active') and conf['Active']:
                    image_xml(root,conf)

    str = etree.tostring(root, pretty_print=True)
    return str

if __name__ == '__main__':
    parser = optparse.OptionParser()

    parser.add_option("-c", "--configs", type="string", dest="configsfile",
                    help="configuration meta file")
    parser.add_option("-o", "--outdir", type="string", dest="outdir",
                    help="outdir")
    parser.add_option("-r", "--repos", type="string", dest="repofile",
                    help="repo meta file")
    parser.add_option("-i", "--index", type="string", dest="indexfile",
                    help="generate index file")

    (options, args) = parser.parse_args()

    if options.configsfile is None or options.repofile is None:
        print "you need to provide meta files with --configs and --repos"
        sys.exit(1)

    outdir = ""
    if options.outdir is None:
        outdir = "."
    else:
        outdir = options.outdir

    ks = KSWriter(options.configsfile, options.repofile, outdir)
    repo_meta = yaml.load(ks.repo_stream)
    image_meta = yaml.load(ks.image_stream)

    r = repo_meta['Repositories']
    if image_meta.has_key('Configurations'):
        for img in image_meta['Configurations']:
            conf = ks.parse(img)
            if conf.has_key('Active') and conf['Active']:
                print "Creating %s (%s.ks)" %(img['Name'], img['FileName'] )
                ks.process_files(conf, r)
            else:
                print "%s is inactive, not generate %s this time" %(img['Name'], img['FileName'] )
    for path in image_meta['ExternalConfigs']:
        for f in os.listdir(path):
            if f.endswith('.yaml'):
                fp = file('%s/%s' %(path, f), 'r')
                local = yaml.load(fp)
                conf = ks.parse(local)
                if conf.has_key('Active') and conf['Active']:
                    print "Creating %s (%s.ks)" %(conf['Name'], conf['FileName'] )
                    ks.process_files(conf, r)
                else:
                    print "%s is inactive, not generate %s this time" %(conf['Name'], conf['FileName'] )
            else:
                print "WARNING: File '%s' ignored." % (f)

    if options.indexfile:
        str = create_xml(image_meta)
        f = open(options.indexfile, 'w')
        f.write(str)
        f.close()
