"""
Requires the ``watchdog`` package.

Watch the current directory and its children for changes to files, and run ``make`` when certain files are changed.

Can be configured by a .watchmakerc file, containing settings in YAML format:

    path = <the path to watch for changes> (default: .)
    default_make: <a list of `make` targets to run> (default: empty list, so the first target in the Makefile)
    extensions: <a list of file extensions that should trigger a ``make`` run> (default: '.js')
"""

from datetime import datetime
import os
import subprocess
import sys
import time
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
import yaml
from pathlib import Path

class MakeHandler(FileSystemEventHandler):

    last_time = None
    gap = 2

    def __init__(self,command,config):
        self.command = command
        self.config = config
        roots = self.config['path']
        self.roots = [Path(root) for root in roots]
        super(FileSystemEventHandler,self).__init__()

    def on_modified(self, event):
        if not event.is_directory:
            t = datetime.now()
            src_path = Path(event.src_path).resolve()
            if self.config['extensions'] is None or src_path.suffix in self.config['extensions']:
                for root in self.roots:
                    if src_path.is_relative_to(root.resolve()):
                        print('{} modified at {}'.format(root / src_path.relative_to(root.resolve()),t))
                if self.last_time is None or (t-self.last_time).seconds>self.gap:
                    self.run()
                self.last_time = t

    def run(self):
        subprocess.call(self.command)

class WatchMaker(object):

    def __init__(self,rootpath):
        self.rootpath = rootpath
        config = {
            'path': '.',
            'default_make': [],
            'extensions': ['.js'],
        }

        try:
            with open(rootpath / '.watchmakerc') as f:
                config.update(yaml.load(f.read(),Loader=yaml.SafeLoader))
        except IOError:
            pass

        self.config = config

    def run(self,targets=None):
        paths = self.config.get('path','.')
        if isinstance(paths,str):
            paths = [paths]
        paths = [self.rootpath / p for p in paths]
        paths = [p for p in paths if os.path.exists(p)]

        print("Watching {}".format(', '.join(str(p) for p in paths)))

        command = ['make']+(targets if targets else self.config['default_make'])

        event_handler = MakeHandler(command,self.config)
        event_handler.run()

        observer = Observer()
        for path in paths:
            observer.schedule(event_handler,str(path),recursive=True)
        observer.start()

        try:
            while True:
                time.sleep(1)
        except KeyboardInterrupt:
            observer.stop()

        observer.join()
