#!/usr/bin/python3.6 -s
# GPL. (C) 2014 Paolo Patruno.

# This program is free software; you can redistribute it and/or modify 
# it under the terms of the GNU General Public License as published by 
# the Free Software Foundation; either version 2 of the License, or 
# (at your option) any later version. 
# 
# This program is distributed in the hope that it will be useful, 
# but WITHOUT ANY WARRANTY; without even the implied warranty of 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
# GNU General Public License for more details. 
# 
# You should have received a copy of the GNU General Public License 
# along with this program; if not, write to the Free Software 
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
# 

import os
import dballe,io
os.environ['DJANGO_SETTINGS_MODULE'] = 'rmap.settings'
import django
django.setup()

from rmap import daemon
import rmap.settings
import threading
import signal
import logging,traceback,time
from rmap.rmap_core import amqpConsumerProducer

amqp2amqp_jsonline2bufr = daemon.Daemon(
        stdin="/dev/null",
        stdout=rmap.settings.logfileamqp2amqp_jsonline2bufrd,
        stderr=rmap.settings.errfileamqp2amqp_jsonline2bufrd,
        pidfile=rmap.settings.lockfileamqp2amqp_jsonline2bufrd,
        user=rmap.settings.useramqp2amqp_jsonline2bufrd,
        group=rmap.settings.groupamqp2amqp_jsonline2bufrd
)


# catch signal to terminate the process
class GracefulKiller:
    kill_now = False
    def __init__(self):
        signal.signal(signal.SIGINT, self.exit_gracefully)
        signal.signal(signal.SIGTERM, self.exit_gracefully)

    def exit_gracefully(self,signum, frame):
        self.kill_now = True

    def keyboard_interrupt(self):
        self.kill_now = True

    def terminate(self):
        self.kill_now = True

def jsonline2bufr(amqp,basic_deliver, properties, body):

    logging.debug(" [x] Received message")
        
    bodyfile = io.BytesIO(body) 
    importer = dballe.Importer("JSON",domain_errors="clamp")
    exporter = dballe.Exporter("BUFR")
    outbufr=b""
    with importer.from_file(bodyfile) as f:
        for msg in f:
            outbufr+=exporter.to_binary(msg)
                
    if (outbufr == b""):
        logging.debug("skip empty output message")
        if (amqp.receive_queue is not None):
            amqp.receive_queue.put_nowait(Message(True,basic_deliver.delivery_tag))
        else:
            amqp.acknowledge_message(basic_deliver.delivery_tag)
    else:

        # Send a message
        if (amqp.send_queue is not None):
            amqp.send_queue.put_nowait(Message(outbufr,basic_deliver.delivery_tag))
        else:                    
            if ( amqp.publish(outbufr,[basic_deliver.delivery_tag])):
                logging.debug('message sended')
                logging.info(" [x] Done")
            else:
                logging.info(" [ ] NOT Done")
                logging.error('message not sended')
                amqp.reject_message(basic_deliver.delivery_tag)


def main(self):

    #arm the signal handler
    killer = GracefulKiller()

    # configure the logger
    formatter=logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s",datefmt="%Y-%m-%d %H:%M:%S")
    handler = logging.handlers.RotatingFileHandler(self.options.stdout, maxBytes=5000000, backupCount=10)
    handler.setFormatter(formatter)
    
    # Add the log message handler to the root logger
    logging.getLogger().addHandler(handler)
    logging.getLogger().setLevel(logging.INFO)

    logging.info('Starting up mqtt2amqpd')

    #send_queue = queue.Queue(maxsize=100)

    user=rmap.settings.amqpuser
    password=rmap.settings.amqppassword
    host=rmap.settings.amqphost
    inqueue="..jsonline.report_fixed"
    outexchange="..bufr.report_fixed"

    
    amqp=amqpConsumerProducer(host,inqueue,outexchange,user,password,pipefunction=jsonline2bufr)
    amqp.start()
    
    # infinite loop
    while True:
        try:
            time.sleep(3) # do nothing
        except Exception as exception:
            logging.error('Exception occured: ' + str(exception))
            logging.error(traceback.format_exc())
            killer.terminate()
            
        # terminate on keyboard interrupt
        except KeyboardInterrupt:
            sys.stdout.write("keyboard interrupt\n")
            logging.info("keyboard interrupt\n")
            killer.keyboard_interrupt()

        if (not amqp.is_alive()):
            logging.info("amqp aborted\n")
            killer.terminate()            
            
        # check if we have to terminate together with other exceptions
        if killer.kill_now:
            logging.info("killed by signal\n")

            amqp.terminate()
            amqp.join()
            logging.debug("AMQP terminated")

            return False


if __name__ == '__main__':

    import sys, os
    amqp2amqp_jsonline2bufr.cwd=os.getcwd()

    if amqp2amqp_jsonline2bufr.service():

        sys.stdout.write("Daemon started with pid %d\n" % os.getpid())
        sys.stdout.write("Daemon stdout output\n")
        sys.stderr.write("Daemon stderr output\n")

        main(amqp2amqp_jsonline2bufr)  # (this code was run as script)

        for proc in amqp2amqp_jsonline2bufr.procs:
            proc.wait()

        sys.stdout.write("Daemon stoppped\n")
        sys.exit(0)
