#from xmlrpclib import ServerProxy, Error
import xmlrpc.client
from xmlrpc.client import ServerProxy
import logging
import time
from types import MethodType
import numpy as np
import struct
import stardice.qla
import types
import subprocess
import os

import pdb

def ask(question, answers=['y', 'n'], bip=True):
    if bip:
        #print '\a'
        pass
    answer = eval(input(question))
    while answer not in answers:
        answer = eval(input('Answer not understood (%s) try again:' % str(answers)))
    return answer

class ProxyWithCompletion(ServerProxy):
    def __dir__(self):
        return self.system.listMethods()

    
class Subsystem(object):
    tracked_properties = []

    def _default_setter_for_tracked_properties(self, name):
        def func(self, value):
            v = getattr(self, '_'+name)
            if value == 'IDLE':
                return v
            if v != value:
                logging.debug('%s: Setting %s to %s' % (self.name, name, str(value)))
                getattr(self.server, 'set_' + name)(value)
                setattr(self, '_' + name, value)
            return value
        return types.MethodType(func, self)
 
    
    def __init__(self, config, name, scheduler):
        self._addr = getattr(config, name).addr
        if self._addr:
            self.server = ProxyWithCompletion(self._addr, allow_none=True)
        #self.server.init()
        self.config = getattr(config, name)
        self.name = name
        self._interactive = {}
        self.scheduler = scheduler
        self._entire_config = config
        
    def configure(self):
        self._config()
        for p in self.tracked_properties:
            getter_name = 'get_%s' % p
            if getter_name not in dir(self):
                setattr(self, getter_name, getattr(self.server, getter_name))
            setter_name = 'set_%s' % p
            if setter_name not in dir(self):
                setattr(self, setter_name, self._default_setter_for_tracked_properties(p))
        self.sync_tracked_properties()
        
    def sync_tracked_properties(self):
        for p in self.tracked_properties:
            setattr(self, '_%s' % p, getattr(self.server, 'get_%s' % p)())
            
    def before_exposure(self, exposure, fitsbuilder):
        res = self._process_params(exposure)
        for p in res:
            if p in self.tracked_properties:
                getattr(self, 'set_%s' % p)(res[p])
            else:
                fitsbuilder.append({p: res[p]}, prefix=self.name)
                
    def exposure(self, exposure, fitsbuilder):
        pass

    def after_exposure(self, exposure, fitsbuilder):
        fitsbuilder.append(self.status(), prefix=self.name)

    def state(self):
        status = self.status()
        st = ''
        for k in status:
            st += '%s: %s\n' % (k, str(status[k]))
        return st

    def status(self):
        stat = {}
        for p in self.tracked_properties:
            stat[p] = getattr(self, '_%s' % p)
        stat.update(self._extended_status())
        return stat

    def _extended_status(self):
        return {}
    
    def _config(self):
        pass

    def _process_params(self, exposure):
        res = {}
        for p in self.expected_params:
            n = "%s.%s" % (self.name, p)
            try:
                res[p] = exposure[n]
            except KeyError:
                logging.warning('parameter %s not found in config file, using default value %s' % (n, str(self.expected_params[p])))
        return res
    
def decode(I):
    fmt = "<%dH" % (len(I['binarydata'].data)/2)
    pixels = np.array(struct.unpack(fmt, I['binarydata'].data), dtype=np.uint16)
    I['pixels'] = pixels.reshape(I['shape'])
    del I['binarydata']
    return I

    
if __name__ == '__main__':
    import scheduler, fitsbuilder
    from stardice import configfiles
    logging.basicConfig(format='%(asctime)s %(message)s', level=logging.DEBUG)
    reload(scheduler)
    config = configfiles.Config('dummy_scheduler.cfg')
    s = scheduler.Scheduler(config)
    fb = fitsbuilder.FitsBuilder(output_dir = './')
    print((s.state()))
    s.focus.before_exposure({'FILTER':'Bi', 'FOCUSPOS':0}, fb)
    print((s.state()))
    #led = LedHead(config, 'Led')
    #focus = Focus(config, 'Focus')
    #camera = Camera(config, 'Camera')

    #mount = LedHead(config, 'Mount')


