import configparser
import argparse
import sys
import logging

from hwtest.component import *
from hwtest.formatter import *


def main():
    all_components = [Framebuffer,
                      Drm,
                      Camera,
                      Magnetometer,
                      Accelerometer,
                      Gyroscope,
                      Temperature,
                      Proximity,
                      Illuminance,
                      Pressure,
                      Input,
                      Modem,
                      Audio,
                      Led]

    names = []
    for c in all_components:
        names.append(c.__name__)
    names = ', '.join(names)

    parser = argparse.ArgumentParser()
    parser.add_argument('--interactive', '-i', help='Enable the tests that require user interaction',
                        action='store_true')
    parser.add_argument('--export', help='Export test results to a file for verifying newer builds',
                        type=argparse.FileType('w'))
    parser.add_argument('--verify', help='Compare test results with an older export', type=argparse.FileType('r'))
    parser.add_argument('--skip', help='Skip a component, can be specified multiple times. Options: {}'.format(names),
                        action='append')
    parser.add_argument('--verbose', help='Enable debugging output', action='store_true')
    parser.add_argument('--formatter', default='ShellTable',
                        help='Output formattere for stdout. Options: ShellTable, MarkdownTable, MediaWikiTable')
    args = parser.parse_args()

    if args.verbose:
        logging.basicConfig(level=logging.DEBUG)
    logging.debug('Enabled debug logging')

    components = []
    skipped = []
    instances = {}
    for c in all_components:
        if args.skip is not None and c.__name__ in args.skip:
            skipped.append(c.__name__)
        else:
            components.append(c)

    if args.export is not None:
        export = configparser.ConfigParser(allow_no_value=True)
        export.add_section('hwtest')
        export.set('hwtest', 'export-version', '1')
        export.set('hwtest', 'interactive', 'yes' if args.interactive else 'no')
        if len(skipped) > 0:
            export.set('hwtest', 'skipped', ','.join(skipped))

    if args.verify is not None:
        verify = configparser.ConfigParser(strict=False)
        verify.read_file(args.verify)

        verify_result = {
            'added': [],
            'fixed': [],
            'broken': [],
            'same': []
        }
        existing = set()

    for c in components:
        instance = c()
        if args.interactive:
            instance.interactive()
        instances[c] = instance

    formatter_class = '{}Formatter'.format(args.formatter)
    if formatter_class not in globals():
        print('Formatter {} does not exist'.format(args.formatter))
        exit(1)
    formatter = globals()[formatter_class]()

    if args.verify is None:
        formatter.start()

    for c in components:
        instance = instances[c]
        for result in instance.test():

            if args.export is not None:
                if not export.has_section(result.category):
                    export.add_section(result.category)
                export.set(result.category, '; {}'.format(result.path))
                export.set(result.category, result.model, str(result.status))

            if args.verify is not None:
                state = 'same'
                if not verify.has_section(result.category) or not verify.has_option(result.category, result.model):
                    state = 'added'
                else:
                    old = verify.get(result.category, result.model) == str(True)
                    if old == result.status:
                        state = 'same'
                    elif result.status:
                        state = 'fixed'
                    else:
                        state = 'broken'

                verify_result[state].append(result)
                existing.add('{}.{}'.format(result.category.lower(), result.model.lower()))

            else:
                formatter.result(result)

    formatter.finish()

    if args.export is not None:
        export.write(args.export)

    if args.verify is not None:
        old_existing = set()
        for section in verify.sections():
            if not section == 'hwtest':
                for option in verify.options(section):
                    old_existing.add('{}.{}'.format(section, option))
        removed = old_existing - existing

        formatter.diff(verify_result['added'], removed, verify_result['fixed'], verify_result['broken'])

        if len(verify_result['broken']) > 0 or len(removed) > 0:
            sys.exit(1)


if __name__ == '__main__':
    main()
