#!/usr/bin/python3.6 -s

# Copyright (c) 2017 Paolo Patruno <p.patruno@iperbole.bologna.it>
# All rights reserved.
# 
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# 
# 1. Redistributions of source code must retain the above copyright notice,
#   this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#   notice, this list of conditions and the following disclaimer in the
#   documentation and/or other materials provided with the distribution.
# 3. Neither the name of mosquitto nor the names of its
#   contributors may be used to endorse or promote products derived from
#   this software without specific prior written permission.
# 
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.

import signal
import os
os.environ['DJANGO_SETTINGS_MODULE'] = 'rmap.settings'
import django
django.setup()

from rmap import daemon
from rmap import __version__
import rmap.settings
from rmap.ttn2dballe import Threaded_ttn2dballe
import threading

# TODO port those on config file !
MQTT_HOST = os.environ.get('MQTT_HOST', 'eu.thethings.network')


mapfile = rmap.settings.mapfilettn2dballed
logfile=rmap.settings.logfilettn2dballed
errfile=rmap.settings.errfilettn2dballed
lockfile=rmap.settings.lockfilettn2dballed
user=rmap.settings.userttn2dballed
group=rmap.settings.groupttn2dballed


ttn2dballed = daemon.Daemon(
        stdin="/dev/null",
        stdout=logfile,
        stderr=errfile,
        pidfile=lockfile,
        user=user,
        group=group
)


# 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 main (self):

    import os,sys,time
    import logging,logging.handlers
    import subprocess
    import traceback

    #arm the signal handler
    killer = GracefulKiller()
    
    # configure the logger
#    formatter=logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(thread)d - %(message)s",datefmt="%Y-%m-%d %H:%M:%S")
    formatter=logging.Formatter("%(asctime)s%(thread)d-%(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.DEBUG)

    logging.info('Starting up ttn2dballed')


    terminate = threading.Event()
    threads=[]
    f = open(mapfile)
    for line in f.readlines():
        line = line.rstrip()
        if len(line) == 0 or line[0] == '#':
            continue
        try:
            mqttuser, mqttpassword , topic, user, slug = line.split()

            thread=Threaded_ttn2dballe(MQTT_HOST,mqttuser, mqttpassword , (topic,), user, slug, terminate)
            #thread.setDaemon(True)
            thread.start()
            threads.append(thread)

        except Exception as exception:
            # log and retry on exception 
            logging.error('Exception occured: ' + str(exception))
            logging.error(traceback.format_exc())
            logging.error('Subprocess failed')
            time.sleep(10)


    try:
        #while (threading.active_count() > nthread):
        while True:
            c=False
            for th in threads:
                if not th.is_alive():
                    c=True
            if c:  break
            
            #logging.debug("OK")
            time.sleep(5)
            if killer.kill_now:
                logging.info("killed by signal\n")
                terminate.set()
                break

    except KeyboardInterrupt:
        # terminate on keyboard interrupt
        sys.stdout.write("keyboard interrupt\n")
        logging.info("keyboard interrupt\n")
        terminate.set()
    finally:
        # check if we have to terminate together with other exceptions
        terminate.set()

    logging.info("wait for thread to terminate")
    for th in threads:
        th.join()

            
if __name__ == '__main__':
    
    import sys, os
    
    ttn2dballed.cwd=os.getcwd()

    if ttn2dballed.service():

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

        main(ttn2dballed)  # (this code was run as script)
        #maindirecttodballe(ttn2dballed) # use this if you do not have arkimet and rabbitmq
            
        for proc in ttn2dballed.procs:
            proc.wait()

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

    
