from __future__ import with_statement

import sys
import code
import socket
import select
import os.path
import logging
import threading

from sarah.socketServer import UnixSocketServer
from sarah.io import IntSocketFile

class HushFile(object):
    """ Wraps around a file, but hushes all errors """
    def __init__(self, f):
        self.f = f
    def write(self, v):
        try: self.f.write(v)
        except: pass
    def read(self, v):
        try: return self.f.read(v)
        except: return ''
    def flush(self):
        try: self.f.flush()
        except: pass
    def readline(self):
        try: return self.f.readline()
        except: return ''

class FileMux(object):
    """ (Barely) wraps a file for writing and notifies handlers about
        these writes. """
    def __init__(self, old):
        self.old = old
        self.handlers = set()
    def write(self, v):
        self.old.write(v)
        for handler in self.handlers:
            handler(v)
    def register(self, handler):
        self.handlers.add(handler)
    def deregister(self, handler):
        self.handlers.remove(handler)

class SockConsole(code.InteractiveConsole):
    """ The InteractiveConsole addapted for usage with ShellServer """
    def __init__(self, sock, locals):
        code.InteractiveConsole.__init__(self, locals)
        self.f = IntSocketFile(sock)
        if not isinstance(sys.stdout, FileMux):
            sys.stdout = FileMux(sys.stdout)
        if not isinstance(sys.stderr, FileMux):
            sys.stderr = FileMux(sys.stderr)
        sys.stdout.register(self.on_std_write)
        sys.stderr.register(self.on_std_write)
        self.log_handler = logging.StreamHandler(HushFile(self.f))
        formatter = logging.Formatter(
                "%(levelname)s:%(name)s:%(message)s")
        self.log_handler.setFormatter(formatter)
        logging.getLogger('').addHandler(self.log_handler)
    def raw_input(self, prompt):
        self.f.write(prompt)
        ret = self.f.readline()
        if ret == '': raise IOError
        return ret[:-1]
    def on_std_write(self, v):
        try:
            self.f.write(v)
        except Exception:
            pass
    def cleanup(self):
        sys.stdout.deregister(self.on_std_write)
        sys.stderr.deregister(self.on_std_write)
        logging.getLogger('').removeHandler(self.log_handler)
    def interrupt(self):
        self.f.interrupt()
    def handle(self):
        self.interact()

class ShellServer(UnixSocketServer):
    def create_handler(self, con, addr, logger):
        locals = {'manager': self.manager}
        for k, ii in self.manager.insts.iteritems():
            locals[k] = ii.object
        console = SockConsole(con, locals)
        return console
# vim: et:sta:bs=2:sw=4: