import json
import time
import os
import logging

from multiprocessing import Process, Lock, Queue as mpQueue

# For RabbitMQ
from kombu.connection import BrokerConnection
from kombu.messaging import Exchange, Queue, Consumer, Producer

import pyinotify
from pyinotify import WatchManager, Notifier, ProcessEvent

from api_clients import api_client
from airtimemetadata import AirtimeMetadata

class AirtimeNotifier(Notifier):

    def __init__(self, watch_manager, default_proc_fun=None, read_freq=0, threshold=0, timeout=None, airtime_config=None):
        Notifier.__init__(self, watch_manager, default_proc_fun, read_freq, threshold, timeout)

        self.logger = logging.getLogger()
        self.config = airtime_config
        self.api_client = api_client.api_client_factory(self.config.cfg)
        self.md_manager = AirtimeMetadata()
        self.import_processes = {}
        self.watched_folders = []

        schedule_exchange = Exchange("airtime-media-monitor", "direct", durable=True, auto_delete=True)
        schedule_queue = Queue("media-monitor", exchange=schedule_exchange, key="filesystem")
        self.connection = BrokerConnection(self.config.cfg["rabbitmq_host"], self.config.cfg["rabbitmq_user"], self.config.cfg["rabbitmq_password"], "/")
        channel = self.connection.channel()
        consumer = Consumer(channel, schedule_queue)
        consumer.register_callback(self.handle_message)
        consumer.consume()

    def handle_message(self, body, message):
        # ACK the message to take it off the queue
        message.ack()

        self.logger.info("Received md from RabbitMQ: " + body)
        m =  json.loads(message.body)

        if m['event_type'] == "md_update":
            self.logger.info("AIRTIME NOTIFIER md update event")
            self.md_manager.save_md_to_file(m)

        elif m['event_type'] == "new_watch":
            self.logger.info("AIRTIME NOTIFIER add watched folder event " + m['directory'])
            #start a new process to walk through this folder and add the files to Airtime.
            p = Process(target=self.walk_newly_watched_directory, args=(m['directory'],))
            p.start()
            self.import_processes[m['directory']] = p
            #add this new folder to our list of watched folders
            self.watched_folders.append(m['directory'])

        elif m['event_type'] == "remove_watch":
            watched_directory = m['directory'].encode('utf-8')

            mm = self.proc_fun()
            wd = mm.wm.get_wd(watched_directory)
            self.logger.info("Removing watch on: %s wd %s", watched_directory, wd)
            mm.wm.rm_watch(wd, rec=True)

        elif m['event_type'] == "change_stor":
            storage_directory = self.config.storage_directory
            new_storage_directory = m['directory'].encode('utf-8')

            mm = self.proc_fun()

            wd = mm.wm.get_wd(storage_directory)
            self.logger.info("Removing watch on: %s wd %s", storage_directory, wd)
            mm.wm.rm_watch(wd, rec=True)

            mm.set_needed_file_permissions(new_storage_directory, True)
            mm.move_file(storage_directory, new_storage_directory)
            self.config.storage_directory = new_storage_directory

            mm.watch_directory(new_storage_directory)


    def update_airtime(self, d):

        filepath = d['filepath']
        mode = d['mode']

        md = {}
        md['MDATA_KEY_FILEPATH'] = filepath

        if 'data' in d:
            file_md = d['data']
            md.update(file_md)
        else:
            file_md = None
            data = None


        if (os.path.exists(filepath) and (mode == self.config.MODE_CREATE)):
            if file_md is None:
                mutagen = self.md_manager.get_md_from_file(filepath)
                md.update(mutagen)

            if d['is_recorded_show']:
                self.api_client.update_media_metadata(md, mode, True)
            else:
                self.api_client.update_media_metadata(md, mode)

        elif (os.path.exists(filepath) and (mode == self.config.MODE_MODIFY)):
            mutagen = self.md_manager.get_md_from_file(filepath)
            md.update(mutagen)
            self.api_client.update_media_metadata(md, mode)

        elif (mode == self.config.MODE_MOVED):
            md['MDATA_KEY_MD5'] = self.md_manager.get_md5(filepath)
            self.api_client.update_media_metadata(md, mode)

        elif (mode == self.config.MODE_DELETE):
            self.api_client.update_media_metadata(md, mode)


    def process_file_events(self, queue):

        while True:
            event = queue.get()
            self.logger.info("received event %s", event);
            self.update_airtime(event)

    def walk_newly_watched_directory(self, directory):

        mm = self.proc_fun()

        for (path, dirs, files) in os.walk(directory):
            for filename in files:
                full_filepath = path+"/"+filename

                if mm.is_audio_file(full_filepath):
                    self.update_airtime({'filepath': full_filepath, 'mode': self.config.MODE_CREATE})