#!/bin/python
import argparse
import hashlib
import json
import logging
import os
import sys


def cleanup_json(data):
    """Cleans up the json structure by removing empty "", and empty key value
    pairs."""
    if (isinstance(data, unicode)):
        copy = data.strip()
        return None if len(copy) == 0 else copy

    if (isinstance(data, dict)):
        copy = {}
        for key, value in data.iteritems():
            rem = cleanup_json(value)
            if (rem is not None):
                copy[key] = rem
        return None if len(copy) == 0 else copy

    if (isinstance(data, list)):
        copy = []
        for elem in data:
            rem = cleanup_json(elem)
            if (rem is not None):
                if rem not in copy:
                    copy.append(rem)

        if len(copy) == 0:
            return None
        return copy


class AttrDict(dict):
    def __init__(self, *args, **kwargs):
        super(AttrDict, self).__init__(*args, **kwargs)
        self.__dict__ = self

    def as_list(self, name):
        v = self.get(name, [])
        if (isinstance(v, list)):
            return v

        return [v]


def remove_lib_prefix(module):
    """Removes the lib prefix, as we are not using them in CMake."""
    if module.startswith('lib'):
        return module[3:]
    else:
        return module


def escape(msg):
    """Escapes the "."""
    return '"' + msg.replace('"', '\\"') + '"'


def header():
    """The auto generate header."""
    return [
        '# This is an autogenerated file! Do not edit!',
        '# instead run make from .../device/generic/goldfish-opengl',
        '# which will re-generate this file.'
    ]


def checksum(fname):
    """Calculates a SHA256 digest of the given file name."""
    m = hashlib.sha256()
    with open(fname, 'r') as mk:
        m.update(mk.read())
    return m.hexdigest()


def generate_module(module):
    """Generates a cmake module."""
    name = remove_lib_prefix(module['module'])
    make = header()
    mkfile = os.path.join(module['path'], 'Android.mk')
    sha256 = checksum(mkfile)
    make.append(
        'android_validate_sha256("${GOLDFISH_DEVICE_ROOT}/%s" "%s")' % (mkfile, sha256))
    make.append('set(%s_src %s)' % (name, ' '.join(module['src'])))
    if module['type'] == 'SHARED_LIBRARY':
        make.append('android_add_shared_library(%s)' % name)
    elif module['type'] == 'STATIC_LIBRARY':
        make.append('android_add_library(%s)' % name)
    else:
        raise ValueError('Unexpected module type: %s' % module['type'])

    # Fix up the includes.
    includes = ['${GOLDFISH_DEVICE_ROOT}/' + s for s in module['includes']]
    make.append('target_include_directories(%s PRIVATE %s)' %
                (name, ' '.join(includes)))

    # filter out definitions
    defs = [escape(d) for d in module['cflags'] if d.startswith('-D')]

    #  And the remaining flags.
    flags = [escape(d) for d in module['cflags'] if not d.startswith('-D')]

    # Make sure we remove the lib prefix from all our dependencies.
    libs = [remove_lib_prefix(l) for l in module['libs']]
    staticlibs = [remove_lib_prefix(l) for l in
                      module.get('staticlibs', [])
                      if l != "libandroidemu"]

    # Configure the target.
    make.append('target_compile_definitions(%s PRIVATE %s)' %
                (name, ' '.join(defs)))
    make.append('target_compile_options(%s PRIVATE %s)' %
                (name, ' '.join(flags)))

    if len(staticlibs) > 0:
        make.append('target_link_libraries(%s PRIVATE %s PRIVATE %s)' %
                    (name, ' '.join(libs), " ".join(staticlibs)))
    else:
        make.append('target_link_libraries(%s PRIVATE %s)' %
                    (name, ' '.join(libs)))
    return make


def main(argv=None):
    parser = argparse.ArgumentParser(
        description='Generates a set of cmake files'
        'based up the js representation.'
        'Use this to generate cmake files that can be consumed by the emulator build')
    parser.add_argument('-i', '--input', dest='input', type=str, required=True,
                        help='json file containing the build tree')
    parser.add_argument('-v', '--verbose',
                        action='store_const', dest='loglevel',
                        const=logging.INFO, default=logging.ERROR,
                        help='Log what is happening')
    parser.add_argument('-o', '--output',
                        dest='outdir', type=str, default=None,
                        help='Output directory for create CMakefile.txt')
    parser.add_argument('-c', '--clean', dest='output', type=str,
                        default=None,
                        help='Write out the cleaned up js')
    args = parser.parse_args()

    logging.basicConfig(level=args.loglevel)

    with open(args.input) as data_file:
        data = json.load(data_file)

    modules = cleanup_json(data)

    # Write out cleaned up json, mainly useful for debugging etc.
    if (args.output is not None):
        with open(args.output, 'w') as out_file:
            out_file.write(json.dumps(modules, indent=2))

    # Location --> CMakeLists.txt
    cmake = {}

    # The root, it will basically just include all the generated files.
    root = os.path.join(args.outdir, 'CMakeLists.txt')
    mkfile = os.path.join(args.outdir, 'Android.mk')
    sha256 = checksum(mkfile)
    cmake[root] = header()
    cmake[root].append('set(GOLDFISH_DEVICE_ROOT ${CMAKE_CURRENT_SOURCE_DIR})')
    cmake[root].append(
        'android_validate_sha256("${GOLDFISH_DEVICE_ROOT}/%s" "%s")' % (mkfile, sha256))

    # Generate the modules.
    for module in modules:
        location = os.path.join(args.outdir, module['path'], 'CMakeLists.txt')

        # Make sure we handle the case where we have >2 modules in the same dir.
        if location not in cmake:
            cmake[root].append('add_subdirectory(%s)' % module['path'])
            cmake[location] = []
        cmake[location].extend(generate_module(module))

    # Write them to disk.
    for (loc, cmklist) in cmake.iteritems():
        logging.info('Writing to %s', loc)
        with open(loc, 'w') as fn:
            fn.write('\n'.join(cmklist))


if __name__ == '__main__':
    sys.exit(main())
