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

'''
CloudControl CLI class
'''

import os, os.path
import sys
import socket
import ssl
import threading
import subprocess
import ConfigParser
import cccli
from cccli import printer, command
from cccli.clierror import *
from cccli.command import Command
from sjrpc.client import SimpleRpcClient
from sjrpc.utils import RpcHandler, pure, threadless, ConnectionProxy
import sjrpc.core.exceptions

import re
import readline

class Cli(object):

    def __init__(self, settings, args):
        self._settings = settings
        if "alias" in settings:
            self.alias = Alias(settings["alias"])
            self.alias.load()
        self._interactive = sys.stderr.isatty() and sys.stdin.isatty()
        self._prompt = "> "
        self._commands = args
        self.rpc = None

    def start(self):
        '''Start a CLI'''
        # Connecting
        self._connect()
        # authentifications
        self._auth()
        # run parsing args
        if len(self._commands) > 0:
            for c in self._commands:
                self._parse(c)
        elif self._interactive:
            self._interactive_parser()
        else:
            self._parser()

    def _connect(self):
        printer.debug("Connecting...")
        rpcc = SimpleRpcClient.from_addr(self._settings["server"],
                                        self._settings["port"],
                                        enable_ssl=True,
                                        on_disconnect=self._on_disconnect
                                        )
        rpcc.start(daemonize=True)
        self.rpc = ConnectionProxy(rpcc)

    def _on_disconnect(self, rpc):
        printer.fatal("Disconnected from server!")

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

    def _interactive_parser(self):
        '''Interactive shell parser'''
        # init readline

        while True:
            try:
                line = raw_input(self._prompt)
                self._parse_line(line)
            except EOFError:
                printer.out("")
                break
            except SystemExit:
                break
            except KeyboardInterrupt:
                printer.out("")
        try:
            pass
            #readline.write_history_file(self._settings["histfile"])
        except IOError:
            pass
        printer.out("Tcho!")

    def _parser(self):
        '''Non interactive parser'''
        while True:
            line = raw_input(self._prompt)
            self._parse_line(line)

    def _parse_line(self, line):
        '''Parse a line (more than one command)'''
        for cmd in line.split(";"):
            if (cmd.strip() == "" or cmd[0] == "#"):
                continue
            elif (cmd[0] == "!"):
                p = subprocess.Popen(cmd[1:], close_fds=True, shell=True)
                p.wait()
                ret = p.returncode
            elif (cmd[0] == "?"):
                Command("help").call()
            else:
                self._parse_command(cmd)

    def _parse_command(self, cmd):
        try:
            # lex command
            argv = self._lex_argv(cmd)
            # alias subs
            if argv[0] in self.alias:
                argv[0] = self.alias[argv[0]]
            # execute command
            Command(argv, self).call()
        except BadArgument, e:
            if str(e):
                printer.error("Bad argument: %s."%str(e))
            else:
                printer.error("Bad argument.")
            usage = Command.usage(argv[0])
            if usage != "":
                printer.out("usage: %s."%usage)
        except BadCommand, e:
            if str(e):
                printer.error("command: %s."%str(e))
            else:
                printer.error("No command: %s."%argv[0])
        except sjrpc.core.exceptions.RpcError, e:
            if cccli.debug: raise
            printer.error("sjRPC: %s"%str(e))
        except Exception, e:
            if cccli.debug: raise
            printer.error("%s: %s."%(argv[0], str(e)))

    def _lex_argv(self, string):
        '''Lex command argument'''
        return string.split(" ")


class Alias(dict):
    ''' Alias wrapper'''
    def __init__(self, filename):
        self._filename = filename

    def load(self):
        '''load alias from file'''
        if os.access(self._filename, os.R_OK):
            fparser = ConfigParser.SafeConfigParser()
            fparser.read(self._filename)
            if fparser.has_section("alias"):
                self.clear()
                self.update(fparser.items("alias"))

    def save(self):
        '''save alias on file'''
        if os.access(self._filename, os.R_OK or os.W_OK):
            fparser = ConfigParser.SafeConfigParser()
            fparser.read(self._filename)
            fparser.remove_section("alias")
            fparser.add_section("alias")
            for n,v in self.items():
                fparser.set("alias", n, v)
            fparser.write(open(self._filename, "w"))