#!/usr/bin/env python
#
# Cloudlet Infrastructure for Mobile Computing
#
#   Author: Kiryong Ha <krha@cmu.edu>
#           Zhuo Chen <zhuoc@cs.cmu.edu>
#
#   Copyright (C) 2011-2013 Carnegie Mellon University
#   Licensed under the Apache License, Version 2.0 (the "License");
#   you may not use this file except in compliance with the License.
#   You may obtain a copy of the License at
#
#       http://www.apache.org/licenses/LICENSE-2.0
#
#   Unless required by applicable law or agreed to in writing, software
#   distributed under the License is distributed on an "AS IS" BASIS,
#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#   See the License for the specific language governing permissions and
#   limitations under the License.
#

import json
from optparse import OptionParser
import pprint
import Queue
import os
import socket
import sys
import threading
import time

dir_file = os.path.dirname(os.path.realpath(__file__))

sys.path.insert(0, os.path.join(dir_file, ".."))
import gabriel
import gabriel.ucomm
LOG = gabriel.logging.getLogger(__name__)


class UCommError(Exception):
    pass

def process_command_line(argv):
    '''
    A command line processing function shared by common cognitive engine proxies
    (maybe ucomms as well)
    '''
    VERSION = gabriel.Const.VERSION
    DESCRIPTION = "Gabriel Cognitive Assistant"

    parser = OptionParser(usage = '%prog [option]', version = VERSION, description = DESCRIPTION)
    parser.add_option(
            '-s', '--address', action = 'store',
            help = "(IP address:port number) of directory server")
    parser.add_option(
            '-n', '--net_interface', action = 'store', default = "eth0",
            help = "the network interface with which the cognitive engines communicate")

    settings, args = parser.parse_args(argv)

    if hasattr(settings, 'address') and settings.address is not None:
        if settings.address.find(":") == -1:
            parser.error("Need address and port. Ex) 10.0.0.1:8021")
    return settings

def register_ucomm(ip_addr, port, net_interface = "eth0"):
    url = "http://%s:%d/" % (ip_addr, port)
    json_info = {
        gabriel.ServiceMeta.UCOMM_SERVER_IP: gabriel.network.get_ip(net_interface),
        gabriel.ServiceMeta.UCOMM_SERVER_PORT: gabriel.Const.UCOMM_SERVER_PORT
        }
    gabriel.network.http_put(url, json_info)


def main():
    ## get service list from control server
    settings = process_command_line(sys.argv[1:])
    ip_addr, port = gabriel.network.get_registry_server_address(settings.address)
    service_list = gabriel.network.get_service_list(ip_addr, port)
    LOG.info("Gabriel Server :")
    LOG.info(pprint.pformat(service_list))

    ## register the current ucomm
    try:
        register_ucomm(ip_addr, port, settings.net_interface)
    except Exception as e:
        LOG.error(str(e))
        LOG.error("failed to register UCOMM to the control")
        sys.exit(1)

    control_vm_ip = service_list.get(gabriel.ServiceMeta.UCOMM_RELAY_IP)
    control_vm_port = service_list.get(gabriel.ServiceMeta.UCOMM_RELAY_PORT)

    # result pub/sub
    try:
        LOG.info("connecting to %s:%d" % (control_vm_ip, control_vm_port))
        result_forward_thread = gabriel.ucomm.ResultForwardingClient((control_vm_ip, control_vm_port))
        result_forward_thread.isDaemon = True
    except socket.error as e:
        # do not proceed if cannot connect to control VM
        if result_forward_thread is not None:
            result_forward_thread.terminate()
        raise UCommError("Failed to connect to Control server (%s:%d)" % (control_vm_ip, control_vm_port))

    # ucomm server
    ucomm_server = gabriel.ucomm.UCommServer(gabriel.Const.UCOMM_SERVER_PORT, gabriel.ucomm.UCommServerHandler)
    ucomm_server_thread = threading.Thread(target = ucomm_server.serve_forever)
    ucomm_server_thread.daemon = True

    # run the threads
    try:
        result_forward_thread.start()
        ucomm_server_thread.start()
        while True:
            time.sleep(100)
    except KeyboardInterrupt as e:
        sys.stdout.write("Exit by user\n")
        sys.exit(0)
    except Exception as e:
        sys.stderr.write(str(e))
        sys.exit(1)
    finally:
        if ucomm_server is not None:
            ucomm_server.terminate()
        if result_forward_thread is not None:
            result_forward_thread.terminate()


if __name__ == '__main__':
    main()
