#from importlibs import *

"""
####################################################
    8 Bytes Magic "MCSTRM "
    8 Bytes File size (at this time not used -1)
    8 Bytes Magic "LISThdr"
    8 Bytes Size of the complete header (X)
    X Bytes Header
    8 Bytes Magic "IDX1POS"
    8 Bytes Size of the index pointer (8)
    8 Bytes Pointer to the index at the end of the file.
    Begin of data (data chunks)

    Data chunks (for Elektrode Raw Data) consists of
    8 Bytes Name of the stream
    8 Bytes Number of bytes in this chunk (Y)
    16 Bytes Timestamp
    Y-16 Bytes Data
####################################################
"""
import struct
import ctypes
import array
import collections
import binascii
import sys
import os
import time
import mmap
endianness_dict = {
    "native-native":    '@',
    "native-standard":  '=',
    "little":           '<',
    "big":              '>',
    "network":          '!'
}
endian = endianness_dict.get(sys.byteorder, "native-standard")


__name__ = "readmcd"
__revision__ = "$Revision: 0.1 - 16 Sep 2010$"
__author__ = "Andrea Maffezzoli"


class readMcd(object):
    """Applying struct.Struct to unpack/decode binary data from mcd files"""
    
    ###########################################################################
    # FileHeader
    ###########################################################################
    McdFileHeader = struct.Struct(endian + '4q')
    #McdFileHeader_size = FileHeader.size

    ###########################################################################
    # Spike Channel Header
    ###########################################################################
    McdVarHeader = struct.Struct(endian + '3q')
    #McdVarHeader_size = SpikeChannelHeader_struct.size

    ###########################################################################
    # Spike Channel Header
    ###########################################################################
    McdDataHeader = struct.Struct(endian + '8s3Q')
    
    ###########################################################################
    # Exporting timestamps in various formats: numpy.ndarray, array.array, list
    ###########################################################################
    func_output = {'numpy': lambda x: numpy.array(x, dtype = 'float32'),
                   '': lambda x: x,
                   'list': list}
    
    ###########################################################################
    # Denomination of channels units
    ###########################################################################
    #UnitsNames = {0: 'Unsorted', 1: 'a', 2: 'b', 3: 'c', 4: 'd', 5: 'e', 6: 'f', 7: 'g'}


    def __init__(self, filename): self.filename = filename
    
    def __call__(self): #, Event_on = False, Continuous_on = False):
        
        self.f = open(self.filename, 'rb')

        #########################################################################
        # Preliminary information on the experiment and Channels data    
        #########################################################################
        self.readFileHeader()  
        self.readVariablesHeader()

        #########################################################################
        # Finally get timestamps for every Channel/Unit pair      
        #########################################################################
        #self.readData()
        
        self.f.close()

    def readFileHeader(self):

        MagicMCSTRM, FileSize, MagicLISThdr, HeaderSize = \
            self.McdFileHeader.unpack(self.f.read(self.McdFileHeader.size))
        print MagicMCSTRM, FileSize, MagicLISThdr, HeaderSize
        #McdFileHeader2 = struct.Struct(endian + '8sq' + str(HeaderSize-16) + 's')
        
        #McdFileHeader2 = struct.Struct(endian + '8sQI2I260s513sQ2Li2f2H')
       #     m_dwLSSoftwareVersion, m_szFile, m_szComment, m_qwTimeStamp, m_qwTimeStamp2, \
        McdFileHeader2 = struct.Struct(endian + '8sQH2I260s513sQ2Ii2f2H')
        BigTup = MagicMCSHDR, Size, m_wHeaderVersion, m_dwMSSoftwareVersion, \
            m_dwLSSoftwareVersion, m_szFile, m_szComment, m_qwTimeStamp, \
            m_dwStreamCount, m_dwMilliSamplesPerSecond, m_iWindowChoice, \
            m_fTime1, m_fTime2, m_wID1, m_wID2 \
            = McdFileHeader2.unpack(self.f.read(McdFileHeader2.size))
        print BigTup

        
    def readVariablesHeader(self):
        """Only for neurons as variables"""

        MagicIDX1POS, indexPointer, Pointer = \
            self.McdVarHeader.unpack(self.f.read(self.McdVarHeader.size))
        print MagicIDX1POS, indexPointer, Pointer
        """
        self.NumDSPChannelsFiring = 0
        self.TSCountsSum = 0

        self.NeuronsInfo_dict = {}
        for v in xrange(self.NumVars):
            _t = Type, Version, Name, DataOffset, Count, WireNumber, \
                UnitNumber, Gain, Filter, XPos, YPos, WFrequency, \
                ADtoMV, NPointsWave, NMarkers, MarkerLength, Padding = \
                    self.McdVarHeader.unpack(self.f.read(self.McdVarHeader.size))
            if Type != 0: continue
            _Name = Name.rstrip(chr(0)).replace('_unit_0_wf', '')
            self.NeuronsInfo_dict[_Name] = _t
        """

    def readData(self):
        
        for _ in xrange(10):
            StreamName, NrBytes, Timestamp8, Timestamp16 = \
                self.McdDataHeader.unpack(self.f.read(self.McdDataHeader.size))
            McdDataHeader2 = struct.Struct(endian + str(NrBytes-16) + 's')
            _h = McdDataHeader2.unpack(self.f.read(McdDataHeader2.size))[0]
            print StreamName, NrBytes, Timestamp8, Timestamp16
        """
        filemmap = mmap.mmap(self.f.fileno(), 0, None, mmap.ACCESS_READ)
        
        _Freq = float(self.Frequency)
        #_f = self.f
        _getTs = lambda ts: ts / _Freq
        self.NeuronsTimestamps_dict = {}
        for n, _t in self.NeuronsInfo_dict.iteritems():
            offset, tscount = _t[3:5]
            filemmap.seek(offset)
            #_f.seek(offset)
            self.NeuronsTimestamps_dict[n] = map(_getTs, array.array('l', filemmap.read(tscount * 4)))
            #self.NeuronsTimestamps_dict[n] = map(_getTs, array.array('l', _f.read(tscount * 4))) #_a)
        
        filemmap.close()
        """

reader = readMcd("E:\MEAdir\mcd\i3315 49 div 100708-01  controllo_spikes.mcd")
reader()
