import numpy as N

def writePLXfileheader(filename, header, wireinfo, threshloc, windowsize, datalength, numwires=4):
	from struct import pack
	from os import name
	"""
	Writes a PLX file header, as well as all relevant channel headers
	Returns a filehandle to the PLX file.
	
	header, wireinfo - dictionaries of file information generated by
					   hsdio.readhsdheader()
	threshloc 		 - The location of threshold crossings when the
					   spikes were detected. I don't actually know
					   how Offline Sorter uses this information...
	windowsize		 - Number of time-samples per spike.
					   NOTE: there are a lot of names for this variable
					   like spikesize or numpoints. They're all the same.
	datalength		 - Length of the data file, in ticks.
					   length in seconds = datalength/samplingrate
	"""
	f = open(filename, 'wb+')

	# I know it's a doozy, but the following is a structure
	# description of the plexon file header format.
	# Hate to do this to ya, but check out their website until I
	# put the entire format in the comments here...
	# The whole format string is--
	# '<Ii128s14id4c3H46x2600x2600x2048x'
	# number of elements = 7504 (according to struct.calcsize())
	
	# We're going to be packing individual parts of the header
	# structure, and then appending them to a binary string
	
	headerstring = pack('<I', 0x58454c50) # MagicNumber
	headerstring += pack('<i', 105) # PLX version = 105 @ 9/3/2007
	headerstring += pack('<128s', header['comment']) # Comment
	headerstring += pack('<i', header['samplingrate']) # ADFrequency
	headerstring += pack('<i', numwires) # NumDSPChannels
	headerstring += pack('<ii', 0, 0) # NumEventChannels, NumSlowChannels
	headerstring += pack('<i', windowsize) # NumPointsWave
	headerstring += pack('<i', threshloc) # NumPointsPreThr
	headerstring += pack('<i', header['date']['year'])   # Year
	headerstring += pack('<i', header['date']['month'])  # Month
	headerstring += pack('<i', header['date']['day'])    # Day
	headerstring += pack('<i', header['date']['hour']) 	 # Hour
	headerstring += pack('<i', header['date']['minute']) # Minute
	headerstring += pack('<i', 0) 						 # Second
	headerstring += pack('<i', 0) # FastRead (?)
	headerstring += pack('<i', header['samplingrate']) # WaveformFreq
	headerstring += pack('<d', datalength) # LastTimeStamp
	
	# filepos: 200
	if numwires == 1:
		headerstring += '\x01\x01\x0c\x0c'
	elif numwires == 2:
		headerstring += '\x02\x01\x0c\x0c'
	elif numwires == 4:
		headerstring += '\x04\x01\x0c\x0c'
	else:
		raise ValueError, 'Illegal value %d for numwires: can only be 1, 2 or 4' % numwires
	
	# headerstring += N.r_[1].astype('int8').tostring() # Trodalness
	# headerstring += N.r_[numwires].astype('int8').tostring()
	# headerstring += pack('<c', str(4)) # DataTrodalness (these settings give nice behavior)
	
	# Ran into weird behavior with the commented pack above, so I opened up a 
	# PLX file created by OfflineSorter, and I'm inserting exactly what I found in these positions
	
	
	headerstring += pack('<3H', 3000, 5000, 1000) # A fuddling of parameters...
	
	headerstring += pack('<46x') # Padding
	headerstring += pack('<2600x') # int TSCounts[130][5], we don't use these,
	headerstring += pack('<2600x') # int WFCounts[130][5]  so we pad (numints)*(4 bytes per int)
	headerstring += pack('<2048x') # int EVCounts[512]
	
	f.write(headerstring)
	return f


def writePLXchanheader(filehandle, wiredict, thresh, numpoints):
	"""
	Writes a channel header in a PLX file.
	Call multiple times to write multiple channels.
	NOTE: in this context, "channel" means "wire".
	So, one channel header is necesssary for each wire, 
	i.e., one tetrode has 4 channel headers.
		
	filehandle - file object of an open PLX file. The function
				 writePLXfileheader() should have been used
				 to generate the filehandle.
	wiredict   - Elements from the wireinfo dictionary generated
				 by the function hsdio.readHSDheader(). Only pass
				 the entry for the wire this header describes
	thresh	   - The voltage threshold value for the channel. 
	numpoints  - The number of time-samples per spike.
	
	USAGE:
	# for wire i and a threshold array for each wire in the file...
	writePLXchanheader(filehandle, wireinfo[i], threshold[i], numpoints)
	"""
	from struct import pack
	from os.path import split
	# wiredict = wireinfo[i]
	# This function will be called in loops, most likely, 
	# so it's best to pass only the necessary parts
	# The format string for the entire thing is --
	# '<32s32siiiiiiiii640x20xi80xi128x44x'
	# 1020 bytes according to struct.calcsize()
	filehandle.seek(0, 2)
	# use the filename (which should include tetrode number) as the channel name. 
	wirename = split(filehandle.name)[1][:-4]
	# Since we don't have subversion installed, just know that
	# a lot of commented code is old ways of doing things, just saved for posterity.
	# wirename = 'Wire ' + str(wiredict['wirenumber']) + ' Tetrode ' + str(wiredict['channelnumber'])

	SIGname = 'Tetrode SIG ' + str(wiredict['wirenumber'])
	
	chanheaderstring = pack('<32s', wirename) 					#Name of the DSP channel
	chanheaderstring += pack('<32s', SIGname) 					# Name of the whole tetrode it belongs to (I think...)
	chanheaderstring += pack('<i', wiredict['wirenumber'])  	# The wire number
	chanheaderstring += pack('<i', 0) 							# WFRate (something about the max number of waveforms... )
	chanheaderstring += pack('<i', wiredict['channelnumber']) 	# SIG channel number (tetrode number, I think...)
	chanheaderstring += pack('<i', 0) 							# Reference wire... I don't think we use this...
	chanheaderstring += pack('<i', 0) 							# Gain of the channel
	chanheaderstring += pack('<i', 0) 							# Filter (0 or 1, don't know the significance)
	chanheaderstring += pack('<i', thresh) 						# The threshold for this wire
	chanheaderstring += pack('<i', 1) 							# Apparently, we use box-sorting... (0 would indicate templates)
	chanheaderstring += pack('<i', 0) 							# NUnits, at the get-go, there are none. 
	chanheaderstring += pack('<640x') 							# Pad the short Templates[5][64] spot
	chanheaderstring += pack('<20x') 							# Pad the int Fit[5] spot
	chanheaderstring += pack('<i', numpoints) 					# Pad the int SortWidth spot
	chanheaderstring += pack('<80x') 							# Pad the short Boxes[5][2][4] spot
	chanheaderstring += pack('<i', 0) 							# Pad the int SortBeg spot
	chanheaderstring += pack('<128x') 							# Unused comment spot
	chanheaderstring += pack('<44x') 							# 11 bytes of padding to finish it off

	filehandle.write(chanheaderstring)
	pass


def writePLXdatablock(filehandle, spikes, ts, channel, endian=True):
	"""
	Write PLX datablocks corresponding to the data
	found in the arrays spikes, ts, and channel
	We assume these are spikes on the given channel, 
	of the length of the waveforms given in spikes
	
	filehandle - pointer to an open PLX file with headers written in
	             (using writePLXfileheader and  writePLXchanheader)
	spikes     - numspikes by len(spike) by 4 array of spikes on a tetrode
	channel    - the channel number that the spikes are found on
	ts         - time-stamps corresponding the spikes
	"""
	
	from struct import pack

	spikes = N.int16(spikes) # Make the spikes int16's for writing out...

	# if endian:
	# 	spikes.byteswap(True)
	#  		# Do an in-place byte-swap to a different
	# 	# endianness if required

	# Clarification: We don't have to byteswap the ts array because we use
	# the pack() function, which takes care of it.
	# The pack function, however, does not work well with anything but single values at a time,
	# So we use the .tofile property of NumPy arrays to spit out already byte-swapped and typed spikes


	# Only the time-stamps, spikes & channel number change when writing all spikes and 
	# time-stamps out from a particular channel, so we can make 
	# slices of byte-bread to sandwich the time-stamp that stay constant

	topslice = pack('<hH', 1, 0) # Type (1 = spike) and UpperByte of Timestamp = 0
	bottomslice = pack('<3h', 0, 1, spikes.shape[1]) # Unit (0=unsorted), numwaveforms = 1, numpoints per waveform

	for i in range(spikes.shape[0]): # For every spike...
		for j in range(spikes.shape[2]): # Iterate over all wires
			filehandle.write(topslice)
			filehandle.write(pack('<L', int(ts[i]))) # Write time-stamp
			filehandle.write(pack('<h', j+1)) # Write the channel
			filehandle.write(bottomslice)
			spikes[i,:,j].tofile(filehandle) # This part is iffy, I'm hoping all information is preserved...
	pass


def writePLXclusters(plxfile, clusterchoices, *argv):
	"""
	Writes clusterchoices back into the unit assignments of each spike.
	This function can be dumb, and will assume that there are only
	datablocks for spikes. Also, we assume there is only one tetrode
	represented per file. See the 'fast' option below for details.

	USAGE:
	writePLXclusters(plxfile, clusterchoices, 'fast')
	OR
	writePLXclusters(plxfile, clusterchoices, ts)
	OR
	writePLXclusters(plxfile, clusterchoices, ts, channel)
	
	
	The last two options are thorough and careful, but comparatively glacial.
	
	plxfile        - Either file handle to an open PLX file or a string
					 specifying a PLX file.
	clusterchoices - a list or 1D array of length numspikes, with a unit
	                 assignment for each spike in the datset
	ts             - list or 1D array of length numspikes, carrying time-stamps
	                 such that ts[i] is the time of the spike described by
	                 clusterchoices[i]
	fast           - set if the PLX file was created with the writePLX*
	                 functions in this package. i.e., there are only four
	                 wires per file, only spike data blocks, and the blocks are
	                 written in groups of four, one per wire, consecutively.
	                 (unimplemented right now...)
	byteindex	   - If given, the next item should be an array of len(ts)
				     that contains the byte locations of the cluster assignments
					 for much faster cluster insertion

	channel		   - if the PLX file in question contains more than one tetrode,
					 you may specify which channel to deal with. The best way to
					 tell which channels are present is to either open up the PLX
					 file and check, or to use
					 spikes, channels, clusterchoices, ts = readPLXspikes(filename)
					 and then
					 N.unique(channel)
					 to see which channels are present.
					 NOTE that we can only write to one channel at a time.
	"""
	if not argv:
		raise ValueError, "Must supply additional arguments"
	
	if isinstance(plxfile, str):
		wasstring = True
		plxfile = open(plxfile, 'rb+')
	else:
		wasstring = False	
	
	# if plxfile.mode != 'rb+':
		# raise ValueError, "File must be writable"
		
	from struct import pack, unpack

	# Check if the plxfile variable is a file handle
	# or string reference to a filename

	
	# Read out the number of headers of all sorts
	# (there shouldn't be any Slow or Event headers, but
	# we'll read them for completeness' sake anyhoo)
	plxfile.seek(0, 2)
	filelength = plxfile.tell()
	plxfile.seek(140)
	ndsp, nevents, nslow = unpack('<3i', plxfile.read(4*3)) # fread(plxfile, 3, 'i')

	# Seek to the datablocks
	plxfile.seek(7504) # past the file header, relative to beginning of file
	plxfile.seek(1020*ndsp + 296*nevents + 296*nslow, 1) # past the channel headers


	# Now, we run through the datablock

	
	if argv[0] == 'fast':
		# Set our position to the first unit location
		a = plxfile.read(16)
		datatype, trash, time, chan, unit, nw, npw = unpack('<hHLhhhh', a)
		plxfile.seek(-6, 1)
		# Skip ahead all the different wires for a spike
		# Plus the datablock headers for each, and then rewind
		# to get to the next unit assignment
		skipamount = nw*npw*2*ndsp + ndsp*16 - 2 

		for i in range(len(clusterchoices)):
			# Write in the clusterchoices
			plxfile.write(pack('<h', clusterchoices[i]))

			# Seek ahead to the next unit location
			plxfile.seek(skipamount, 1)
	elif argv[0] == 'byteindex':
		byteindex = argv[1]
		for i in range(len(byteindex)):
			plxfile.seek(byteindex[i])
			plxfile.write(pack('<h', clusterchoices[i]))
	else:
		if len(argv) == 1:
			ts = argv[0]
			channel = 'notspecified'
		elif len(argv) == 2:
			ts = argv[0]
			channel = argv[1]
		elif len(argv) > 2:
			raise ValueError, "Only two extra arguments (ts and channel) are allowed"
		
		if not len(ts) == len(clusterchoices):
			raise ValueError, "Number of time-stamps and clusterchoices must be equal"

		while True:
			# Unpack the data header
			try:
				datatype, trash, time, chan, unit, nw, npw = unpack('<hHLhhhh', plxfile.read(16))
			except:
				break
			# So now we're at the end of the dataheader
			
			if datatype == 1:
				# Filter by channel if need be, or fuggedaboutit
				isrightchannel = (chan == channel)
				wedontcare = (channel == 'notspecified')
				
				if isrightchannel or wedontcare:
					# Find which clusterchoice to write
					index = N.where(ts==time)[0]    
					plxfile.seek(-6, 1) # Seek back to the unit byte-location
					plxfile.write(pack('<h', clusterchoices[index])) # Write the unit
					plxfile.seek(nw*npw*2 + 4, 1) # seek nw*npw + 2 int16's ahead

			elif datatype == 5:
				# If it's a continuous a/d block, seek past the data
				plxfile.seek(nw*npw*2, 1)

			elif not (datatype == 1) | (datatype == 4) | (datatype == 5):
				print('Found unrecognized type = ' + str(type))
				raise ValueError, "Unrecognized data type (not a spike, event or continuous a/d block)"

	# If the PLX file was passed as a filename,
	# close the file opened.
	if wasstring: plxfile.close()

def readPLXforHSDextraction(filename):
	"""
	Read out time-stamps, cluster assignments,
	and channel ID's for HSD spike extraction and cluster analysis.
	
	USAGE:
	ts, clusterchoices, savechannel = readPLXforHSDextraction(filename)
	"""
	from scipy.io import fread
	f = open(filename, 'rb')
	f.seek(0,2)
	dl = f.tell() # Get the length of the data file
	f.seek(0)
	header = fread(f, 64, 'l') 
	ndsp =  header[35] # Number of DSP channels
	nevents = header[36] # Number of event channels
	nslow = header[37] # Number of slow channels
	npw = header[38] # Number of points per waveform

	# Seek past some useless information
	skipamt = 5*130 + 5*130 + 512
	skipamt *= 4
	f.seek(skipamt, 1)
	# Seek to the data blocks
	f.seek((1020*ndsp + 296*nevents + 296*nslow), 1)
	
	# Initialize the spike array
	savechannel = []
	clusterchoices = []
	ts = []
	# Read out the data records
	# The minimum length of a datablock is 16 bytes,
	# so we enforce this size
	while f.tell() < (dl - 16):
		# Type 1 indicates a spike
		type = fread(f, 1, 'h')
		junk = fread(f, 1, 'h')
		timestamp = fread(f, 1, 'i')
		spikeinfo = fread(f, 4, 'h')
		ichannel = spikeinfo[0]
		iunit = spikeinfo[1]
		nwf = spikeinfo[2]
		numpoints = spikeinfo[3]
		
		if numpoints > 0:
			f.seek(numpoints*2, 1)
			# wf = fread(f, numpoints, 'h')
			if (type == 1) & (ichannel in channel) & (iunit in unit):
				savechannel.append(ichannel)
				clusterchoices.append(iunit)
				ts.append(timestamp)
				
	savechannel = N.asarray(savechannel)
	clusterchoices = N.asarray(clusterchoices)
	ts = N.asarray(ts)
	
	f.close()
	
	# Format arrays as list of NumPy arrays, list indices
	# correspond to cells
	
	# NOTE--
	# I'm assuming that a cell has only ONE channel associated with it
	# i.e., CHANNEL means TETRODE, not wire.

	# Need to double check this.
	
	clusters = N.unique(clusterchoices)
	returnts = []
	returnchannels = []
	for channel in N.unique(savechannel):
		for cluster in clusters:
			whichspikes = (savechannel == channel) & (clusters == cluster)
			returnts.append(ts[whichspikes])
			returnchannels.append(channel)
	return returnts, N.array(returnchannels)
	
def readPLXspikes(filename, unit = 'all', channel = None, getbytes = False,  maxspikes = 20000):
	# TODO: expand functionality of readPLXspikes
	# so that we don't have to make special-function
	# code to read out this or that alone from a PLX file
	"""
	Read out spikes from one channel of a PLX file, optionally
	providing the variable spikeclass, which can be a list
	or NumPy array containing the cluster assignments
	of spikes to pull out.
	
	One intended use is to pull out spikes
	isolated from noise in a PLX file, and then sort
	them, so as not to confound feature extraction and
	clustering algorithms with noise.
	
	
	USAGE:
	# Where unit is 'all', 'sorted', or a list of numbers from 1-28.
	unitsicareabout = [1,3,5]
	savespikes, channels, clusterchoices, ts, byteindex = readPLXspikes(filename, unit=unitsicareabout)
	
	NOTE:
	Make sure only one tetrode is present per PLX file
	Offline Sorter provides a utility to split a PLX file
	into multiple tetrodes.
	If this is really inconvenient, email me at
	alexwilt@umich.edu, and we can work something out
	to change this behavior.
	"""
	if channel == None:
		# If there's no channel, just make a huge array
		channel = N.r_[0:160].astype('int16')
	if (unit == None) | (unit == 'all'):
		# Ditto
		unit = N.r_[0:28].astype('int16')
	elif (unit == 'sorted'):
		unit = N.r_[1:28].astype('int16')
	unit = N.asarray(unit)
	
	f = open(filename, 'rb')
	f.seek(0,2)
	dl = f.tell() # Get the length of the data file
	f.seek(0)
	header = N.fromfile(f, 'l', 64) 
	ndsp =  header[35] # Number of DSP channels
	nevents = header[36] # Number of event channels
	nslow = header[37] # Number of slow channels
	npw = header[38] # Number of points per waveform

	# Seek past some useless information
	skipamt = 5*130 + 5*130 + 512
	skipamt *= 4
	f.seek(skipamt, 1)
	# Seek to the data blocks
	f.seek((1020*ndsp + 296*nevents + 296*nslow), 1)
	
	nossochan = 32
	
	# Initialize the spike array
	spikes = N.empty((maxspikes*nossochan, npw), dtype='float64')
	savechannel = N.zeros((maxspikes*nossochan), dtype='int8') - 1
	clusterchoices = N.zeros((maxspikes*nossochan), dtype='int8')
	ts = N.zeros((maxspikes*nossochan), dtype='int32')
	if getbytes: byteindex = N.zeros((maxspikes*4), dtype='int64')
	spikecount = 0
	
	
	# Read out the data records
	# The minimum length of a datablock is 16 bytes,
	# so we enforce this size
	while f.tell() < (dl - 16):
		# Type 1 indicates a spike
		
		type = N.fromfile(f, 'h', 1)
		junk = N.fromfile(f, 'h', 1)
		timestamp = N.fromfile(f, 'i', 1)
		ichannel = N.fromfile(f, 'h', 1)
		ibyte = f.tell()
		iunit, nwf, numpoints = N.fromfile(f, 'h', 3)
		
		if numpoints > 0:
			wf = N.fromfile(f, 'h', numpoints)
			if (type == 1) & (ichannel in channel) & (iunit in unit):
				spikes[spikecount] = wf
				savechannel[spikecount] = ichannel
				clusterchoices[spikecount] = iunit
				ts[spikecount] = timestamp
				if getbytes: byteindex[spikecount] = ibyte
				spikecount += 1
				if spikecount == maxspikes*nossochan: break # since spikes are read in one wire at a time, we have to multiply by 4 (4 wires per tetrode)
	
	
	if spikecount == 0: raise ZeroDivisionError, 'There are no spikes in this file'
	
	
	
	# Trim up the arrays to contain just the extracted info
	spikes = spikes[:spikecount,:]
	savechannel = savechannel[:spikecount]
	if getbytes: byteindex = byteindex[:spikecount]
	clusterchoices = clusterchoices[:spikecount]
	ts = ts[:spikecount]
	channels = N.unique(savechannel)
	
	# Now make spikes into the 3D array we've gotten used to--
#	numevents, numpoints = spikes.shape
#	numspikes = numevents/channels.size
#	print numevents, numpoints, channels.size, numspikes
#	spikes = N.swapaxes(spikes.reshape(numspikes, channels.size, numpoints), 1, 2)
	
	f.close()
	
	if getbytes: return spikes, savechannel, clusterchoices, ts, byteindex
	return spikes, savechannel, clusterchoices, ts
	
def resortPLX(filename=None, maxclusters=25, maxspikes=500000, spikeworks=False):
	# TODO:
	# Allow for selected-unit resorting, multi-channel recordings
	# At least generate an error message now.
	"""
	Grab a PLX file, and resort everything on all channels,
	as seen in Offline Sorter.
	We use 3 PCA coefficients per wire and KlustaKwik to sort.
	
	USAGE:
	resortPLX(maxclusters=20, maxspikes=500000)
		
	A file dialog will pop up, pick the PLX file to resort,
	and all 
	
	NOTE:
	This function will resort ALL spikes on ALL channels.
	Also, your file will be overwritten. Make a copy if you want
	to save any clustering already in the PLX file.
	
	If you would like to leave spikes out:
		Invalidate the waveforms you don't want in Offline Sorter
		and reexport the PLX file, choosing the option to ignore
		invalidated waveforms.
	If you would like to leave channels out:
		Use the PlexUtil program, provided by Plexon,
		to split the PLX file into separate channels as desired.
	"""
	
	from wavefilter import pcafeatures, kk
	from struct import unpack
	
	if filename == None:
		filename = str(getplxfilename())
	print('\nResorting ' + filename)
	print('Reading spikes out of the PLX file...')
	# Read out the spikes of the 0-cluster, aka, the unsorted spikes
	if spikeworks is True:
		spikes, channels, clusterchoices, ts = readPLXspikes(filename, unit='all', maxspikes=maxspikes, getbytes=False)
	else:
		spikes, channels, clusterchoices, ts, byteindex = readPLXspikes(filename, unit = 'all', maxspikes = maxspikes)
	byteindex = byteindex[::4]
	uniquechannels = N.unique(channels)
	# Read out samplingrate, windowsize and threshloc
	# These parameters will be useful in computing better PCA components
	f  = open(filename, 'rb+')
	f.seek(136)
	samplingrate = unpack('<i', f.read(4))
	f.seek(152)
	windowsize, peaksample = unpack('<ii', f.read(8))

	print('\tCalculating PCA features for sorting...')
	# Construct the window used for PCA
	width = 0.3 # In milliseconds
	# Convert windowsize from ms to samples
	halfwindow = N.floor((width / 2.) / 1000*N.r_[samplingrate]).astype('int16')
	# Construct window masking array
	sortind = N.r_[halfwindow-peaksample:peaksample+halfwindow]
	sortind = sortind[sortind >= 0]
	sortind = sortind[sortind <= windowsize]
	numcoeffsperwire = 3
	# Get 3 PCA features per wire from all 4 wires of the spike array
	coeffs = pcafeatures(spikes[:,sortind,:], numcoeffsperwire)
	del spikes # for memory usage
	
	print('\tSorting ' + str(coeffs.shape[0]) + ' spikes...')
	clusterchoices = kk(coeffs, maxclusters, exelocation = "C:\spikeworks\KlustaKwik.exe") # Sort with KlustaKwik
	
	print('\tReinserting cluster choices...')
	if spikeworks is True:
		writePLXclusters(f, clusterchoices, 'fast')
	else:
		writePLXclusters(f, clusterchoices, 'byteindex', byteindex)
		
	f.close()
	print('PLX file resorted')
	
def writePLXspikes(filename, spikes, ts, header, wireinfo):
	"""
	A weensy helper function to turn a spike array, along with
	some information about where the spikes came from,
	into a PLX file straight from Python.
	This has been mostly used for testing, 
	it's not in any serious workflow.
	
	USAGE:
	writePLXspikes(filename, spikes, ts, header, wireinfo)
	
	"""
	numspikes, numpoints, numwires = spikes.shape
	# Write file header
	f = writePLXfileheader(filename, header, wireinfo, numpoints/2, numpoints, header['datalength'])
	# Write channel headers
	for i in range(numwires):
		writePLXchanheader(f, wireinfo[i], 0, numpoints)
	# Write spikes in
	writePLXdatablock(f, spikes, ts, 1, True)
	f.close()
	
def getplxfilename():
	"""
	A helper-function used by resortPLXspikes.
	Makes a file GUI to grab PLX files. 
	Usage:
	
	filename = getplxfilename()
	
	simple enough.
	"""
	import wx
	from os import getcwd
	app = wx.PySimpleApp()
	
	filename = wx.FileSelector(
		message='Choose a PLX file to resort', 
		wildcard = 'Plexon file (*.plx)|*.plx',
		default_path = getcwd()
		)
	app.Destroy()
	return filename