#!/home/chenxm/.pyenv/versions/3.6.7/bin/python
import argparse
import sys
from pathlib import Path

from verminator import *
from verminator.utils import *


class VerminatorCmd(object):

    def __init__(self):
        parser = argparse.ArgumentParser(
            description='TDC image version management terminator.',
            usage='''verminator <command> [<args>]

The most commonly used verminator commands are:
   validate         Validate existing image versions and fix errors automatically
   genver           Create a new release version
   genoem		    Convert TDC into OEM release
''')
        parser.add_argument('command', help='Subcommand to run')
        args = parser.parse_args(sys.argv[1:2])
        if not hasattr(self, args.command):
            print('Unrecognized command')
            parser.print_help()
            exit(1)
        getattr(self, args.command)()

    def validate(self):
        parser = argparse.ArgumentParser(
            description='Validate existing image versions and fix errors automatically')
        parser.add_argument('-c', '--component', help='a specific instance to validate')
        parser.add_argument('-o', '--oemname', help='an oem name')
        parser.add_argument('--releasemeta', help='the releases_meta.yml file')
        parser.add_argument('--nodump', action='store_false', help='if dumpping update')
        parser.add_argument('instance_folder', help='the instances folder of images definition')
        args = parser.parse_args(sys.argv[2:])

        print('Running validation, instance_folder=%s, releasemeta=%s ...' % \
              (args.instance_folder, args.releasemeta))
        _validate_instances(
            instance_folder=args.instance_folder,
            releasemeta=args.releasemeta,
            component=args.component,
            dump=not args.nodump,
            oemname=args.oemname
        )

    def genver(self):
        parser = argparse.ArgumentParser(description='Create a new release version')
        parser.add_argument('-v', '--version', required=True, help='a new version for product line')
        parser.add_argument('-c', '--component', help='a specific instance to validate')
        parser.add_argument('-o', '--oemname', help='an oem name')
        parser.add_argument('--releasemeta', help='the releases_meta.yml file')
        parser.add_argument('--nodump', action='store_false', help='if dumpping update')
        parser.add_argument('instance_folder', help='the instances folder of images definition')
        args = parser.parse_args(sys.argv[2:])
        dump = not args.nodump

        print('Running version creation ...')
        _create_version(
            instance_folder=args.instance_folder,
            version=args.version,
            component=args.component,
            dump=dump,
            releasemeta=args.releasemeta,
            oemname=args.oemname
        )

    def genoem(self):
        parser = argparse.ArgumentParser(description='Create an OEM release')
        parser.add_argument('-o', '--oemname', required=True, help='an oem name')
        parser.add_argument('--releasemeta', help='the releases_meta.yml file')
        parser.add_argument('--nodump', action='store_false', help='if dumpping update')
        parser.add_argument('instance_folder', help='the instances folder of images definition')
        args = parser.parse_args(sys.argv[2:])
        dump = not args.nodump

        print('Running OEM creation, oemname=%s ...' % args.oemname)
        _create_oem(
            instance_folder=args.instance_folder,
            oemname=args.oemname,
            dump=dump,
            releasemeta=args.releasemeta
        )


def _validate_instances(instance_folder, releasemeta=None, component=None, dump=True, oemname=None):
    verminator_config.set_oem(oemname)
    p = Path(instance_folder)
    assert p.is_dir()
    print('Validating versioned instances against release meta')
    if releasemeta is not None:
        releasemeta = Path(releasemeta)
    else:
        releasemeta = p.joinpath('releases_meta.yaml')
    assert releasemeta.is_file()
    meta = ProductReleaseMeta(releasemeta)
    component_found = False
    for instance_path in p.iterdir():
        if not instance_path.is_dir():
            continue
        if component is not None:
            if instance_path.name != component:
                continue
            else:
                component_found = True
        instance = Instance(instance_path.name, instance_path)
        for ver, versioned_ins in instance.versioned_instances.items():
            print(instance_path.joinpath(ver))
            versioned_ins.validate(meta)

        if not dump:
            instance.dump()

    if component is not None and not component_found:
        raise ValueError('Component %s not found in folder %s' % (component, instance_folder))

    print('Validating release dependencies (originally from product-meta testing')
    from verminator.validate_release_dep import scan_instances, validate_dependence_versions
    scan_instances(p)
    validate_dependence_versions()


def _create_version(instance_folder, version, component=None, dump=True, releasemeta=None, oemname=None):
    verminator_config.set_oem(oemname)
    product = product_name(version)
    p = Path(instance_folder)
    assert p.is_dir()

    # Load release metadata
    if releasemeta is not None:
        releasemeta = Path(releasemeta)
    else:
        releasemeta = p.joinpath('releases_meta.yaml')
    assert releasemeta.is_file()
    meta = ProductReleaseMeta(releasemeta)

    # Get declared tdc version range from release meta
    tdc_vrange = meta.get_tdc_version_range(version)
    if tdc_vrange is None:
        raise ValueError('Version %s should be declared in releasemeta first' % version)

    component_found = False
    for instance_path in p.iterdir():
        if not instance_path.is_dir():
            continue

        if component is not None:
            if instance_path.name != component:
                continue
            else:
                component_found = True

        instance = Instance(instance_path.name, instance_path)
        has_version_for_product = False

        for ver, ins in instance.versioned_instances.items():
            if ins.find_latest_release(product):
                has_version_for_product = True

        if has_version_for_product:
            print('Creating release {} for {}'.format(version, instance.instance_type))
            instance.create_release(version)

        if not dump:
            instance.dump()

    if component is not None and not component_found:
        raise ValueError('Component %s not found in folder %s' % (component, instance_folder))


def _create_oem(instance_folder, oemname, dump=True, releasemeta=None):
    verminator_config.set_oem(oemname)
    p = Path(instance_folder)
    assert p.is_dir()
    for instance_path in p.iterdir():
        if not instance_path.is_dir():
            continue
        instance = Instance(instance_path.name, instance_path)
        for ver, versioned_ins in instance.versioned_instances.items():
            print(instance_path.joinpath(ver))
            versioned_ins.convert_oem()
        if not dump:
            instance.dump()


if __name__ == '__main__':
    VerminatorCmd()
