#!/usr/bin/env python
import logging
import os
import sys
import datetime
from collections import OrderedDict
from optparse import OptionParser
import signal
from twisted.internet import reactor, protocol, task

from siptest.client import ReceiverFactory, SenderFactory
from siptest.common.constants import SIP_HOST, SIP_PORT, RUNS_COUNT, \
    CALL_DURATION, INTERVAL, WAIT_TIME
from twisted.internet.error import ReactorNotRunning


if __name__ == '__main__':
    usage = "usage: %prog [host:port] -f <testfile> [options]"
    optp = OptionParser(usage=usage)
    # Output verbosity options.
    optp.add_option('-q', '--quiet', help='set logging to ERROR',
                    action='store_const', dest='loglevel',
                    const=logging.ERROR, default=logging.INFO)
    optp.add_option('-v', '--verbose', help='set logging to DEBUG',
                    action='store_const', dest='loglevel',
                    const=5, default=logging.INFO)
    optp.add_option('-f', '--file',
                    help='file with MSISDN:pass format',
                    dest='filename')
    #optp.add_option('-i', '--interval',
    #                help='interval between client start seconds (float)',
    #                dest='interval', default=INTERVAL, type='float')
    optp.add_option('-d', '--duration',
                    help='call duration in seconds', type='int',
                    dest='duration', default=CALL_DURATION)
    optp.add_option('-w', '--wait',
                    help='wait time in seconds for all calls', type='int',
                    dest='wait', default=WAIT_TIME)
    optp.add_option('-r', '--rtp', help='rtp file path', dest='rtp_file')
    opts, args = optp.parse_args()

    host = None
    port = None
    if not len(args):
        host = SIP_HOST
        port = SIP_PORT
    elif len(args) == 1:
        (host, port) = args[0].split(":")
    if len(args) > 1:
        print("Please set only one host")

    setattr(opts, "host", host)
    setattr(opts, "port", port)

    logging.basicConfig(level=opts.loglevel,
                        format='%(asctime)s %(levelname)-8s %(message)s')

    if not opts.filename:
        print("Please specify the filename for tests")
        optp.print_help()
        sys.exit(1)

    if not opts.rtp_file or not os.path.isfile(opts.rtp_file):
        print("Please specify the filename for rtp payload")
        optp.print_help()
        sys.exit(1)

    user_file_data = ""
    try:
        with open(opts.filename, 'r') as user_file:
            user_file_data = user_file.readlines()
    except Exception as e:
        print("Can't read file %s" % opts.filename)
        print(e)
        sys.exit(1)

    # parse file
    users = OrderedDict()
    for line in user_file_data:
        (msisdn, password) = line.rstrip().split(":")
        users.update({msisdn: password})

    if len(users) % 2:
        print("Please check file %s. Count of lines must be even")
        sys.exit(1)

    # distribute senders and receivers to workers
    is_receiver = True
    clients = []
    # create variable for simple statistic
    sender_num = 0
    receiver_num = 0
    for msisdn, password in users.items():
        if is_receiver:
            clients.append(ReceiverFactory(msisdn, password, opts, receiver_num))
            is_receiver = not is_receiver
            receiver_num += 1
        else:
            clients.append(SenderFactory(msisdn, password, opts, sender_num,
                                  to=clients[-1].msisdn))
            is_receiver = not is_receiver
            sender_num += 1


    for client in clients:
        client.run()

    living_time = opts.duration + opts.wait
    stop_time = datetime.datetime.now() + \
                datetime.timedelta(seconds=living_time)

    def check_reactor_time():
        now = datetime.datetime.now()
        if now > stop_time:
            reactor.stop()

    check_call = task.LoopingCall(check_reactor_time)
    check_call.start(1)

    def gen_requests_per_seconds():
        start = datetime.datetime.now()
        requests_per_sec = 0
        resps_per_sec = 0
        active_calls_per_sec = 0
        for client in clients:
            requests_per_sec += client.requests_done
            resps_per_sec += client.responses_received
            client.requests_done = 0
            client.responses_received = 0
            if isinstance(client, SenderFactory):
                active_calls_per_sec += client.active_calls
        stop = datetime.datetime.now()
        delta = stop - start
        logging.info("Requests %s, Responses %s, Active calls %s" %
                     (requests_per_sec, resps_per_sec, active_calls_per_sec))

    requests_per_seconds_call = task.LoopingCall(gen_requests_per_seconds)
    requests_per_seconds_call.start(1)

    # catch Ctrl + C
    def signal_handler(signal, frame):
        try:
            reactor.stop()
        except ReactorNotRunning as e:
            raise e
    signal.signal(signal.SIGINT, signal_handler)

    reactor.run()

    # count statistic
    successes = 0
    result = {}
    nums_with_invite_resend = {}
    nums_with_reconnects = {}

    for client in clients:
        successes += client.successes
        if client.invites_count > 1:
            nums_with_invite_resend["%s" % client] = client.invites_count
        if client.reconnects:
            nums_with_reconnects["%s" % client] = client.reconnects

    result["successes"] = successes
    result["nums_with_invite_resend"] = nums_with_invite_resend
    result["nums_with_reconnects"] = nums_with_reconnects
    print(result)
