import sys, time, os, socket
import struct, binascii, re, csv
from datetime import datetime, timedelta

# Twisted
from twisted.protocols.basic import LineReceiver
from twisted.internet import reactor
from twisted.python import usage, log
from twisted.internet.serialport import SerialPort
from twisted.web.server import Site
from twisted.web.static import File

try: # version > 0.8.0
    from autobahn.wamp1.protocol import exportRpc
except:
    from autobahn.wamp import exportRpc

def timeToArray(timestring):
    # Converts time string of format 2013-12-12T23:12:23.122324
    # to an array similiat to a datetime object
    try:
        splittedfull = timestring.split(' ')
        splittedday = splittedfull[0].split('-')
        splittedsec = splittedfull[1].split('.')
        splittedtime = splittedsec[0].split(':')
        datearray = splittedday + splittedtime
        datearray.append(splittedsec[1])
        datearray = map(int,datearray)
        return datearray
    except:
        log.msg('Error while extracting time array')
        return []

def dataToFile(outputdir, sensorid, filedate, bindata, header):
    # File Operations
    try:
        hostname = socket.gethostname()
        path = os.path.join(outputdir,hostname,sensorid)
        # outputdir defined in main options class
        if not os.path.exists(path):
            os.makedirs(path)
        savefile = os.path.join(path, sensorid+'_'+filedate+".bin")
        if not os.path.isfile(savefile):
            with open(savefile, "wb") as myfile:
                myfile.write(header + "\n")
                myfile.write(bindata + "\n")
        else:
            with open(savefile, "a") as myfile:
                myfile.write(bindata + "\n")
    except:
        log.err("Protocol: Error while saving file")        


## meteolabor BM35 protocol
##
class BM35Protocol(LineReceiver):
    """
    The BM35 protocol for extracting atmospheric pressure data from BM35
    SETUP of BM35 (RS485 version):
        1.) connect a RS485 to RS232 converter
    Supported modes:
        instantaneous values
        in future filtered values
    """

    def __init__(self, wsMcuFactory, sensor, outputdir):
        self.wsMcuFactory = wsMcuFactory
        self.sensor = sensor
        self.outputdir = outputdir
        self.hostname = socket.gethostname()
        print ("Initialize the connection and set automatic mode (use ser.commands?)")
        ### TODO send A00d03000^M to serial - done by serial-init.py !!!

    @exportRpc("control-led")
    def controlLed(self, status):
        if status:
            print ("turn on LED")
            self.transport.write('1')
        else:
            print ("turn off LED")
            self.transport.write('0')

    #def send_command(...?)

    def connectionLost(self):
        log.msg('BM35 connection lost. Perform steps to restart it!')

    def connectionMade(self):
        log.msg('%s connected.' % self.sensor)

    def processData(self, data):

        currenttime = datetime.utcnow()
        date = datetime.strftime(currenttime, "%Y-%m-%d")
        actualtime = datetime.strftime(currenttime, "%Y-%m-%dT%H:%M:%S.%f")
        outtime = datetime.strftime(currenttime, "%H:%M:%S")
        timestamp = datetime.strftime(currenttime, "%Y-%m-%d %H:%M:%S.%f")
        ## TODO??? -> Roman!
        #intensity = 88888.8
        pressure1 = 88888.8
        pressure2 = 88888.8
        typ = "none"
        dontsavedata = False

#        packcode = '6hLLL'
#        header = "# MagPyBin %s %s %s %s %s %s %d" % (self.sensor, '[var3,var4]', '[p1,p2]', '[mBar,mBar]', '[1000,1000]', packcode, struct.calcsize(packcode))
        packcode = '6hLL'
        header = "# MagPyBin %s %s %s %s %s %s %d" % (self.sensor, '[var3]', '[p]', '[mBar]', '[1000]', packcode, struct.calcsize(packcode))

        try:
            # Extract data
            data_array = data.strip().split(',')
            #print data_array, len(data_array)
            if len(data_array) == 2:
                typ = "valid"
            # add other types here
        except:
            # TODO??? base x mobile?
            log.err('BM35 - Protocol: Output format not supported - use either base, ... or mobile')
        # Extracting the data from the instrument

        if typ == "valid": 
            pressure1 = float(data_array[0].strip())
            # pressure1 is raw 
            pressure2 = float(data_array[1].strip())
            # pressure2 is calculated from pressure1 by calibration values
        elif typ == "none":
            dontsavedata = True
            pass

        # TODO right now, saving data is not necessary
        try:
            if not typ == "none":
                # extract time data
                datearray = timeToArray(timestamp)
                try:
                    datearray.append(int(pressure2*1000.))
                    data_bin = struct.pack(packcode,*datearray)
                    dataToFile(self.outputdir,self.sensor, date, data_bin, header)
                except:
                    log.msg('BM35 - Protocol: Error while packing binary data')
                    pass
        except:
            log.msg('BM35 - Protocol: Error with binary save routine')
            pass
        evt1 = {'id': 1, 'value': timestamp}
        evt35 = {'id': 35, 'value': pressure2}
        if not ((pressure2 < 1300) and (pressure2 > 800)):
            print('BM35: Druck ausserhalb ',pressure2)
        evt99 = {'id': 99, 'value': 'eol'}

        return evt1,evt35,evt99
         
    def lineReceived(self, line):
        dispatch_url =  "http://example.com/"+self.hostname+"/bm3#"+self.sensor+"-value"
        try:
            evt1, evt35, evt99 = self.processData(line)
        except ValueError:
            log.err('BM35 - Protocol: Unable to parse data %s' % line)
        except:
            pass

        try:
            ## publish event to all clients subscribed to topic
            ##
            self.wsMcuFactory.dispatch(dispatch_url, evt1)
            #self.wsMcuFactory.dispatch(dispatch_url, evt3)
            self.wsMcuFactory.dispatch(dispatch_url, evt35)
            self.wsMcuFactory.dispatch(dispatch_url, evt99)
        except:
            log.err('BM35 - Protocol: wsMcuFactory error while dispatching data.')