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

'''
CloudControl CLI main module
'''

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

import cccli
from cccli.command import Command, Alias
from cccli.printer import Printer, color
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...")
        try:
            self.rpc.authentify(self.settings["login"], self.settings["pass"])
        except Exception:
            raise cliError("Autentification failed!")
        self.printer.debug("Authenticated.")

    def _parse(self):
        '''Parse a line'''
        if self.interactive:
            prompt = "%s%s>%s "%(color["lwhite"],self.settings["login"],color["reset"])
        else:
            prompt = ""
        while True:
            try:
                argv = shlex.split(self.printer.getline(prompt), comments=True)
            except ValueError as e:
                print type(e)
                self.printer.error("Lexer: %s"%str(e))
                continue
            except KeyboardInterrupt:
                self.printer.out("")
                continue
            except EOFError:
                break
            except SystemExit:
                break
            if len(argv) == 0:
                continue
            # alias subsitution
            if argv[0] in self.alias:
                argv[0] = self.alias[argv[0]]
            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 as 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 as e:
            if str(e):
                self.printer.error("command: %s."%str(e))
            else:
                self.printer.error("No command: %s."%argv[0])
        except cmdWarning as e:
            self.printer.warn("%s: %s"%(argv[0], str(e)))
        except cmdError as e:
            self.printer.error("%s: %s"%(argv[0], str(e)))
        except Exception as e:
            if cccli.debug:
                raise
            self.printer.error(str(e))
            self.printer.warn("This is a not expected error, please report it!")

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

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

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