#!/usr/bin/env python
#coding=utf8

'''
CloudControl CLI main module
'''

import os, os.path
import sys
import re
import subprocess
import shlex
import StringIO

from cccli import version, debug
from cccli.command import Command, Alias
from cccli.printer import Printer
from cccli.exception import *

from sjrpc.client import SimpleRpcClient
from sjrpc.utils import RpcHandler, ConnectionProxy, pure
from sjrpc.core.exceptions import *

class Cli(object):
    def __init__(self, settings):
        self.settings = settings
        self.prompt = ""
        self.rpc = None
        self.printer = None
        self.alias = Alias()

    def start(self, line=""):
        '''Start a CLI'''
        # line stuff
        if line:
            sys.stdin = StringIO.StringIO(line)
        # set interactive mode
        self.interactive = sys.stderr.isatty() and sys.stdin.isatty()
        # start printer and load history
        self.printer = Printer(self.interactive)
        self.printer.history.load(self.settings.get("history", ""))
        self.printer.history.maxsize(self.settings.get("hsize", None))
        # load alias
        self.alias.load(self.settings.get("alias", ""))
        # print debug
        self.printer.debug("Interactive: %s"%self.interactive)
        self.printer.debug("Alias: %s"%self.alias)
        self.printer.debug("Loaded history: %s"%len(self.printer.history))
        # Connecting
        self._connect()
        # authentifications
        self._auth()
        # Parsing
        self._parse()
        # save history
        self.printer.history.save(self.settings.get("history", ""))

    def _connect(self):
        self.printer.debug("Connecting...")
        rpcc = SimpleRpcClient.from_addr(self.settings["server"],
                                         self.settings["port"],
                                         enable_ssl=True,
                                         default_handler=CliHandler(),
                                         on_disconnect="quit",
                                         timeout=self.settings["timeout"]
                                        )
        rpcc.start(daemonize=True)
        self.rpc = ConnectionProxy(rpcc)

    def _auth(self):
        '''Handle server authentification'''
        self.printer.debug("Authenticating...")
        if self.rpc.authentify(self.settings["login"], self.settings["pass"]):
            self.printer.debug("Authenticated.")
        else:
            self.printer.fatal("Autentification failed!")

    def _parse(self):
        '''Parse a line'''
        prompt = "> " if self.interactive else ""
        while True:
            try:
                argv = shlex.split(self.printer.getline(prompt), comments=True)
                # alias subsitution
                if argv[0] in self.alias:
                    argv[0] = self.alias[argv[0]]
            except ValueError, e:
                self.printer.error("Lexer: %s"%str(e))
                continue
            except EOFError:
                break
            except SystemExit:
                break
            except KeyboardInterrupt:
                self.printer.out("")
            self._exec_command(argv)
        if self.interactive:
            self.printer.out("tcho!")

    def _exec_command(self, argv):
        '''Execute command'''
        try:
            if (argv[0] == "!"):
                p = subprocess.Popen(argv[1:], close_fds=True, shell=True)
                p.wait()
                ret = p.returncode
            elif (argv[0] == "?"):
                Command(["help"], self).call()
            else:
                Command(argv, self).call()
        except BadArgument, e:
            if str(e):
                self.printer.error("Bad argument: %s."%str(e))
            else:
                self.printer.error("Bad argument.")
            usage = Command.usage(argv[0])
            if usage != "":
                self.printer.out("usage: %s."%usage)
        except BadCommand, e:
            if str(e):
                self.printer.error("command: %s."%str(e))
            else:
                self.printer.error("No command: %s."%argv[0])
        except RpcError, e:
            if debug: raise
            self.printer.error("sjRPC: %s"%str(e))
        except Exception, e:
            if debug: raise
            self.printer.error("%s: %s."%(argv[0], str(e)))

class CliHandler(RpcHandler):
    '''Handle RPC incoming request'''

    @pure
    def get_tags(self, tags=()):
        if "version" in tags:
            return { "version": version }

    @pure
    def quit(self, rpc=None):
        self.printer.fatal("Disconnected from server!")

class CliLexer(object):

    def __init__(self, fd):
        self.fd = fd

    def get_next_token(self):
        pass