#Copyright 2015 B. Johan G. Svensson
#Licensed under the terms of the MIT license (see LICENSE).

from __future__ import division
import struct, time, csv
import fsslib


class CSVWriter():
    def __init__(self, fid, samplerate):
        pass


class CSVReader():
    def __init__(self, fid, samplerate):
        self.samplerate = samplerate
        self.csvfile = csv.reader(fid, skipinitialspace = True,strict=True)
        self.csvfile.next()  # Waste header
    def getnext(self):
        try:
            linelst = self.csvfile.next()
        except:
            return False, False, False, False, False, False
        dtime = int(round(float(linelst[0]) * self.samplerate))
        data = linelst[1] == '1'   # int() is too slow
        indx = linelst[2] == '1'   # int() is too slow
        step = linelst[3] == '1'   # int() is too slow
        side = linelst[4] == '1'   # int() is too slow
        oper = linelst[5] == '1'   # int() is too slow
        return dtime, data, indx, step, side, oper


class BinDeltaWrite():
    def __init__(self, fid, samplerate):
        pass


class BinDeltaWriter():
    def __init__(self, fid):
        self.fid = fid
    def write(self, dtime, data, indx, step, side, oper):
        bitfield = data | (indx << 1) | (step << 2) | (side << 3) | (oper << 4)
        data = struct.pack('<QB', dtime, bitfield)
        self.fid.write(data)


class BinDeltaReader():
    def __init__(self, fid):
        self.fid = fid
    def getnext(self):
        data = self.fid.read(9)
        if len(data) < 9:
            return False, False, False, False, False, False
        dtime, bitfield = struct.unpack('<QB',data)
        data = bitfield & 1
        indx = (bitfield >> 1) & 1
        step = (bitfield >> 2) & 1
        side = (bitfield >> 3) & 1
        oper = (bitfield >> 4) & 1
        return dtime, data, indx, step, side, oper


class BinDeltaReader2():
    def __init__(self, fid, blocksize):
        self.fid = fid
        self.indx = 0
        self.data = ''
        self.datatuple = tuple()
        self.blocksize = blocksize
    def fillbuffer(self):
        self.data = self.fid.read(9*self.blocksize)
        length = len(self.data)//9
        self.datatuple = struct.unpack('<' + length*'QB',self.data)
        self.indx = 0
    def getnext(self):
        if self.indx + 1 >= len(self.datatuple):
            self.fillbuffer()
        if len(self.data) < 9:
            return False, False, False, False, False, False
        dtime = self.datatuple[self.indx]
        bitfield = self.datatuple[self.indx + 1]
        data = bitfield & 1
        indx = (bitfield >> 1) & 1
        step = (bitfield >> 2) & 1
        side = (bitfield >> 3) & 1
        oper = (bitfield >> 4) & 1
        self.indx += 2
        return dtime, data, indx, step, side, oper

def converttofss(fnamein,fnameout):
    samplerate = 25000000
    fin = open(fnamein,'rb')
    fin.seek(0,2)
    size = fin.tell()
    fin.seek(0)
    print 'Init readers'
    #reader = CSVReader(fin, samplerate)
    #reader = BinDeltaReader(fin)
    reader = BinDeltaReader2(fin, 10000)
    print 'Init buffers'
    packer = fsslib.Pacman(samplerate)
    print 'Init done'
    howfar = 1
    tim1sum = 0
    tim2sum = 0
    tim3sum = 0
    tim4sum = 0
    timtot = 0
    howfar2 = 1
    tic3 = time.clock()
    while True:
        tic0 = time.clock()
        dtime, data, indx, step, side, oper = reader.getnext()
        if not dtime:
            break
        tic1 = time.clock()
        packer.store(dtime, data, indx, step, side, oper)
        tic2 = time.clock()
        howfar += 1
        if howfar > 1000000:
            print str(100*fin.tell()/size) + '%'
            howfar = 1
            print 'Time phase 1', tim1sum
            print 'Time phase 2', tim2sum
            print 'Time phase 3', tim3sum
            print 'Time phase 4', tim4sum
            print 'Time total', timtot
        howfar2 += 1
        tic3last = tic3
        tic3 = time.clock()
        tim1sum += tic1 - tic0
        tim2sum += tic2 - tic1
        tim3sum += tic3 - tic2
        tim4sum += tic0 - tic3last
        timtot += tic3 - tic3last
    fin.close()
    print 'Pack: Start'
    outstr = packer.commit()
    print 'Pack: Saving to file'
    fout = open(fnameout,'wb')
    fout.write(outstr)
    fout.close()
    print 'All done'


def convertfrfss(fnamein, fnameout):
    fin = open(fnamein, 'rb')
    print 'Reading file'
    unpacker = fsslib.Streamer(fin)
    samplerate = unpacker.samplerate
    fin.close()
    fout = open(fnameout, 'wb')
    writer = BinDeltaWriter(fout)
    print 'Decoding (will take LONG time!)'
    while True:
        stim, data, indx, step, side, oper = unpacker.getnext()
        if stim is False:
            break
        writer.write(stim, data, indx, step, side, oper)


def test01():
    converttofss('j:\\Transfer\\Midwinter-64bitDELTA8bit25MHz.bin', 'j:\\Transfer\\Midwinter.fss')

def test02():
    convertfrfss('j:\\Transfer\\Midwinter.fss', 'j:\\Transfer\\Midwinter-DELTATEST.bin')

def main():
    #test01()
    test02()

if __name__ == '__main__':
    main()

