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
