#!/usr/bin/env python
# -*- coding: utf-8 -*-

from minimalkb import __version__

import logging; logger = logging.getLogger("minimalKB");


import sys
import asyncore, asynchat
import os, socket, string
import traceback

import json

from minimalkb.kb import MinimalKB, KbServerError

PORT = 6969

class MinimalKBChannel(asynchat.async_chat):

    def __init__(self, server, sock, addr, kb):
        asynchat.async_chat.__init__(self, sock)
        self.set_terminator("#end#")
        self.request = None
        self.data = ""

        self.kb = kb

    def parse_request(self, req):
        tokens = [a.strip() for a in req.strip().split("\n")]
        if len(tokens) == 1:
            return tokens[0], []
        else:
            args = []
            for t in tokens[1:]:
                try:
                    args.append(json.loads(t))
                except ValueError:
                    logger.error("Invalid arguments for <%s>: %s. Valid JSON was expected."%(tokens[0], t))
            return tokens[0], args

    def collect_incoming_data(self, data):
        self.data = self.data + data

    def found_terminator(self):

        logger.debug("Got request:" + self.data )
        request, args = self.parse_request(self.data)
        self.data = ""
        self.kb.submitrequest(self, request, *args)

    def sendmsg(self, msg):
        logger.debug("Sent message:" + msg)
        self.push(msg + "#end#\n")


class MinimalKBServer(asyncore.dispatcher):

    def __init__(self, port, kb):
        asyncore.dispatcher.__init__(self)

        self.kb = kb

        self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
        self.set_reuse_addr()
        self.bind(("", port))
        self.listen(5)

    def handle_accept(self):
        conn, addr = self.accept()
        MinimalKBChannel(self, conn, addr, kb)

def version():
    print("minimalKB %s" % __version__)

if __name__ == '__main__':

    from minimalkb.ansistrm import ColorizingStreamHandler
    import argparse

    parser = argparse.ArgumentParser(description='A minimal knowledge base for robots.')
    parser.add_argument('-v', '--version', action='version',
                       version=version(), help='returns minimalKB version')
    parser.add_argument('-q', '--quiet', action='store_true',
                                help='be quiet (only errors are reported)')
    parser.add_argument('-d', '--debug', action='store_true',
                                help='enables verbose output')
    parser.add_argument('-p', '--port', default=PORT, type=int, nargs='?',
                                help='port the server listen to.')
    parser.add_argument('ontology', default="", nargs='?', help="local file or URL of an intial ontology to load")

    args = parser.parse_args()

    console = ColorizingStreamHandler()
    
    if args.debug:
        logger.setLevel(logging.DEBUG)
    elif args.quiet:
        logger.setLevel(logging.ERROR)
    else:
        logger.setLevel(logging.INFO)

    formatter = logging.Formatter('%(asctime)-15s: %(message)s')
    console.setFormatter(formatter)
    logger.addHandler(console)

    kb = MinimalKB(args.ontology)

    s = MinimalKBServer(args.port, kb)
    logger.info("Starting to serve at port %d..." % args.port)

    try:
        while True:
            asyncore.loop(count = 1)
            kb.process()
    except KeyboardInterrupt:
        logger.info("Bye bye")
