#    Copyright (C) 2012-2013 Yahoo! Inc. All Rights Reserved.
#
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
#    not use this file except in compliance with the License. You may obtain
#    a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License.

import logging
import os
import sys

logging.basicConfig(level=logging.ERROR)

top_dir = os.path.abspath(
    os.path.join(os.path.dirname(__file__), os.pardir, os.pardir)
)
sys.path.insert(0, top_dir)

import taskflow.engines
from taskflow.patterns import graph_flow as gf
from taskflow import task

import example_utils as eu  # noqa


# In this example we demonstrate use of a target flow (a flow that only
# executes up to a specified target) to make an *oversimplified* pseudo
# build system. It pretends to compile all sources to object files and
# link them into an executable. It also can build docs, but this can be
# "switched off" via targeted flow special power -- ability to ignore
# all tasks not needed by its target.


class CompileTask(task.Task):
    """Pretends to take a source and make object file."""

    default_provides = 'object_filename'

    def execute(self, source_filename):
        object_filename = '%s.o' % os.path.splitext(source_filename)[0]
        print('Compiling %s into %s' % (source_filename, object_filename))
        return object_filename


class LinkTask(task.Task):
    """Pretends to link executable form several object files."""

    default_provides = 'executable'

    def __init__(self, executable_path, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._executable_path = executable_path

    def execute(self, **kwargs):
        object_filenames = list(kwargs.values())
        print(
            'Linking executable %s from files %s'
            % (self._executable_path, ', '.join(object_filenames))
        )
        return self._executable_path


class BuildDocsTask(task.Task):
    """Pretends to build docs from sources."""

    default_provides = 'docs'

    def execute(self, **kwargs):
        for source_filename in kwargs.values():
            print("Building docs for %s" % source_filename)
        return 'docs'


def make_flow_and_store(source_files, executable_only=False):
    flow = gf.TargetedFlow('build-flow')
    object_targets = []
    store = {}
    for source in source_files:
        source_stored = '%s-source' % source
        object_stored = '%s-object' % source
        store[source_stored] = source
        object_targets.append(object_stored)
        flow.add(
            CompileTask(
                name='compile-%s' % source,
                rebind={'source_filename': source_stored},
                provides=object_stored,
            )
        )
    flow.add(BuildDocsTask(requires=list(store.keys())))

    # Try this to see executable_only switch broken:
    object_targets.append('docs')
    link_task = LinkTask('build/executable', requires=object_targets)
    flow.add(link_task)
    if executable_only:
        flow.set_target(link_task)
    return flow, store


if __name__ == "__main__":
    SOURCE_FILES = ['first.c', 'second.cpp', 'main.cpp']
    eu.print_wrapped('Running all tasks:')
    flow, store = make_flow_and_store(SOURCE_FILES)
    taskflow.engines.run(flow, store=store)

    eu.print_wrapped('Building executable, no docs:')
    flow, store = make_flow_and_store(SOURCE_FILES, executable_only=True)
    taskflow.engines.run(flow, store=store)
