#!/usr/bin/env python
from __future__ import print_function
from subprocess import Popen, STDOUT
from threading import Thread
import atexit
import os
import sys
import termios
import json
import yaml
import textwrap

from pmake.gossi import Logger, Msg


LOGGER = Logger()

def which(file):
    for path in os.environ["PATH"].split(os.pathsep):
        if os.path.exists(os.path.join(path, file)):
                return os.path.join(path, file)

    return None

def enable_echo(enable):
    fd = sys.stdin.fileno()
    new = termios.tcgetattr(fd)
    if enable:
        new[3] |= termios.ECHO
    else:
        new[3] &= ~termios.ECHO

    termios.tcsetattr(fd, termios.TCSANOW, new)


def follow_task(tag, root, build_task):
    build_opts = {}
    if 'require' in build_task.keys():
        requirements = build_task['require']
        for req in requirements.keys():
            for opt in requirements[req]['opt']:
                if which(opt) != None:
                    build_opts[req] = opt
                    break
            if req not in build_opts.keys():
                LOGGER.log(Msg(tag, 'Failed - {err_msg}'.format(**build_task), msg_color='red'), tag_id=tag)
                return

    for cmd in build_task['run']:
        os.makedirs(os.path.dirname(build_task['log_file']), exist_ok=True)
        with open(os.path.join('.', build_task['log_file']), 'w+') as logfile:
            work_dir = '.' if 'path' not in build_task.keys() else os.path.join(root, build_task['path'])
            process = Popen(cmd['cmd'].format(**build_opts).split(), stderr=STDOUT, stdout=logfile, cwd=work_dir)
            LOGGER.wait(tag, Msg(tag, cmd['msg']), process)
            process.wait()
            if process.returncode != 0:
                err = 'Exited with nonzero code: {}'.format(process.returncode)
                LOGGER.log(Msg(tag, err, msg_color='red'), tag_id=tag)
                break
    LOGGER.log(Msg(tag, 'Done.', msg_color='green'), tag_id=tag)


def spawn(task, tag, root):
    LOGGER.tag(tag).log(Msg(tag, 'Beginning build...'), tag_id=tag)
    t = Thread(target=follow_task, args=[tag, root, task])
    t.start()
    return t


def build(config):
    root = os.getcwd()

    LOGGER.log(Msg('system', 'Starting Build:'))
    LOGGER.log(Msg('system', '---------------'))

    build_phases = config['phases']
    tasks = config['tasks']

    # Run build phases in order
    for build_phase in build_phases:

        awaiting = []

        # Launch all build phase instructions
        for instruction in build_phase:
            awaiting += [spawn(tasks[instruction['task']], instruction['tag'], root)]

        # Wait for all instructions to finish
        for process in awaiting:
            process.join()

    LOGGER.log(Msg('system', '---------------'))
    LOGGER.log(Msg('system', 'Build Completed.'))


# always run
atexit.register(enable_echo, True)
enable_echo(False)

# Run when main
if __name__ == '__main__':
    assert sys.version_info >= (3, 2), 'PMake requires Python > 3.2'
    args = {}
    if len(sys.argv) == 1:
        if (os.path.exists('pmake.json')):
            with open(os.path.join(os.getcwd(), 'pmake.json')) as cfg:
                args = json.load(cfg.read())
                print('Loaded from JSON config file')
        elif (os.path.exists('pmake.yml')):
            with open(os.path.join(os.getcwd(), 'pmake.yml')) as cfg:
                args = yaml.load(cfg.read())
                print('Loaded from YAML config file')
        else:
            print('PMake config not found in local directory')
            sys.exit(1)
        build(args)
    else:
        if sys.argv[1] == 'init':
            with open(os.path.join(os.getcwd(), 'pmake.yml'), 'w+') as pmake_file:
                pmake_file.write(textwrap.dedent('''
                phases:
                tasks:
                '''))
        else:
            print('Unknown Pmake command')
