from importlibs import *
"""
import struct
import ctypes
import array
import collections
import binascii
import sys
import os
import time
#import numpy
import mmap

endianness_dict = {
    "native-native":    '@',
    "native-standard":  '=',
    "little":           '<',
    "big":              '>',
    "network":          '!'
}
endian = endianness_dict.get(sys.byteorder, "native-standard")
"""

__name__ = "readnex"
__revision__ = "$Revision: 0.13 - 16 March 2010$"
__author__ = "Andrea Maffezzoli"



class readNex(object):
    """Applying struct.Struct to unpack/decode binary data from plx files"""
    

    ###########################################################################
    # FileHeader
    ###########################################################################
    NexFileHeader = struct.Struct(endian + '2i256sd4i256s')
    #NexFileHeader_size = FileHeader.size

    ###########################################################################
    # Spike Channel Header
    ###########################################################################
    NexVarHeader = struct.Struct(endian + '2i64s6i4d3i68s')
    #NexVarHeader_size = SpikeChannelHeader_struct.size

    ###########################################################################
    # 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):

        NexFileHeader = MagicNumber, self.NexVersion, Comment, \
            self.Frequency, self.Beg, self.End, self.NumVars, \
            self.NextFileHeader, Padding = \
                self.NexFileHeader.unpack(self.f.read(self.NexFileHeader.size))
        
    def readVariablesHeader(self):
        """Only for neurons as variables"""

        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.NexVarHeader.unpack(self.f.read(self.NexVarHeader.size))
            if Type != 0: continue
            _Name = Name.rstrip(chr(0)).replace('_unit_0_wf', '')
            self.NeuronsInfo_dict[_Name] = _t


    def readData(self):

        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()
