#!/usr/bin/env python
from __future__ import print_function

import os
import re
import sys
import glob
from fnmatch import fnmatch
from itertools import ifilter
from os.path import join as pathjoin, relpath, dirname, \
                    abspath, basename, splitext, sep as pathsep


HERE = dirname(abspath(__file__))
FLEXUNIT = pathjoin('$(HOME)', '.local', 'share', 'flexunit')
AUTOGEN_WARNING = ('# ******** AUTOGENERATED by {0} ' +
                   ('*' * 20)).format(basename(sys.argv[0]))
DEP_SEP = ' \\\n            '
RULE_SEP = '\n\n'
TARGET_FMT = '{target}:' + DEP_SEP + '{deps}'
RULE_FMT = '\\\n\t'.join([
    '\t$(MXMLC) {primary_dep} ',
    '$(MXMLC_FLAGS) ',
    '-l+={parent_dir} ',
    '-l+={package_base} ',
    '-l+={flexunit} ',
    '-sp+={package_base} ',
    '-sp+={flexunit} ',
    '-o {target}',
])


def main(sysargs=sys.argv[:]):
    targets_mk = pathjoin(HERE, 'targets.mk')
    os.chmod(targets_mk, 0600)
    targetmaker = TargetMaker(outstream=open(targets_mk, 'wb'))
    targetmaker.make()
    os.chmod(targets_mk, 0444)
    return 0


class TargetMaker(object):
    _to_glob = (
        pathjoin(HERE, '[0-9]*-*', '*.mxml'),
        pathjoin(HERE, 'custom-*', '*.mxml'),
    )
    _source_fileexts = ('.mxml', '.as', '.css')

    def __init__(self, outstream=sys.stdout):
        self.outstream = outstream
        self.targets = {}

    def make(self):
        self._glob_for_top_level_mxml_targets()
        self._find_test_suite_targets()
        self._write_out_targets()

    def _glob_for_top_level_mxml_targets(self):
        for pattern in self._to_glob:
            for mxml in glob.glob(pattern):
                self._add_target_from_mxml(mxml)

    def _find_test_suite_targets(self):
        for dirpath, dirnames, filenames in os.walk(HERE):
            filter_generated_dirs(dirnames)
            for filename in filenames:
                if is_test_suite(filename):
                    test_suite = pathjoin(dirpath, filename)
                    self._add_target_from_test_suite(test_suite)

    def _add_target_from_test_suite(self, test_suite):
        rel_class = relpath(test_suite, HERE)
        as_swf = re.sub('(.*)\.as$', '\\1.swf', rel_class)
        self.targets[as_swf] = set([rel_class])

    def _add_target_from_mxml(self, mxml):
        rel_mxml = relpath(mxml, HERE)
        as_swf = re.sub('(.*)\.mxml$', '\\1.swf', rel_mxml)
        self.targets[as_swf] = set([rel_mxml])
        self._add_deps_from_alt_source_file_extensions(as_swf, rel_mxml)

    def _add_deps_from_alt_source_file_extensions(self, as_swf, rel_mxml):
        basedir = dirname(rel_mxml)
        for dirpath, dirnames, filenames in os.walk(basedir):
            filter_generated_dirs(dirnames)
            filter_test_suitees(filenames)
            for filename in filenames:
                if ext(filename) in self._source_fileexts:
                    rel_source = relpath(pathjoin(dirpath, filename), HERE)
                    self.targets[as_swf].add(rel_source)

    def _write_out_targets(self):
        print(AUTOGEN_WARNING, file=self.outstream)
        for target in sorted(self.targets.iterkeys()):
            deps = self._get_deps_for_target(target)
            primary_dep = self._get_primary_dep(target, deps)
            pattern_rule_kwargs = \
                self._get_pattern_rule_kwargs(primary_dep, target)

            rel_target = './' + target.lstrip('./')
            print(TARGET_FMT.format(target=rel_target,
                    deps=DEP_SEP.join(deps),
                ), file=self.outstream
            )
            print(RULE_FMT.format(**pattern_rule_kwargs) +
                  RULE_SEP, file=self.outstream
            )

    def _get_deps_for_target(self, target):
        deps = []
        for dep in reversed(sorted(list(self.targets[target]), key=ext)):
            deps.append(dep)
        return deps

    def _get_primary_dep(self, target, deps):
        primary_dep = deps[0]

        for dependency in deps:
            if fnmatch(target, namebase(dependency) + '.*'):
                primary_dep = dependency

        return primary_dep

    def _get_pattern_rule_kwargs(self, primary_dep, target):
        ret = dict(
            primary_dep=primary_dep,
            parent_dir=dirname(primary_dep),
            package_base=primary_dep.strip('./').split(pathsep)[0],
            target=target,
            flexunit=FLEXUNIT
        )
        return ret


def ext(filename):
    return splitext(filename)[-1]


def namebase(filename):
    return splitext(filename)[0]


def filter_generated_dirs(dirnames):
    for i, directory in enumerate(dirnames[:]):
        if directory == 'generated':
            dirnames[i] = None
    dirnames[:] = list(ifilter(None, dirnames))


def filter_test_suitees(filenames):
    for i, filename in enumerate(filenames[:]):
        if is_test_suite(filename):
            filenames[i] = None
    filenames[:] = list(ifilter(None, filenames))


def is_test_suite(filename):
    base_filename = basename(filename)
    return base_filename.startswith('TestSuite') and \
        ext(filename) == '.as'


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

# vim:filetype=python
