#!/usr/bin/env python

from cStringIO import StringIO
import json
import yaml
import subprocess
import select
import fcntl
import os
from termcolor import colored
import signal
import itertools

ColorFactory = itertools.cycle([
'white',                     
'green',
'yellow',
'blue',
'magenta',
'cyan',
])

class Subprocess():
    def __init__(self, name, cmdline):
        self.name = name
        self.cmdline = cmdline
        self.p = None
        self.color = ColorFactory.next()
        self.restart()
        
    @property
    def stdout(self):
        return self.p.stdout

    @property
    def stderr(self):
        return self.p.stderr
    
    def read_stdout(self):
        self.stdout_buf += self.stdout.read()
        
        while '\n' in self.stdout_buf:
            line, self.stdout_buf = self.stdout_buf.split('\n', 1)
            self.print_line(line)

    def read_stderr(self):
        self.stderr_buf += self.stderr.read()
        
        while '\n' in self.stderr_buf:
            line, self.stderr_buf = self.stderr_buf.split('\n', 1)
            self.print_line(line)
            
    def restart(self):
        self.stdout_buf = ''
        
        self.stderr_buf = ''
        if self.p and self.p.poll() is None:
            self.p.terminate()
            self.p.wait()
        self.p = subprocess.Popen(self.cmdline, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
               
        fd = self.p.stdout.fileno()
        fl = fcntl.fcntl(fd, fcntl.F_GETFL)
        fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)                

        fd = self.p.stderr.fileno()
        fl = fcntl.fcntl(fd, fcntl.F_GETFL)
        fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)                

    def print_line(self, l):
        print colored('%s:' % self.name, self.color, attrs=['bold']),
        print colored(l, self.color)

    def __unicode__(self):
        return self.name
    
    def __repr__(self):
        return 'Subprocess(%r)' % self.name


def manage_subprocesses(proclist):
    time_to_quit = {'status': False}
    
    def sigint(signal, frame):
        print colored('Got sigint. Terminating processes...', 'red')
        time_to_quit['status'] = True
        
    old_sigint = signal.signal(signal.SIGINT, sigint)
    
    while not time_to_quit['status']:
        try:
            file_map = {}
            for p in proclist:
                file_map[p.stdout] = p.read_stdout
                file_map[p.stderr] = p.read_stderr
            
            rlist, _, _ = select.select(file_map.keys(), [], [], 2)
    
            for f in rlist:
                file_map[f]()
                
            for p in proclist:
                if p.p.poll() is not None:
                    print colored('%s finished with %d. Restarting...' % (p.name, p.p.poll()), 'red')
                    p.restart()
        except select.error:
            continue
    signal.signal(signal.SIGINT, old_sigint)
    
    for p in proclist:
        p.p.terminate()
    for p in proclist:
        p.p.wait()
        
    print colored('Done.', 'red')
        

with open('Henfile', 'rt') as f:
    #henfile = json.load(f)
    henfile = yaml.load(f)


env = henfile.get('env')
if env:
    os.environ.update(env)

import sys
sys.stdout.write("\x1b]2;%s\x07" % henfile['name'])
processes = [Subprocess(key, cmd) for key, cmd in henfile['proc'].items()]
manage_subprocesses(processes)
