from ij import *
from ij import IJ, ImagePlus, ImageListener, VirtualStack, ImageStack
from ij.io import DirectoryChooser
from ij.gui import ImageCanvas
import os
from ij.plugin import ContrastEnhancer,StackCombiner,AVI_Reader
import random
import pickle
from java.lang import Exception, Double

from java.lang.System import getProperty

import sys

### NOTE THIS CODE WAS DESIGNED TO RUN AS A MACRO IN FIJI (IMAGEJ)
### TO USE THIS CODE, FIRST DOWNLOAD AND INSTALL IMAGEJ
### YOU WILL ALSO NEED TO INCLUDE THE "jmatio.jar" IN THE JAR FOLDER
### SINCE FIJI IS CROSS-PLATFORM, THIS "SHOULD" WORK WITH ANY OPERATING 
### SYSTEM BUT WE USE IT ON LINUX AND MAC COMPUTERS
### IT MIGHT BE A BIT CONFUSING TO SET THIS SCRIPT UP SO FEEL FREE TO CONTACT
### THE CORRESPONDING AUTHORS FOR HELP. THERE IS A SLIGHTLY EMBARRASSING 
### TUTORIAL VIDEO THAT WE CAN FORWARD TO YOU.
### ALSO, I WOULD NOT RECOMMEND BUILDING ON THE SCRIPT, "JYTHON" IS A STUPID
### LANGUAGE AND THE CURRENT POSSIBILITIES WITH POPULAR VR VISUALIZATION
### LIBRARIES WOULD BE WONDERFUL. WE HAVE STARTED TO GO IN THAT DIRECTION.
### IF YOU ARE THINKING THE SAME THING PERHAPS WE SHOULD TALK (benjamin.dunn@ntnu.no)
### VISUALIZATION IS A SURPRISINGLY USEFUL TOOL (THOUGH A BIT OBVIOUS NOW)



##### put jmatio.jar in the jar folder!!!!
from com.jmatio.io import MatFileReader, MatFileWriter
from com.jmatio.types import MLDouble, MLChar

import copy
import csv
import time

from org.apache.commons.math3.linear import Array2DRowRealMatrix, SingularValueDecomposition, LUDecomposition, RealMatrix
from org.apache.commons.math3.util import MathArrays

from java import io

import time
import math

from jarray import array, zeros

from javax.swing import JScrollPane, JPanel, JComboBox, JLabel, JFrame, JTextField, JCheckBox, JButton, JToggleButton, JFileChooser, BorderFactory, JFormattedTextField, JDialog, JSlider, Timer, JOptionPane, MutableComboBoxModel, SpinnerNumberModel, JSpinner, JTextArea, JTable, SwingUtilities, DefaultCellEditor, JTabbedPane
from javax.swing.filechooser import FileNameExtensionFilter
from javax.swing.table import DefaultTableModel, DefaultTableCellRenderer, TableCellRenderer

from javax.swing.event import ChangeListener
from java.awt import Color, GridLayout, GridBagLayout, KeyboardFocusManager, Toolkit, GraphicsEnvironment
from java.awt.event import ActionListener, ItemListener, ItemEvent, FocusListener, WindowAdapter, KeyListener, KeyEvent
from java.text import NumberFormat

from org.jfree.chart import ChartFactory, ChartPanel, JFreeChart, ChartFrame
from org.jfree.chart.axis import NumberAxis, SymbolAxis, NumberTickUnit
from org.jfree.chart.plot import PlotOrientation, XYPlot
from org.jfree.chart.renderer.xy import XYLineAndShapeRenderer
from org.jfree.data.xy import XYDataset, XYSeries, XYSeriesCollection
from org.jfree.ui import ApplicationFrame, RefineryUtilities#, Spacer
from org.jfree.data.statistics import HistogramDataset, HistogramType


from java.awt.event import MouseAdapter, InputEvent
from java.util import BitSet

from org.scijava.java3d.utils.geometry import Sphere, Box
from org.scijava.java3d.utils.universe import SimpleUniverse
from org.scijava.java3d.utils.picking import PickCanvas, PickResult
from org.scijava.java3d.utils.behaviors.mouse import MouseRotate, MouseTranslate, MouseZoom

from org.scijava.java3d import Canvas3D, BranchGroup, Transform3D, TransformGroup, Shape3D, BoundingSphere, Background, Appearance, ColoringAttributes, Material, DirectionalLight, RenderingAttributes, Switch, LineArray, LineAttributes, IndexedQuadArray, TransparencyAttributes, BoundingBox, View, GraphicsConfigTemplate3D
from org.scijava.vecmath import Vector3f, Color3f, Point3d, Vector3d, AxisAngle4d, Matrix3f, Matrix3d

import ij.measure.Minimizer

import ratemapgenerator

from javax.sound.sampled import AudioInputStream, AudioSystem, Clip




print (sys.version)
# a = Double.NaN
# print a
# if Double.isNaN(a):
#   print "a is NaN!"
clear = lambda: os.system('cls' if os.name=='nt' else 'clear')


class plotthingy():
  def updatet(self, t, winsize):
    mm = t-winsize
    if(mm < 0):
      mm = 0
      MM = mm+2*winsize
    else:
      MM = t+winsize
    if(MM > len(self.xvals)-1):
      MM = len(self.xvals)-1
      mm = MM-2*winsize
      if(mm < 0):
        mm = 0
    if(MM-mm < 0.01):
      MM = mm+0.01
    (self.plot.getDomainAxis()).setRange(mm, MM)
    self.seriesT.clear()
    self.seriesT.add(t, self.rangemm, False)
    self.seriesT.add(t, self.rangeMM, True)

  def updatebitchskippies(self, skippies):
    self.seriesA.clear()
    if(len(self.centeredvals)>2):
      for i in range(0, len(self.xvals), skippies):
        if(i == len(self.xvals)-1):
          self.seriesA.add(self.xvals[i], self.centeredvals[i], True)
        else:
          self.seriesA.add(self.xvals[i], self.centeredvals[i], False)
    if(len(self.tracevals)>2):
      for i in range(0, len(self.xvals), skippies):
        if(i == len(self.xvals)-1):
          self.seriesA.add(self.xvals[i], self.tracevals[i], True)
        else:
          self.seriesA.add(self.xvals[i], self.tracevals[i], False)

  def updatebitchcentered(self, xvals, centeredvals, skippies):
    self.xvals = xvals
    self.seriesA.clear()
    self.seriesB.clear()
    self.tracevals = []
    self.centeredvals = centeredvals

    if(len(centeredvals)<1):
      print 'WTF: you need trace data for this shit to work!'
      stop

    T = len(xvals)
    meanval = sum(centeredvals)/float(T)
    #tempval = 0.
    #for i in range(0, len(xvals), 1):
      #tt = (centeredvals[i]-meanval)
      #tempval += tt*tt/float(T)
    #stdval = math.sqrt(tempval)
    #for i in range(0, len(xvals), 1):
      #self.centeredvals[i] = (centeredvals[i] - meanval)/stdval
    self.seriesB.add(xvals[0], meanval, True)
    self.seriesB.add(xvals[T-1], meanval, False)

    for i in range(0, len(xvals), skippies):
      if(i == len(xvals)-1):
        self.seriesA.add(xvals[i], self.centeredvals[i], True)
      else:
        self.seriesA.add(xvals[i], self.centeredvals[i], False)
    #self.rangemm = -3.05
    #self.rangeMM = 3.05
    self.rangemm = min(self.centeredvals)
    self.rangeMM = max(self.centeredvals)
    (self.plot.getRangeAxis()).setRange(self.rangemm, self.rangeMM)
    mm = min(xvals)
    MM = max(xvals)
    if(MM-mm < 0.01):
      MM = mm+0.01
    (self.plot.getDomainAxis()).setRange(mm, MM)

  def updatebitchtrace(self, xvals, tracevals, skippies):
    self.xvals = xvals
    self.tracevals = tracevals
    self.centeredvals = []
    self.seriesA.clear()

    if(len(tracevals)<1):
      print 'WTF: you need trace data for this shit to work!'
      stop

    maxtraces = -100000000000000000.
    mintraces = 1000000000000000000.
    maxnfr = -10000000000000000000.
    minnfr = 100000000000000000000.
    for i in range(0, len(xvals), 1):
      if(tracevals[i]<mintraces):
        mintraces = tracevals[i]
      if(tracevals[i]>maxtraces):
        maxtraces = tracevals[i]
    denom = 1.
    if(abs(maxtraces-mintraces)>0.0000000001):
      denom = maxtraces-mintraces
    for i in range(0, len(xvals), 1):
      self.tracevals[i] = (tracevals[i] - mintraces)/denom


    for i in range(0, len(xvals), skippies):
      if(i == len(xvals)-1):
        self.seriesA.add(xvals[i], self.tracevals[i], True)
      else:
        self.seriesA.add(xvals[i], self.tracevals[i], False)
    self.rangemm = -0.05
    self.rangeMM = 1.05
    (self.plot.getRangeAxis()).setRange(-0.05, 1.05)
    mm = min(xvals)
    MM = max(xvals)
    if(MM-mm < 0.01):
      MM = mm+0.01
    (self.plot.getDomainAxis()).setRange(mm, MM)
  def __init__(self, cc=Color.blue):
    self.xvals = []
    self.seriesA = XYSeries("A")
    for i in range(2):
      x = 10.*i/1.-5.
      y = 0.
      self.seriesA.add(x, y)

    self.tracevals = []
    self.centeredvals = []

    self.seriesT = XYSeries("Time")
    self.seriesT.add(2, 0, False)
    self.seriesT.add(2, 1, True)

    a2 = XYSeriesCollection()
    a2.addSeries(self.seriesA)
    a2.addSeries(self.seriesT)

    if(cc==Color.red):
      self.seriesB = XYSeries("B")
      for i in range(2):
        x = 10.*i/1.-5.
        y = 0.
        self.seriesB.add(x, y)
      a2.addSeries(self.seriesB)

    self.chart = ChartFactory.createScatterPlot('', '', '', a2, PlotOrientation.VERTICAL, False, False, False)
    self.plot = self.chart.getXYPlot()
    renderer = XYLineAndShapeRenderer()
    renderer.setSeriesLinesVisible(0, True)
    renderer.setSeriesShapesVisible(0, False)
    renderer.setSeriesPaint(0, cc)
    if(cc==Color.red):
      renderer.setSeriesLinesVisible(2, True)
      renderer.setSeriesShapesVisible(2, False)
      renderer.setSeriesPaint(2, Color.black)

    self.plot.setRenderer(renderer)
    self.plot.setDomainCrosshairVisible(False)
    self.plot.setRangeCrosshairVisible(False)
    self.plot.setDomainGridlinesVisible(False)
    self.plot.setRangeGridlinesVisible(False)
    self.plot.setDomainMinorGridlinesVisible(False)
    self.plot.setRangeMinorGridlinesVisible(False)
    self.plot.setDomainPannable(False)
    self.plot.setRangePannable(False)
    self.plot.setDomainZeroBaselineVisible(True)
    self.plot.setRangeZeroBaselineVisible(False)
    self.plot.setBackgroundPaint(Color.white)
    self.plot.getRangeAxis().setVisible(False)
    self.plot.getDomainAxis().setVisible(False)
    self.panel = ChartPanel(self.chart)


class plotrenderer(DefaultTableCellRenderer) :
  def __init__(self):
    DefaultTableCellRenderer.__init__(self)
    self.emptypanel = JPanel() # EMPTY PANEL
    self.winsize = 5000
    self.timeguy = []
    self.allplots = []
    self.alltypies = []
    self.N = 0
    self.currentskippy = 5

  def updatewindowsize(self, winsize, skippies):
    self.winsize = int(round(winsize))
    if(abs(skippies-self.currentskippy)>0.1):
      self.currentskippy = int(round(skippies + 0.))
      for i in range(len(self.allplots)):
        self.allplots[i].updatebitchskippies(self.currentskippy)

  def addone(self, xvals, plottingvalues, typie):
    self.timeguy = xvals
    self.alltypies.append(typie)
    if(typie == 'centered'):
      newone = plotthingy(Color.red)
      newone.updatebitchcentered(xvals, plottingvalues, self.currentskippy)
    else:
      newone = plotthingy()
      newone.updatebitchtrace(xvals, plottingvalues, self.currentskippy)
    self.allplots.append(newone)
    self.N = len(self.allplots)

  def getTableCellRendererComponent(self, table, value, isSelected, hasFocus, rowIndex, vColIndex):
    if(value == None or value<0):
      return self.emptypanel
    indN = table.convertRowIndexToModel(rowIndex)
    self.allplots[indN].updatet(value, self.winsize)
    return self.allplots[indN].panel




class labelcellrenderer(DefaultTableCellRenderer):
  def __init__(self):
    self.scrollpane = JScrollPane()
    self.labelcell = JTextArea()
    self.labelcell.setLineWrap(True)
    self.labelcell.setWrapStyleWord(True)
    self.scrollpane.getViewport().add(self.labelcell)

  def getTableCellRendererComponent(self, table, value, isSelected, hasFocus, row, column):
    if(isSelected):
      self.scrollpane.setForeground(table.getSelectionForeground())
      self.scrollpane.setBackground(table.getSelectionBackground())
      self.labelcell.setForeground(table.getSelectionForeground())
      self.labelcell.setBackground(table.getSelectionBackground())
    else:
      self.scrollpane.setForeground(table.getForeground())
      self.scrollpane.setBackground(table.getBackground())
      self.labelcell.setForeground(table.getForeground())
      self.labelcell.setBackground(table.getBackground())

    self.labelcell.setText(String(value))
    self.setSize(table.getColumnModel().getColumn(column).getWidth(), self.labelcell.getPreferredSize().height)
    if(table.getRowHeight(row) < self.labelcell.getPreferredSize().height):
      table.setRowHeight(row, self.labelcell.getPreferredSize().height)
    return self.labelcell

class labelcelleditor(DefaultCellEditor):
  def __init__(self):
    self.labelcell = JTextArea()
    self.labelcell.setLineWrap(True)
    self.labelcell.setWrapStyleWord(True)
    self.scrollpane = JScrollPane()
    self.scrollpane.getViewport().add(self.labelcell)
    DefaultCellEditor.__init__(self, JCheckBox())

  def getTableCellEditorComponent(self, table, value, isSelected, row, col):
    self.labelcell.setText(String(value))
    return(self.scrollpane)

  def getCellEditorValue(self):
    return self.labelcell.getText()


class analysistablemodel(DefaultTableModel):
  def setupdatefunction(self, updatefunction):
    self.updatefunction = updatefunction

  def causeanupdate(self):
    self.updatefunction.updatet(-1)

  def __init__(self):
    self.currentt = 0
    self.updatefunction = None
    self.windowsize = 10
    self.data = []
    self.plottingvalues = []
    self.columnNames = ['#', ' ', 'Label', 'Value', 'Plot']
    self.columnClasses = [Integer, Boolean,  JTextArea, Float, ChartPanel]
    DefaultTableModel.__init__(self, self.data, self.columnNames)

  def addathing(self, label, plottingvals):
    i = len(self.data)
    self.data.append( [Integer(i+1), Boolean(1),  label, Float(0.), 1] )
    self.plottingvalues.append(plottingvals)
    self.setDataVector(self.data, self.columnNames)

  def updatet(self, tvid=-100):
    if(tvid<0):
      t = self.currentt
    else:
      t = tvid
      if(t == self.currentt):
        return
      self.currentt = t
    for i in range(len(self.data)):
      if(Boolean(self.getValueAt(i, 1)) == Boolean(1)):
        self.setValueAt((self.plottingvalues[i])[t], i, 3)
        self.data[i][4] = t
        self.fireTableCellUpdated(i, 4)

  def getRowCount(self):
    return(len(self.data))
  def getColumnCount(self):
    return(len(self.columnNames))
  def getValueAt(self, rowI, colI):
    return(self.data[rowI][colI])
  def getColumnName(self, columnIndex):
    return self.columnNames[columnIndex]
  def getColumnClass(self, columnIndex):
    return self.columnClasses[columnIndex]
  def isCellEditable(self, rowIndex, columnIndex):
    if(columnIndex == 1 or columnIndex == 2):
      return(True)
    return(False)
  def setValueAt (self, value, rowIndex, columnIndex):
    if(columnIndex == 1):
      value = Boolean(value)
      self.data[rowIndex][columnIndex] = value
      self.fireTableCellUpdated(rowIndex, columnIndex)
      if(value == Boolean(1)):
        self.updatet(-1)
      else:
        self.data[rowIndex][4] = -1 
        self.fireTableCellUpdated(rowIndex, 4)
        self.data[rowIndex][3] = 0
    else:
      self.data[rowIndex][columnIndex] = value
      self.fireTableCellUpdated(rowIndex, columnIndex)



class analysistable(JPanel):
  def addanewrowtothetable(self, plotvalues, texty, typie):
    T = len(plotvalues)
    self.chartrendererthing.addone(range(T), plotvalues, typie)
    self.tablemodel.addathing(texty, plotvalues)

  def loadanalysisdata(self, filename):
    dafile = open(filename)
    rawfile = dafile.readlines()
    reader = csv.reader(dafile)
    Ta = len(rawfile)-1

    dafile.seek(0)
    Na = -1
    for row in reader:
      Na = len(row)
      break
    dafile.seek(0)

    labels = []
    typies = []
    analdata = []
    for i in range(Na):
      analdata.append(zeros(Ta, 'd'))

    print 'Printing the first 10 lines of the analysis csv file (just a visual check)'
    count = 0
    for row in reader:
      if(count < 10):
        print row

      for j in range(Na):
        if(count == 0):
          labels.append(row[j])
        elif(count == 1):
          typies.append(row[j])
        else:
          valval = float(row[j])
          if(valval < -100000):
            valval = 0.
          (analdata[j])[count-2] = valval
      count += 1
      if( count%(25000) == 0 ):
        print '%2.2f percent done reading in the analysis csv file'%(100*float(count)/float(Ta))
    print '%2.2f percent done reading in the analysis csv file'%(100*float(count)/float(Ta))
    dafile.close()

    for i in range(len(labels)):
      self.addanewrowtothetable(analdata[i], labels[i], typies[i])
    return


  def setupdatefunction(self, updatefunction):
    self.tablemodel.setupdatefunction(updatefunction)
    self.updatefunction = updatefunction


  def __init__(self):
    self.updatefunction = None

    self.currentt = 0

    self.setLayout(GridBagLayout())
    self.setAlignmentX(Component.LEFT_ALIGNMENT)

    c = GridBagConstraints()
    c.insets = Insets(2, 2, 2, 2)
    c.weighty = 0
    c.weightx = 0
    c.fill = c.BOTH
    c.weightx = 1
    c.weighty = 0.0001

    c.gridx = 0
    c.gridy = 0
    c.gridwidth = 1
    c.gridheight = 1

    c.weightx = 0.001
    self.add(JLabel('Window size (frames) '), c)
    c.weightx = 0.999
    c.gridx = 1
    self.jwindowsize = JTextField('5000')
    self.add(self.jwindowsize, c)

    c.gridx = 2
    c.weightx = 0.001
    self.add(JLabel(' Increment (frames) '), c)
    c.gridx = 3
    c.weightx = 0.999
    self.jskippies = JTextField('5')
    self.add(self.jskippies, c)

    c.gridx = 4
    class buttonlistener(ActionListener):
      def __init__(self, parent):
        self.papa = parent
      def actionPerformed(self, event):
        self.papa.chartrendererthing.updatewindowsize(float(self.papa.jwindowsize.getText()), float(self.papa.jskippies.getText()))
	self.papa.tablemodel.updatet(-1)

    updatesize = JButton('Update')
    updatesize.addActionListener(buttonlistener(self))
    self.add(updatesize, c)

    self.tablemodel = analysistablemodel()
    self.table = JTable(self.tablemodel) 
    self.table.setRowHeight(50)
    self.table.setFillsViewportHeight(True);

    self.chartrendererthing = plotrenderer()
    self.chartrendererthing.updatewindowsize(float(self.jwindowsize.getText()), float(self.jskippies.getText()))
    self.table.setDefaultRenderer(ChartPanel, self.chartrendererthing)

    self.table.setDefaultRenderer(JTextArea, labelcellrenderer())
    self.table.setDefaultEditor(JTextArea, labelcelleditor())

    ((self.table.getColumnModel()).getColumn(0)).setPreferredWidth(40)
    ((self.table.getColumnModel()).getColumn(1)).setPreferredWidth(40)
    ((self.table.getColumnModel()).getColumn(2)).setPreferredWidth(100)
    ((self.table.getColumnModel()).getColumn(3)).setPreferredWidth(80)
    ((self.table.getColumnModel()).getColumn(4)).setPreferredWidth(875)
    self.table.setAutoCreateRowSorter(True)
    self.table.getRowSorter().setSortable(4, False)

    c.gridy = 1
    c.gridx = 0
    c.gridwidth = 5
    c.weighty = 1.
    self.add(JScrollPane(self.table), c)


class superfunfilter(JDialog):
  def __init__(self, parentguy):
    self.parentguy = parentguy
    self.setLocationRelativeTo(None)
    self.setTitle("Fun filter")

    firingratepanel = JPanel()
    firingratepanel.setLayout(GridBagLayout())
    cpan = GridBagConstraints()
    cpan.insets = Insets(3, 3, 3, 3)
    cpan.fill = GridBagConstraints.HORIZONTAL
    cpan.gridx = 0
    cpan.gridy = 0
    cpan.gridwidth = 1
    firingratepanel.add(JLabel('Time bin width (ms)'), cpan)
    cpan.gridx = 3
    self.timebin = JTextField('20   ')
    firingratepanel.add(self.timebin, cpan)

    cpan.gridx = 0
    cpan.gridy = 1
    firingratepanel.add(JLabel('Smoothing window size (ms)'), cpan)
    cpan.gridx = 3
    self.frtimewindow = JTextField('200   ')
    firingratepanel.add(self.frtimewindow, cpan)

    cpan.gridwidth=4
    cpan.gridy = 2
    cpan.gridx = 0
    frhist = JButton('Firing rate histograms')
    class frhistlistener(ActionListener):
      def __init__(self, parentguy):
        self.parentguy = parentguy
      def actionPerformed(self, event):
        self.parentguy.parentguy.displayfiringratehistogram(float(self.parentguy.timebin.getText()), float(self.parentguy.frtimewindow.getText()))
    frhist.addActionListener(frhistlistener(self))
    firingratepanel.add(frhist, cpan)

    cpan.gridy = 3
    firingratepanel.add(JLabel(''), cpan)
    cpan.gridwidth = 1

    cpan.gridy = 6
    cpan.gridx = 0
    firingratepanel.add(JLabel('Minimum firing rate (Hz)'), cpan)
    cpan.gridx = 3
    self.minfiringrate = JTextField('60')
    firingratepanel.add(self.minfiringrate, cpan)

    cpan.gridy = 8
    cpan.gridx = 0
    firingratepanel.add(JLabel('Minimum time min rate sustained (ms)'), cpan)
    cpan.gridx = 3
    self.frtimesustained = JTextField('40')
    firingratepanel.add(self.frtimesustained, cpan)

    cpan.gridy = 9
    cpan.gridx = 0
    firingratepanel.add(JLabel('Added slowdown time around event (ms)'), cpan)
    cpan.gridx = 3
    self.addslowdowntime = JTextField('200')
    firingratepanel.add(self.addslowdowntime, cpan)

    extfileguy = JPanel()
    self.moviefilename = JLabel("Movie file (csv)")
    extfileguy.add(self.moviefilename)
    self.moviefilepath = ''

    class moviefilenamelistener(ActionListener):
      def __init__(self, jguy):
        self.jguy = jguy
      def actionPerformed(self, event):
        fc = JFileChooser(self.jguy.parentguy.data.currentdirectory)
        fc.setFileFilter(FileNameExtensionFilter("Movie file", ["csv"]))
        fc.setDialogTitle('Movie file with segments of cool')
        ret = fc.showOpenDialog(None)
        if(ret == 0):
          self.jguy.moviefilepath = fc.selectedFile.getAbsolutePath()
          self.jguy.moviefilename.setText('%s'%(fc.selectedFile.getName()))
    moviefilenamebut = JButton('...')
    moviefilenamebut.addActionListener(moviefilenamelistener(self))
    extfileguy.add(moviefilenamebut)

    self.tabbedpane = JTabbedPane()
    self.tabbedpane.addTab('External file', extfileguy)
    self.tabbedpane.addTab('Cells', firingratepanel)
    self.tabbedpane.setEnabledAt(1, False)

    self.setLayout(GridBagLayout())
    self.cguy = GridBagConstraints()
    self.cguy.insets = Insets(3, 3, 3, 3)
    self.cguy.fill = GridBagConstraints.HORIZONTAL

    self.cguy.gridy = 0
    self.cguy.gridx = 0
    self.cguy.gridwidth=4
    self.add(self.tabbedpane, self.cguy)

    self.cguy.gridx = 0
    self.cguy.gridy = 10
    self.cguy.gridwidth=1
    self.add(JLabel('In rate speed up'), self.cguy)
    self.cguy.gridx = 3
    self.inratespeedup = JTextField('0.1')
    self.add(self.inratespeedup, self.cguy)

    self.cguy.gridy = 12
    self.cguy.gridx = 0
    self.add(JLabel('Out rate speed up'), self.cguy)
    self.cguy.gridx = 3
    self.outratespeedup = JTextField('100')
    self.add(self.outratespeedup, self.cguy)

    self.cguy.gridy = 14
    self.cguy.gridx = 0
    self.cguy.gridwidth=4
    class fastforwardlistener(ActionListener):
      def __init__(self, parentguy):
        self.parentguy = parentguy
      def actionPerformed(self, event):
        whichtab = self.parentguy.tabbedpane.getSelectedIndex()
        if(whichtab==0):
          self.parentguy.parentguy.funwithfiringratefilterfromfile(self.parentguy.moviefilepath, float(self.parentguy.inratespeedup.getText()), float(self.parentguy.outratespeedup.getText()))
        else:
          self.parentguy.parentguy.funwithfiringratefilter(float(self.parentguy.timebin.getText()), float(self.parentguy.frtimewindow.getText()), float(self.parentguy.minfiringrate.getText()), float(self.parentguy.frtimesustained.getText()), float(self.parentguy.addslowdowntime.getText()), float(self.parentguy.inratespeedup.getText()), float(self.parentguy.outratespeedup.getText()))
        return
    fastforwardbut = JButton('Fast forward to highlights')
    fastforwardbut.addActionListener(fastforwardlistener(self))
    self.add(fastforwardbut, self.cguy)

    self.pack()
    self.repaint()


class supertemplateadjuster(JDialog):
  def __init__(self, parentguy):
    self.parentguy = parentguy
    self.setLocationRelativeTo(None)
    self.setTitle("Template adjustment land")
    self.setLayout(GridBagLayout())
    self.cguy = GridBagConstraints()
    self.cguy.insets = Insets(3, 3, 3, 3)
    self.cguy.fill = GridBagConstraints.HORIZONTAL

    self.cguy.gridx = 0
    self.cguy.gridy = 0
    self.cguy.gridwidth = 1
    self.add(JLabel('x offset'), self.cguy)
    self.cguy.gridx = 3
    self.xoffset = JTextField('0       ')
    self.add(self.xoffset, self.cguy)

    self.cguy.gridx = 0
    self.cguy.gridy = 1
    self.cguy.gridwidth = 1
    self.add(JLabel('y offset'), self.cguy)
    self.cguy.gridx = 3
    self.yoffset = JTextField('0       ')
    self.add(self.yoffset, self.cguy)

    self.cguy.gridx = 0
    self.cguy.gridy = 2
    self.cguy.gridwidth = 1
    self.add(JLabel('z offset'), self.cguy)
    self.cguy.gridx = 3
    #self.zoffset = JTextField('0       ')
    self.zoffset = JSpinner()
    self.zoffset.setModel(SpinnerNumberModel(0.,-1.,1.,0.01))
    #mySpinner.setEditor(new JSpinner.NumberEditor(mySpinner,"##.#"));
    #JFormattedTextField txt = ((JSpinner.NumberEditor) mySpinner.getEditor()).getTextField();
    #((NumberFormatter) txt.getFormatter()).setAllowsInvalid(false);

    self.add(self.zoffset, self.cguy)

    self.pack()
    self.repaint()

 

class pickguy(MouseAdapter):
  def __init__(self, pickcanvas, parentguy):
    self.pickcanvas = pickcanvas
    self.parentguy = parentguy
    
  def mouseClicked(self, e):
    self.pickcanvas.setShapeLocation(e)
    res = self.pickcanvas.pickClosest()
    if(res == None):
      return
    ems = e.getModifiers()
    if(ems == InputEvent.BUTTON1_MASK):
      self.parentguy.setdapointwithdacolorandstuff(res.getNode(PickResult.SHAPE3D), 1)
    if(ems == InputEvent.BUTTON3_MASK):
      self.parentguy.setdapointwithdacolorandstuff(res.getNode(PickResult.SHAPE3D), -1)

class crazydatafileio(JPanel):
  def getstartandstoptimestamps(self, withit):
    centerpanel = JPanel()
    centerpanel.setLayout(GridLayout(8,2))
    centerpanel.add(JLabel("TRACKING start time stamp "))
    Astart = JTextField(15)
    centerpanel.add(Astart)
    if(self.starttrackingtimestamp>-0.0001):
      Astart.setText('%d'%(int(round(1000000.*self.starttrackingtimestamp))))
    centerpanel.add(JLabel("TRACKING end time stamp "))
    Astop = JTextField(15)
    if(self.stoptrackingtimestamp>-0.0001):
      Astop.setText('%d'%(int(round(1000000.*self.stoptrackingtimestamp))))
    centerpanel.add(Astop)
    centerpanel.add(JLabel("SESSION start time stamp "))
    Bstart = JTextField(15)
    centerpanel.add(Bstart)
    if(self.startsessiontimestamp>-0.0001):
      Bstart.setText('%d'%(int(round(1000000.*self.startsessiontimestamp))))
    centerpanel.add(JLabel("SESSION end time stamp "))
    Bstop = JTextField(15)
    centerpanel.add(Bstop)
    if(self.stopsessiontimestamp>-0.0001):
      Bstop.setText('%d'%(int(round(1000000.*self.stopsessiontimestamp))))
    centerpanel.add(JLabel("VT1 start time stamp "))
    Cstart = JTextField(15)
    centerpanel.add(Cstart)
    if(self.startratcamtimestamp>-0.0001):
      Cstart.setText('%d'%(int(round(1000000.*self.startratcamtimestamp))))
    centerpanel.add(JLabel("VT1 end time stamp " ))
    Cstop = JTextField(15)
    centerpanel.add(Cstop)
    if(self.stopratcamtimestamp>-0.0001):
      Cstop.setText('%d'%(int(round(1000000.*self.stopratcamtimestamp))))

    if(withit==True):
      centerpanel.add(JLabel("Capture frame rate " ))
      FRATE = JTextField(15)
      centerpanel.add(FRATE)
      if(self.framerate>-0.0001):
        FRATE.setText('%d'%(int(round(self.framerate))))

      centerpanel.add(JLabel("Rat cam frame rate " ))
      CAMFRATE = JTextField(15)
      centerpanel.add(CAMFRATE)
      CAMFRATE.setText('%d'%(int(round(self.ratcamframerate))))

    centerpanel.validate() 
    centerpanel.setVisible(True)
    sel = JOptionPane.showConfirmDialog(None, centerpanel, 'Enter Mr Time Stamps', JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE)
    if(sel == JOptionPane.OK_OPTION):
      if(len(Astart.getText())>0):
        self.starttrackingtimestamp = float(Astart.getText())/1000000. #convert to seconds
      if(len(Bstop.getText())>0):
        self.stoptrackingtimestamp = float(Astop.getText())/1000000. #convert to seconds
      if(len(Bstart.getText())>0):
        self.startsessiontimestamp = float(Bstart.getText())/1000000. #convert to seconds
      if(len(Bstop.getText())>0):
        self.stopsessiontimestamp = float(Bstop.getText())/1000000. #convert to seconds
      if(len(Cstart.getText())>0):
        self.startratcamtimestamp = float(Cstart.getText())/1000000.
      if(len(Cstop.getText())>0):
        self.stopratcamtimestamp = float(Cstop.getText())/1000000.
      if(withit==True):
        if(len(FRATE.getText())>0):
          self.framerate = float(FRATE.getText())
        if(len(CAMFRATE.getText())>0):
          self.ratcamframerate = float(CAMFRATE.getText())



  def getpointsfromcsvfile(self, csvfile):
    dafile = open(csvfile)
    rawfile = dafile.readlines()
    T = len(rawfile) - 6
    reader = csv.reader(dafile)
    dafile.seek(0)
    count = 0

    whatyguy = zeros(T, 'i')
    negguy = zeros(T, 'd')
    for i in range(T):
      whatyguy[i] = -10000
      negguy[i] = -10000
    emptyguy = []
    for i in range(3):
      emptyguy.append(copy.deepcopy(negguy))
    emptyguy.append(whatyguy) ## neuron label number
    emptyguy.append(negguy) ## 'distance' measure (set as -1 if set by user)
              #dapoints.append(copy.deepcopy(emptyguy))

    whiches = 0
    axisguys = 0
    dapoints = []

    daframerate = 0.

    firstframe = -1.
    firsttime = -1.
    conversionfactor = 1.

    print 'Printing the first 10 lines of the csv file and then the first 30 rows in the subsequent data structure (just a visual check)'
    for row in reader:
      if(count < 10):
        print row

      if(len(row)<1):
        count += 1
        continue

      if(count == 0):
        whiches = zeros(len(row), 'i')
        for i in range(len(whiches)):
          if('Length Unit' in row[i] and 'Centimeters' in row[i+1]):
            print 'Note, converting from centimeters to meters for arbitrary reasons'
            conversionfactor = 0.01
        daframerate = (float(row[7]))

      elif(count == 2):
        whiches = zeros(len(row), 'i')
        for i in range(len(whiches)):
          if('Marker' in row[i]):
            whiches[i] = 10
          else:
            whiches[i] = -100
      elif(count == 3):
        ids = []
        for i in range(len(row)):
          if(len(row[i])>0):
            which = -1
            for j in range(len(ids)):
              if(row[i] in ids[j]):
                which = j
                break
            if(which<0):
              which = len(ids)
              ids.append(row[i])
            if(whiches[i]>-1):
              whiches[i] = which+0
      elif(count == 5):
        for i in range(len(row)):
          if("Positi" not in row[i]):
            whiches[i] = -100
      elif(count == 6):
        axisguys = zeros(len(row), 'i')
        for i in range(len(row)):
          if("X" in row[i] and whiches[i]>-1):
            axisguys[i] = 1
          elif("Y" in row[i] and whiches[i]>-1):
            axisguys[i] = 2
          elif("Z" in row[i] and whiches[i]>-1):
            axisguys[i] = 0
          else:
            axisguys[i] = -100
      elif(count > 7):
        #if(count == 8):
          #firstframe = float(row[0])
          #firsttime = float(row[1])
        #if(count == 9):
          #self.framerate = (float(row[0])-firstframe) / (float(row[1])-firsttime)

        dingo = []
        for i in range(len(row)):
          if(whiches[i]>-1 and axisguys[i]>-1 and axisguys[i]<3):
            if(len(row[i])<1):
              continue
            whichguy = -1
            for j in range(len(dingo)):
              if(whiches[i] == dingo[j]):
                whichguy = j
            if(whichguy<0):
              whichguy = len(dingo)
              dingo.append(whiches[i])
            if(whichguy > len(dapoints)-1):
              dapoints.append(copy.deepcopy(emptyguy))
            if(whichguy > len(dapoints)-1):
              print 'wtf, this shit is broken'
              stop
            ((dapoints[whichguy])[axisguys[i]])[count-6] = conversionfactor * float(row[i])
      count += 1
      if( count%(5000) == 0 ):
        if(count == 5000):
            for i in range(30):
              outy = "%04d"%i
              for j in range(len(dapoints)):
                for k in range(3):
                  outy += ' %1.3f'%( ((dapoints[j])[k])[i] )
                if(j<len(dapoints)-1):
                  outy += ', '
              print outy
        print '%2.2f percent done reading in the csv file'%(100*float(count)/float(T-1))
    print '%2.2f percent done reading in the csv file'%(100*float(count)/float(T-1))
    dafile.close()

    return dapoints, daframerate

  def initializefromcsvfile(self, csvfile):
    self.getstartandstoptimestamps(False)
    self.points, self.framerate = self.getpointsfromcsvfile(csvfile)

  def addtemplatefromcsvfile(self, csvfile):
    templepoints, dummy = self.getpointsfromcsvfile(csvfile)

    N = len(templepoints)
    D = len(templepoints[0])
    T = len((templepoints[0])[0])
    print 'Number of points', N, ', number of dimensions', D, 'length of time', T

    for t in range(T):
      print 'TIME', t
      for i in range(N):
        print i,
        for j in range(D):
          print ((templepoints[i])[j])[t],
        print ''
      if(t>20):
        break

    print 'Getting rid of time here (because it does not matter)'
    print 'and reducing the points to only those that appear stationary in at least one fourth of the template recording'


    trypoints = []
    for n in range(N):
      for t in range(T):
        found = False
        for ii in range(len(trypoints)):
          dd = 0.
          for d in range(3):
            dd += ( ((templepoints[n])[d])[t] - (trypoints[ii])[d] )**2
          dd = math.sqrt(dd)
          print dd
          if ( dd<0.01 ):
            if(found == True):
              print 'Crap: found two points!!'
              stop
            (trypoints[ii])[3] += 1
            found = True
            print 'value of dd when true', dd
            print ii, trypoints[ii]
            print ((templepoints[n])[0])[t], ((templepoints[n])[1])[t], ((templepoints[n])[2])[t]
            print ''
        if(found == False):
          trypoints.append( [ ((templepoints[n])[0])[t], ((templepoints[n])[1])[t], ((templepoints[n])[2])[t], 1 ] )
   
    self.templatepoints = []
    for n in range(len(trypoints)):
      if((trypoints[n])[3] > 0.25*float(T)):
        if( (trypoints[n])[0] > -1000. and  (trypoints[n])[1] > -1000. and  (trypoints[n])[2] > -1000.):
          (trypoints[n])[3] = 1
          self.templatepoints.append( copy.deepcopy(trypoints[n]) )




  def exportalldata(self, datafile):
    def addaguytoexport(output, aguy, aguyname):
      aguyXYZ = zeros(3*len(aguy), 'd')
      for i in range(len(aguy)):
        if(aguy[i] == None):
          aguyXYZ[i*3] = -1000000000000000000000000000000000
          aguyXYZ[i*3+1] = -1000000000000000000000000000000000
          aguyXYZ[i*3+2] = -1000000000000000000000000000000000
        else:
          if(i<4):
            print i, aguyname, (aguy[i]).x, (aguy[i]).y, (aguy[i]).z
          aguyXYZ[i*3] = (aguy[i]).x
          aguyXYZ[i*3+1] = (aguy[i]).y
          aguyXYZ[i*3+2] = (aguy[i]).z
      output.append(MLDouble(aguyname, aguyXYZ, 1))
      print 'Length = ', len(aguyXYZ)
      return output

    output = []
    output = addaguytoexport(output, self.headorigin, 'headorigin')
    output = addaguytoexport(output, self.headX, 'headX')
    output = addaguytoexport(output, self.headY, 'headY')
    output = addaguytoexport(output, self.headZ, 'headZ')
    output.append(MLDouble('framerate', [self.framerate], 1))


    n = len(self.points)
    d = len(self.points[0])
    t = len((self.points[0])[0])
    print 'Number of points', len(self.points), ', number of dimensions', len(self.points[0]), 'length of time', len((self.points[0])[0])
    pointsdata = zeros(n*d*t, 'd')
    iii = 0
    for i in range(n):
      pp = self.points[i]
      for j in range(d):
        dd = pp[j] 
        for k in range(t):
          pointsdata[iii] = dd[k]
          iii = iii+1
    output.append(MLDouble('pointdata', pointsdata, 1))
    output.append(MLDouble('pointdatadimensions', [n, d, t], 1))

    output.append(MLDouble('bbtransXY', [self.boundingboxtransX, self.boundingboxtransY], 1))
    output.append(MLDouble('bbscaleXY', [self.boundingboxscaleX, self.boundingboxscaleY], 1))
    output.append(MLDouble('bbrot', [self.boundingboxrotation], 1))

    output.append(MLDouble('trackingTS', [self.starttrackingtimestamp, self.stoptrackingtimestamp], 1))
    output.append(MLDouble('sessionTS', [self.startsessiontimestamp, self.stopsessiontimestamp], 1))
    output.append(MLDouble('ratcamTS', [self.startratcamtimestamp, self.stopratcamtimestamp], 1))

    if(len(self.allcellnames)>0):
      for i in range(len(self.allcells)):
        output.append(MLChar('cellname_%05d'%i, self.allcellnames[i]))
        output.append(MLDouble('cell_%05d'%i, self.allcells[i], 1))

    print datafile
    MatFileWriter(datafile, output)

    return

  def savetrackeddata(self, trackingdatafile):
    superOorientsARRAY = []
    superXorientsARRAY = []
    superYorientsARRAY = []
    superZorientsARRAY = []
    for i in range(len(self.headorigin)):
      if(self.headorigin[i] == None):
        superOorientsARRAY.append([0,0,0])
        superXorientsARRAY.append([0,0,0])
        superYorientsARRAY.append([0,0,0])
        superZorientsARRAY.append([0,0,0])
      else:
        superOorientsARRAY.append([(self.headorigin[i]).x, (self.headorigin[i]).y, (self.headorigin[i]).z])
        superXorientsARRAY.append([(self.headX[i]).x, (self.headX[i]).y, (self.headX[i]).z])
        superYorientsARRAY.append([(self.headY[i]).x, (self.headY[i]).y, (self.headY[i]).z])
        superZorientsARRAY.append([(self.headZ[i]).x, (self.headZ[i]).y, (self.headZ[i]).z])
    mat = {'points':self.points, 'pointlabels':self.pointlabels}
    mat['headoriginarray'] = superOorientsARRAY
    mat['headXarray'] = superXorientsARRAY
    mat['headYarray'] = superYorientsARRAY
    mat['headZarray'] = superZorientsARRAY
    mat['starttrackingtimestamp'] = self.starttrackingtimestamp
    mat['stoptrackingtimestamp'] = self.stoptrackingtimestamp
    mat['startsessiontimestamp'] = self.startsessiontimestamp
    mat['stopsessiontimestamp'] = self.stopsessiontimestamp
    mat['startratcamtimestamp'] = self.startratcamtimestamp
    mat['stopratcamtimestamp'] = self.stopratcamtimestamp

    mat['boundingboxrotation'] = self.boundingboxrotation
    mat['boundingboxtransX'] = self.boundingboxtransX
    mat['boundingboxtransY'] = self.boundingboxtransY
    mat['boundingboxscaleX'] = self.boundingboxscaleX
    mat['boundingboxscaleY'] = self.boundingboxscaleY

    mat['framerate'] = self.framerate

    if(".pkl" in trackingdatafile):
      pickle_file = open(trackingdatafile,'wb')
      pickle.dump(mat, pickle_file)
      pickle_file.close()
    return



  def initializefrompklfile(self, trackingdatafile):
    pickle_file = open(trackingdatafile,'rb')
    mat = pickle.load(pickle_file)
    if('pointlabels' in mat):
      self.pointlabels = mat['pointlabels']
      for i in range(len(self.pointlabels.keys())):
        self.jbigguy.mysuperpointlabeler.addmearow(self.pointlabels.keys()[i])
      for i in range(len(self.pointlabels.keys())):
        for j in range(len(self.jbigguy.mysuperpointlabeler.combolist)):
          if(self.jbigguy.mysuperpointlabeler.combolist[j].namy == self.pointlabels.keys()[i]):
            self.jbigguy.mysuperpointlabeler.combolist[j].setSelectedIndex( (self.jbigguy.cnames.keys()).index( (self.pointlabels[ self.pointlabels.keys()[i] ])[0] ) )
        for j in range(len(self.jbigguy.mysuperpointlabeler.pointtypecombolist)):
          if(self.jbigguy.mysuperpointlabeler.pointtypecombolist[j].namy == self.pointlabels.keys()[i]):
            self.jbigguy.mysuperpointlabeler.pointtypecombolist[j].setSelectedIndex( (self.jbigguy.pointtypes).index( (self.pointlabels[ self.pointlabels.keys()[i] ])[1] ) )
    pickle_file.close()
    self.analysisprogression = 0 #(at least)

    if('framerate' in mat):
      self.framerate = float(mat['framerate'])
      #print 'Frame rate is ', self.framerate
    if("points" not in mat):
      print 'File (%s) is screwed, it should have the variable points in it'%trackingdatafile
      return(-1)
    self.points = mat['points']
    self.plen = len( (self.points[0])[0] )

    if("starttrackingtimestamp" in mat):
      self.starttrackingtimestamp = mat['starttrackingtimestamp']
      self.stoptrackingtimestamp = mat['stoptrackingtimestamp']
    if("startsessiontimestamp" in mat):
      self.startsessiontimestamp = mat['startsessiontimestamp']
      self.stopsessiontimestamp = mat['stopsessiontimestamp']
    if('startratcamtimestamp' in mat):
      self.startratcamtimestamp = mat['startratcamtimestamp']
      self.stopratcamtimestamp = mat['stopratcamtimestamp']

    if('boundingboxrotation' in mat):
      self.boundingboxrotation = mat['boundingboxrotation']
      self.boundingboxtransX = mat['boundingboxtransX']
      self.boundingboxtransY = mat['boundingboxtransY']
      self.boundingboxscaleX = mat['boundingboxscaleX']
      self.boundingboxscaleY = mat['boundingboxscaleY'] 
      self.jbigguy.adjustdisplaybox()

    if('headoriginarray' in mat):
      self.analysisprogression = 1
      superOorientsARRAY = mat['headoriginarray']
      superXorientsARRAY = mat['headXarray']
      superYorientsARRAY = mat['headYarray']
      superZorientsARRAY = mat['headZarray']
      self.headorigin = []
      self.headX = []
      self.headY = []
      self.headZ = []
      for i in range(len(superXorientsARRAY)):
        if(math.fabs((superXorientsARRAY[i])[0]) + math.fabs((superXorientsARRAY[i])[1]) + math.fabs((superXorientsARRAY[i])[2]) < 0.01):
          self.headorigin.append(None)
          self.headX.append(None)
          self.headY.append(None)
          self.headZ.append(None)
        else:
          self.headorigin.append(Vector3d( (superOorientsARRAY[i])[0],  (superOorientsARRAY[i])[1],  (superOorientsARRAY[i])[2] ))
          self.headX.append(Vector3d( (superXorientsARRAY[i])[0],  (superXorientsARRAY[i])[1],  (superXorientsARRAY[i])[2] ))
          self.headY.append(Vector3d( (superYorientsARRAY[i])[0],  (superYorientsARRAY[i])[1],  (superYorientsARRAY[i])[2] ))
          self.headZ.append(Vector3d( (superZorientsARRAY[i])[0],  (superZorientsARRAY[i])[1],  (superZorientsARRAY[i])[2] ))

  def initializefrommatfile(self, trackingdatafile):
    matfilereader = MatFileReader(trackingdatafile)
    bbtransXY = (matfilereader.getMLArray('bbtransXY')).getArray()
    bbscaleXY = (matfilereader.getMLArray('bbscaleXY')).getArray()
    bbrot = (matfilereader.getMLArray('bbrot')).getArray()
    print 'trans',bbtransXY
    print 'scale',bbscaleXY
    print 'rotation',bbrot
    self.boundingboxtransX = (bbtransXY[0])[0]
    self.boundingboxtransY = (bbtransXY[0])[1]
    self.boundingboxscaleX = (bbscaleXY[0])[0]
    self.boundingboxscaleY = (bbscaleXY[0])[1]
    self.boundingboxrotation = (bbrot[0])[0]
    print 'trans', self.boundingboxtransX, self.boundingboxtransY
    print 'scale', self.boundingboxscaleX, self.boundingboxscaleY
    print 'rotation', self.boundingboxrotation
    self.jbigguy.adjustdisplaybox()

    trackingTS = (matfilereader.getMLArray('trackingTS')).getArray()
    sessionTS = (matfilereader.getMLArray('sessionTS')).getArray()
    ratcamTS = (matfilereader.getMLArray('ratcamTS'))
    if(ratcamTS != None):
      ratcamTS = ratcamTS.getArray()
      self.startratcamtimestamp = (ratcamTS[0])[0]
      self.stopratcamtimestamp = (ratcamTS[0])[1]
      print 'ratcam ts', ratcamTS

    print 'tracking ts', trackingTS
    print 'session ts', sessionTS
    print len(trackingTS), 'is two?'
    self.starttrackingtimestamp = (trackingTS[0])[0]
    self.stoptrackingtimestamp = (trackingTS[0])[1]
    self.startsessiontimestamp = (sessionTS[0])[0]
    self.stopsessiontimestamp = (sessionTS[0])[1]
    print 'tracking ts', self.starttrackingtimestamp, self.stoptrackingtimestamp
    print 'tracking ts minus', self.starttrackingtimestamp-math.floor(self.starttrackingtimestamp), self.stoptrackingtimestamp-math.floor(self.stoptrackingtimestamp)
    print 'session ts', self.startsessiontimestamp, self.stopsessiontimestamp

    pdd = (matfilereader.getMLArray('pointdatadimensions')).getArray() 
    pointsdata = (matfilereader.getMLArray('pointdata')).getArray() 
    n = int(round( (pdd[0])[0] ))
    d = int(round( (pdd[0])[1] ))
    T = int(round( (pdd[0])[2] ))
    print 'making point array of size', n, d, T
    whatyguy = zeros(T, 'i')
    negguy = zeros(T, 'd')
    for i in range(T):
      whatyguy[i] = -10000
      negguy[i] = -10000
    emptyguy = []
    for i in range(3):
      emptyguy.append(copy.deepcopy(negguy))
    emptyguy.append(whatyguy) ## neuron label number
    emptyguy.append(copy.deepcopy(negguy)) ## 'distance' measure (set as -1 if set by user)
    self.points = []
    for i in range(n):
      self.points.append(copy.deepcopy(emptyguy))
    print len(self.points[0]), 'should be the same as', d
    iii = 0
    numkinds = 0
    for i in range(n):
      for j in range(d):
        for k in range(T):
          if(j==3): ## this is where it crapped out
            ((self.points[i])[j])[k] = int(round( (pointsdata[0])[iii] ))
            if(((self.points[i])[j])[k] > numkinds):
              numkinds = ((self.points[i])[j])[k]
          else:
            ((self.points[i])[j])[k] = (pointsdata[0])[iii]
          iii = iii+1
    self.plen = T

    def addaguyfromimport(aguy):
      valguy = []
      aguyXYZ = matfilereader.getMLArray(aguy)
      if(aguyXYZ == None):
        return None
      aguyXYZ = (aguyXYZ.getArray())[0]
      for i in range(T):
        if(aguyXYZ[i*3] < -1000000):
          valguy.append(None)
        else:
          valguy.append(Vector3d( [ aguyXYZ[i*3], aguyXYZ[i*3+1], aguyXYZ[i*3+2] ] ))
      return valguy

    self.headorigin = addaguyfromimport('headorigin')
    self.headX = addaguyfromimport('headX')
    self.headY = addaguyfromimport('headY')
    self.headZ = addaguyfromimport('headZ')
    self.framerate = (((matfilereader.getMLArray('framerate')).getArray())[0])[0]
    
    self.analysisprogression = 0
    if(self.headorigin != None):
      self.analysisprogression = 1

    for i in range(numkinds+1):
      self.jbigguy.mysuperpointlabeler.addmearow(i)
      #for i in range(len(self.pointlabels.keys())):
        #for j in range(len(self.jbigguy.mysuperpointlabeler.combolist)):
          #if(self.jbigguy.mysuperpointlabeler.combolist[j].namy == self.pointlabels.keys()[i]):
            #self.jbigguy.mysuperpointlabeler.combolist[j].setSelectedIndex( (self.jbigguy.cnames.keys()).index( (self.pointlabels[ self.pointlabels.keys()[i] ])[0] ) )
        #for j in range(len(self.jbigguy.mysuperpointlabeler.pointtypecombolist)):
          #if(self.jbigguy.mysuperpointlabeler.pointtypecombolist[j].namy == self.pointlabels.keys()[i]):
            #self.jbigguy.mysuperpointlabeler.pointtypecombolist[j].setSelectedIndex( (self.jbigguy.pointtypes).index( (self.pointlabels[ self.pointlabels.keys()[i] ])[1] ) )

    return

  def gettrackeddatafromfile(self, trackingdatafile):
    base, ext = os.path.splitext(trackingdatafile)
    self.framerate = 120. ### DEFAULT VALUE COULD BE WRONG!!!
    if('csv' in ext):
      self.analysisprogression = 0
      self.initializefromcsvfile(trackingdatafile)
      self.plen = len( (self.points[0])[0] )
    if('pkl' in ext):
      self.initializefrompklfile(trackingdatafile)
    if('mat' in ext):
      self.initializefrommatfile(trackingdatafile)


  def getcelldatafromfile(self, filenames):
    self.allcells = []
    self.allcellnames = []
    earliesttimepoint = 1000000000000000000000000000000000000000
    latesttimepoint = -100000000000000000000000000000000000000
    for i in range(len(filenames)):
      matfilereader = MatFileReader(filenames[i])
      cellts = (matfilereader.getMLArray('cellTS')).getArray()
      values = zeros(len(cellts), 'd')
      for j in range(len(cellts)):
        values[j] = (cellts[j])[0]
        if(values[j] > latesttimepoint):
          latesttimepoint = values[j]
        if(values[j] < earliesttimepoint):
          earliesttimepoint = values[j]
      name = '%d cell'%i
      for temp in range(len(filenames[i])-4, 0, -1):
        if( (filenames[i])[temp] == 'T' ):
          name = (filenames[i])[temp:(len(filenames[i])-4)]
          break
      self.allcellnames.append(name)
      self.allcells.append(values)
      matfilereader = 0
    self.getstartandstoptimestamps(True)
    #print 'Earliest time point in matlab files is:', earliesttimepoint
    #print 'Latest time point in matlab files is:', latesttimepoint
    self.jbigguy.addspikestostuff(self.allcells, self.allcellnames)

  def addthingies(self):
    tempty = JPanel()
    self.jcheckorigpoints = JCheckBox()
    class jcheckerorigpoints(ItemListener):
      def __init__(self, parentguy):
        self.parentguy = parentguy
      def itemStateChanged(self, e):
        self.parentguy.jbigguy.settimepoint()
    self.jcheckorigpoints.addItemListener(jcheckerorigpoints(self))
    tempty.add(self.jcheckorigpoints)
    tempty.add(JLabel('Show points'))
    self.revalidate()
    self.setVisible(True)
    self.jcheckorigpoints.setSelected(True)
    

    labelpointsbut = JButton('Tracking')
    class labelpointlistener(ActionListener):
      def __init__(self, parentguy):
        self.parentguy = parentguy
      def actionPerformed(self, event):
        self.parentguy.jbigguy.mysuperpointlabeler.setVisible(True)
    labelpointsbut.addActionListener(labelpointlistener(self))
    tempty.add(labelpointsbut)
    tempty.validate()

    c = GridBagConstraints()
    c.anchor = GridBagConstraints.WEST
    c.insets = Insets(3, 3, 3, 3)
    c.fill = GridBagConstraints.HORIZONTAL
    c.gridy = 0
    c.gridx = 3
    c.gridwidth=2
    self.add(tempty, c)

  def __init__(self, jbigguy):
    self.plen = -1
    self.headorigin = None
    self.jbigguy = jbigguy
    self.analysisprogression = -1
    self.starttrackingtimestamp = -1.
    self.stoptrackingtimestamp = -1.
    self.startsessiontimestamp = -1.
    self.stopsessiontimestamp = -1.
    self.startratcamtimestamp = -1.
    self.stopratcamtimestamp = -1.
    self.boundingboxrotation = 0.
    self.boundingboxtransX = 0.
    self.boundingboxtransY = 0.
    self.boundingboxscaleX = 1.
    self.boundingboxscaleY = 1.

 
    self.currentdirectory = ''
    preferencefile = '%s/Lib/trackedpointprefs.txt'%(getProperty('python.home'))
    if(os.path.exists(preferencefile)):
      preffile = open(preferencefile,'r')
      for line in preffile:
        if(len(line)>0):
          vals = line.split()
          if(len(vals)==2):
            if(vals[0] == 'LAST_DIRECTORY'):
              self.currentdirectory = vals[1]
      preffile.close()

    self.ratcamframerate = 25.

    self.allcells = []
    self.allcellnames = []

    self.setLayout(GridBagLayout())
    self.pointlabels = {}
    self.headorigin = []
    self.headX = []
    self.headY = []
    self.headZ = []
    c = GridBagConstraints()
    c.anchor = GridBagConstraints.WEST
    c.insets = Insets(3, 3, 3, 3)
    c.gridx = 0
    c.gridy = 0
    c.fill = GridBagConstraints.HORIZONTAL
    class opentrackingdatalistener(ActionListener):
      def __init__(self, jguy):
        self.jguy = jguy
        self.fc = JFileChooser(self.jguy.currentdirectory)
        self.fc.setFileFilter(FileNameExtensionFilter("*.pkl, *.mat or *.csv file", ["mat","pkl","csv"]))
      def actionPerformed(self, event):
        ret = self.fc.showOpenDialog(None)
        if(ret == 0):
          self.jguy.jbut1.setEnabled(False)
          self.jguy.spikingloadbutton.setEnabled(True)
          self.jguy.ratcamloadbutton.setEnabled(True)
          self.jguy.analysisdatabutton.setEnabled(True)
          self.jguy.currentdirectory = self.fc.getCurrentDirectory()
          preferencefile = '%s/Lib/trackedpointprefs.txt'%(getProperty('python.home'))
          preffile = open(preferencefile,'w')
          preffile.write('LAST_DIRECTORY %s'%self.jguy.currentdirectory)
          preffile.close()

          self.jguy.jtrackingdata.setText( self.fc.selectedFile.getName() )
          self.jguy.gettrackeddatafromfile(self.fc.selectedFile.getAbsolutePath())
          if(self.jguy.plen > 0):
            self.jguy.jbigguy.setsuperpoints()
          self.jguy.jexportdata.setVisible(True)
          self.jguy.repaint()
          self.jguy.jbigguy.jcomboskippies.setEnabled(True)
          self.jguy.jbigguy.jcombospeedups.setEnabled(True)
          self.jguy.jbigguy.jbutfun.setEnabled(True)
          self.jguy.jbigguy.jcomboskippies.setSelectedIndex(0)
          self.jguy.jbigguy.jcombospeedups.setSelectedIndex(3)

          SwingUtilities.windowForComponent(self.jguy).revalidate()
          SwingUtilities.windowForComponent(self.jguy).pack()
            

    self.jtrackingdata = JLabel('Tracking data (pkl, mat or csv file)')
    self.jtrackingdata.setPreferredSize(Dimension(500,20))
    self.add(self.jtrackingdata,c)
    self.jbut1 = JButton('Load')
    #jbut1.setPreferredSize(Dimension(20,20))
    self.jbut1.addActionListener(opentrackingdatalistener(self))
    c.gridx=1
    self.add(self.jbut1,c)

    class savestepbuttonlistener(ActionListener):
      def __init__(self, jguy):
        self.jguy = jguy
      def actionPerformed(self, event):
        fc = JFileChooser(self.jguy.currentdirectory)
        fc.setFileFilter(FileNameExtensionFilter("Pickled (*.pkl)", ["pkl"]))
        ret = fc.showSaveDialog(None)
        if(ret == 0):
          self.jguy.jtrackingdata.setText( fc.selectedFile.getName() )
          self.jguy.jtrackingdata.setPreferredSize(Dimension(500,20))
          self.jguy.savetrackeddata(fc.selectedFile.getAbsolutePath())
          SwingUtilities.windowForComponent(self.jguy).revalidate()
          SwingUtilities.windowForComponent(self.jguy).pack()
        ## save the data!!

    jbut3 = JButton('Save')
    #jbut3.setPreferredSize(Dimension(60,20))
    jbut3.addActionListener(savestepbuttonlistener(self))
    c.gridx=2
    self.add(jbut3, c)
    c.gridy=1
    c.gridx=0
    self.jspikingdata = JLabel('Spiking data (mat files)')
    self.jspikingdata.setPreferredSize(Dimension(500,20))
    self.add(self.jspikingdata,c)
    self.spikingloadbutton = JButton('Load')
    #jbut2.setPreferredSize(Dimension(20,20))
    class openneuraldatalistener(ActionListener):
      def __init__(self, jguy):
        self.jguy = jguy
      def actionPerformed(self, event):
        fc = JFileChooser(self.jguy.currentdirectory)
        fc.setMultiSelectionEnabled(True)
        fc.setFileFilter(FileNameExtensionFilter("matlab files (*.mat)", ["mat"]))
        ret = fc.showOpenDialog(None)
        if(ret == 0):
          names = []
          justname = ''
          for i in range(len(fc.selectedFiles)):
            names.append( (fc.selectedFiles[i]).getAbsolutePath() )
          if(len(names)==1):
            self.jguy.jspikingdata.setText(names[0])
          else:
            self.jguy.jspikingdata.setText('%s and friends'%(names[0]))
          self.jguy.jspikingdata.setPreferredSize(Dimension(500,20))
          self.jguy.getcelldatafromfile(names)
          self.jguy.spikingloadbutton.setEnabled(False)
          self.jguy.jbutratemaps.setVisible(True)
          self.jguy.jexportdata.setVisible(True)
          self.jguy.repaint()
          SwingUtilities.windowForComponent(self.jguy).revalidate()
          SwingUtilities.windowForComponent(self.jguy).pack()

          

    self.spikingloadbutton.addActionListener(openneuraldatalistener(self))
    self.spikingloadbutton.setEnabled(False)
    c.gridx=1
    self.add(self.spikingloadbutton,c)

    self.ratemapguy = ratemapgenerator.ratemapthingy()

    class makeratemaplistener(ActionListener):
      def __init__(self, jguy):
        self.jguy = jguy
      def actionPerformed(self, event):
        self.jguy.ratemapguy.gogogo( self.jguy )
    self.jbutratemaps = JButton('Rate maps')
    self.jbutratemaps.addActionListener(makeratemaplistener(self))
    c.gridx=3
    self.add(self.jbutratemaps,c)
    self.jbutratemaps.setVisible(False)

    class exportforratemaplistener(ActionListener):
      def __init__(self, jguy):
        self.jguy = jguy
      def actionPerformed(self, event):
        fc = JFileChooser(self.jguy.currentdirectory)
        fc.setFileFilter(FileNameExtensionFilter("Matlab file (*.mat)", ["mat"]))
        ret = fc.showSaveDialog(None)
        if(ret == 0):
          self.jguy.exportalldata(fc.selectedFile.getAbsolutePath())

    self.jexportdata = JButton('Export all')
    self.jexportdata.addActionListener(exportforratemaplistener(self))
    c.gridx=4
    self.add(self.jexportdata,c)
    self.jexportdata.setVisible(False)
    
    c.gridy=2
    c.gridx=0
    self.avifile = JLabel('Rat cam video file (avi file)')
    self.avifile.setPreferredSize(Dimension(500,20))
    self.add(self.avifile,c)
    self.ratcamloadbutton = JButton('Open')
    class openavibuttonlistener(ActionListener):
      def __init__(self, jguy):
        self.jguy = jguy
      def actionPerformed(self, event):
        fc = JFileChooser(self.jguy.currentdirectory)
        fc.setFileFilter(FileNameExtensionFilter("Rat cam video", ["avi"]))
        ret = fc.showOpenDialog(None)
        if(ret == 0):
          self.jguy.ratcamloadbutton.setEnabled(False)
          self.jguy.avifile.setText(fc.selectedFile.getName())
          self.jguy.actualavifile = fc.selectedFile.getAbsolutePath()
          self.jguy.avifile.setPreferredSize(Dimension(500,20))
          self.jguy.getstartandstoptimestamps(True)
          self.jguy.jbigguy.synchwithratcam()
          self.jguy.repaint()
          SwingUtilities.windowForComponent(self.jguy).revalidate()
          SwingUtilities.windowForComponent(self.jguy).pack()
    self.ratcamloadbutton.addActionListener(openavibuttonlistener(self))
    self.ratcamloadbutton.setEnabled(False)
    c.gridx=1
    self.add(self.ratcamloadbutton,c)
    
    c.gridy=3
    c.gridx=0
    self.templatefile = JLabel('Template file (csv file)')
    self.templatefile.setPreferredSize(Dimension(500,20))
    self.add(self.templatefile, c)
    self.templatefilebutton = JButton('Load')
    class templatefilebuttonlistener(ActionListener):
      def __init__(self, jguy):
        self.jguy = jguy
      def actionPerformed(self, event):
        fc = JFileChooser(self.jguy.currentdirectory)
        fc.setFileFilter(FileNameExtensionFilter("Template file", ["csv"]))
        ret = fc.showOpenDialog(None)
        if(ret == 0):
          self.jguy.adjusttemplatefilebutton.setEnabled(True)
          self.jguy.templatefile.setText(fc.selectedFile.getName())
          self.jguy.templatefile.setPreferredSize(Dimension(500,20))
          self.jguy.addtemplatefromcsvfile(fc.selectedFile.getAbsolutePath())
          #self.jguy.jbigguy.setsuperpoints()
          self.jguy.jbigguy.settemplatepoints()
          self.jguy.repaint()
    self.templatefilebutton.addActionListener(templatefilebuttonlistener(self))
    self.templatefilebutton.setEnabled(True)
    c.gridx=1
    self.add(self.templatefilebutton,c)

    self.templateadjuster = supertemplateadjuster(self)
    self.templateadjuster.setVisible(False)
    class adjusttemplatefilebuttonlistener(ActionListener):
      def __init__(self, jguy):
        self.jguy = jguy
      def actionPerformed(self, event):
        self.jguy.templateadjuster.setVisible(True)

    self.adjusttemplatefilebutton = JButton('Adjust it')
    self.adjusttemplatefilebutton.addActionListener(adjusttemplatefilebuttonlistener(self))
    self.adjusttemplatefilebutton.setEnabled(False)
    c.gridx=2
    self.add(self.adjusttemplatefilebutton,c)

    c.gridy=4
    c.gridx=0
    self.analysisdata = JLabel('Analysis files (csv)')
    self.analysisdata.setPreferredSize(Dimension(500,20))
    self.add(self.analysisdata, c)
    self.analysisdatabutton = JButton('Add one')
    class analysisdatabuttonlistener(ActionListener):
      def __init__(self, jguy):
        self.jguy = jguy
      def actionPerformed(self, event):
        fc = JFileChooser(self.jguy.currentdirectory)
        fc.setFileFilter(FileNameExtensionFilter("Template file", ["csv"]))
        fc.setDialogTitle('Analysis data (assumed length of traces)')
        ret = fc.showOpenDialog(None)
        if(ret == 0):
          self.jguy.analysisdata.setText('%s added'%(fc.selectedFile.getName()))
          self.jguy.jbigguy.datatable.loadanalysisdata(fc.selectedFile.getAbsolutePath())
          self.jguy.repaint()
          self.jguy.jbigguy.analysisstuffthingy.setVisible(True)
    self.analysisdatabutton.addActionListener(analysisdatabuttonlistener(self))
    self.analysisdatabutton.setEnabled(False)
    c.gridx=1
    self.add(self.analysisdatabutton,c)

    self.revalidate()
    self.setVisible(True)


class superpointlabeler(JDialog):
  def addmearow(self, namy):
    class combocellguylistener(ItemListener):
      def __init__(self, parentguy):
        self.parentguy = parentguy
      def itemStateChanged(self, e):
        self.parentguy.parentguy.settimepoint()
   
    class JComboWithName(JComboBox):
      def setnamy(self, namy):
        self.namy = namy

    self.cguy.gridy = self.cguy.gridy+1
    self.cguy.gridwidth=1
    self.cguy.gridx=0

    jpp = JPanel()
    jpp.add(JLabel('%s'%namy))

    jcb = JCheckBox()
    self.jcheckboxpoints.append(jcb)
    class jcheckboxpointslistener(ItemListener):
      def __init__(self, parentguy):
        self.parentguy = parentguy
        #self.namy = namy
      def itemStateChanged(self, e):
        #if(e.getSource().isSelected()):
        self.parentguy.parentguy.settimepoint()
    jcb.addItemListener(jcheckboxpointslistener(self))
    jcb.setSelected(True)
    jpp.add(jcb)
    
    self.add(jpp, self.cguy)

    pointypecombo = JComboWithName(self.parentguy.pointtypes)
    pointypecombo.setnamy(namy)


    def checkitnow(indy):
      for i in range(len(self.pointtypecombolist)):
        if((self.pointtypecombolist[i]).getSelectedIndex()==indy):
          return False
      return True
    firstgoodone = len(self.parentguy.pointtypes)-1
    for i in range(len(self.parentguy.pointtypes)):
      if(checkitnow(i) == True):
        firstgoodone = i
        break
    pointypecombo.setSelectedIndex(firstgoodone)

    self.pointtypecombolist.append(pointypecombo)
    gowithindex = 0
    self.cguy.gridx = 1
    self.add(pointypecombo, self.cguy)

    newcombo = JComboWithName(self.parentguy.cnames.keys())
    newcombo.setnamy(namy)
    someind = int(math.floor(random.random()*(len(self.parentguy.cnames.keys())-1)))
    newcombo.setSelectedIndex( someind )
    self.combolist.append(newcombo)
    newcombo.addItemListener(combocellguylistener(self))
    self.cguy.gridx = 2
    self.cguy.gridwidth = 2
    self.add(newcombo, self.cguy)

    class assignbuttonslistener(ActionListener):
      def __init__(self, parentguy, namy):
        self.parentguy = parentguy
        self.namy = namy
      def actionPerformed(self, event):
        if(event.getSource().isSelected()):
          self.parentguy.parentguy.currentpointassigner = self.namy
          for i in range(len(self.parentguy.togglebuttons)):
            if(self.parentguy.togglebuttons[i] == event.getSource()):
              continue
            else:
              self.parentguy.togglebuttons[i].setSelected(False)
        else:
          self.parentguy.parentguy.currentpointassigner = -10

    newbutton = JToggleButton('Assign points')
    self.cguy.gridx = 4
    newbutton.addActionListener(assignbuttonslistener(self, namy))
    self.add(newbutton, self.cguy)
    self.togglebuttons.append(newbutton)

    class findnextthinglistener(ActionListener):
      def __init__(self, parentguy, namy):
        self.parentguy = parentguy
        self.namy = namy
      def actionPerformed(self, event):
        self.parentguy.parentguy.gotonextwithnonamy(self.namy)

    findnextguy = JButton('Go to next empty')
    self.cguy.gridx = 6
    self.cguy.gridwidth = 1
    findnextguy.addActionListener(findnextthinglistener(self, namy))
    self.add(findnextguy, self.cguy)



    #self.cguy.gridx = 5
    #self.add(JLabel('    '), self.cguy)

    #removeass = JButton('Remove assignments')
    #self.cguy.gridx = 6
    #self.add(removeass, self.cguy)
    self.pack()
    self.repaint()

  def __init__(self, parentguy):
    self.parentguy = parentguy
    self.combolist = []
    self.pointtypecombolist = []
    self.togglebuttons = []
    self.jcheckboxpoints = []
    self.setLocationRelativeTo(None)
    self.setTitle("Tracking interface")
    self.setLayout(GridBagLayout())
    self.cguy = GridBagConstraints()
    self.cguy.insets = Insets(3, 3, 3, 3)
    self.cguy.gridx = 0
    self.cguy.gridy = 0
    self.cguy.gridwidth=2
    self.cguy.fill = GridBagConstraints.HORIZONTAL

    fitboxtopath = JButton('Fit display floor to points')
    class fitboxlistener(ActionListener):
      def __init__(self, parentguy):
        self.parentguy = parentguy
      def actionPerformed(self, event):
        self.parentguy.parentguy.fitdisplayboxtopath()
        return
    fitboxtopath.addActionListener(fitboxlistener(self))
    self.add(fitboxtopath, self.cguy)

    self.cguy.gridy = 1
    trytofillin = JButton('Fill in after hand labeled')
    class trytofillinlistener(ActionListener):
      def __init__(self, parentguy, whichthing):
        self.parentguy = parentguy
        self.whichthing = whichthing
      def actionPerformed(self, event):
        if(self.whichthing==1):
          self.parentguy.parentguy.fillinpoints(self.whichthing, 0.01*float(self.parentguy.fillintol1.getText()))
        else:
          self.parentguy.parentguy.fillinpoints(self.whichthing, 0.01*float(self.parentguy.fillintol0.getText()))
        return
    trytofillin.addActionListener(trytofillinlistener(self, 1))
    self.add(trytofillin, self.cguy)

    self.cguy.gridx = 2
    self.cguy.gridwidth = 1
    self.add(JLabel('Tolerance (cm)'), self.cguy)
    self.cguy.gridx = 3
    self.fillintol1 = JTextField('1')
    self.add(self.fillintol1, self.cguy)

    # Go to specific frame

    self.cguy.gridy = 2

    goToFrame = JButton('Go to frame')

    class goToFramelistener(ActionListener):
      def __init__(self, parentguy):
        self.parentguy = parentguy
      def actionPerformed(self, event):
        self.parentguy.parentguy.gotospecificframe(int(self.parentguy.frameNumber.getText()))
        return

    goToFrame.addActionListener(goToFramelistener(self))
    self.cguy.gridx = 0
    self.cguy.gridwidth = 2
    self.add(goToFrame, self.cguy)

    self.cguy.gridx = 2
    self.cguy.gridwidth = 1
    self.add(JLabel('Frame Number'), self.cguy)
    
    self.cguy.gridx = 3
    self.frameNumber = JTextField('0')
    self.add(self.frameNumber, self.cguy)


    self.cguy.gridy = 3
    superheadcheckbutton = JButton('Assign within tolerance (slow)')
    class superheadchecklistener(ActionListener):
      def __init__(self, parentguy):
        self.parentguy = parentguy
      def actionPerformed(self, event):
        self.parentguy.parentguy.superheadfindaverage()
        val = 0.01*float(self.parentguy.rmsdistval.getText())
        self.parentguy.parentguy.superheadfillin(val)
    superheadcheckbutton.addActionListener(superheadchecklistener(self))
    self.cguy.gridx = 0
    self.cguy.gridwidth = 2
    self.add(superheadcheckbutton, self.cguy)

    self.cguy.gridx = 2
    self.cguy.gridwidth = 1
    self.add(JLabel('Tolerance (cm)'), self.cguy)
    self.cguy.gridx = 3
    self.rmsdistval = JTextField('0.05')
    self.add(self.rmsdistval, self.cguy)

    superautobutton = JButton('Automate the rest')
    class superautobuttonlistener(ActionListener):
      def __init__(self, parentguy):
        self.parentguy = parentguy
      def actionPerformed(self, event):
        self.parentguy.parentguy.superheadfindaverage()
        val = 0.01*float(self.parentguy.rmsdistval.getText())
        self.parentguy.parentguy.superheadfillin(val, 1)
        self.parentguy.parentguy.fillinpoints(0, 0.01*float(self.parentguy.fillintol0.getText()))
        self.parentguy.parentguy.getheadorigin()
        val = float(self.parentguy.transcsysval.getText())
        self.parentguy.parentguy.transformcsystomin(val, 1)
        self.parentguy.parentguy.optimizefororientationstuff(float(self.parentguy.minspeedfortranf.getText()), int(round(float(self.parentguy.numbinstocalculatedom.getText()))), 1)
        self.parentguy.parentguy.settimepoint()

    superautobutton.addActionListener(superautobuttonlistener(self))
    self.cguy.gridx = 6
    self.add(superautobutton, self.cguy)

    self.cguy.gridy = 4
    self.cguy.gridx = 0
    self.cguy.gridwidth=2
    trytofillin2 = JButton('Fill in from any (slow)')
    trytofillin2.addActionListener(trytofillinlistener(self, 0))
    self.add(trytofillin2, self.cguy)

    self.cguy.gridx = 2
    self.cguy.gridwidth = 1
    self.add(JLabel('Tolerance (cm)'), self.cguy)
    self.cguy.gridx = 3
    self.fillintol0 = JTextField('1')
    self.add(self.fillintol0, self.cguy)

    self.cguy.gridy = 5
    #self.cguy.gridx = 0
    #self.jcheckcsysthingy = JCheckBox()
    #class jcheckcsysthingylistener(ItemListener):
      #def __init__(self, parentguy):
        #self.parentguy = parentguy
      #def itemStateChanged(self, e):
        #self.parentguy.parentguy.settimepoint()
    #self.jcheckcsysthingy.addItemListener(jcheckcsysthingylistener(self))
    #self.add(self.jcheckcsysthingy, self.cguy)


    self.cguy.gridx = 0
    self.cguy.gridwidth = 2
    headoriginbut = JButton('Head csys maker')
    class gettheheadthinglistener(ActionListener):
      def __init__(self, parentguy):
        self.parentguy = parentguy
      def actionPerformed(self, event):
        self.parentguy.parentguy.getheadorigin()
        self.parentguy.parentguy.settimepoint()
    headoriginbut.addActionListener(gettheheadthinglistener(self))
    self.add(headoriginbut, self.cguy)

    self.cguy.gridy = 6
    self.cguy.gridx = 0
    self.cguy.gridwidth = 2
    transformcsystominbut = JButton('Transform to min shakes')
    class transformcsystominlistener(ActionListener):
      def __init__(self, parentguy):
        self.parentguy = parentguy
      def actionPerformed(self, event):
        val = float(self.parentguy.transcsysval.getText())
        self.parentguy.parentguy.transformcsystomin(val)
    transformcsystominbut.addActionListener(transformcsystominlistener(self))
    self.add(transformcsystominbut, self.cguy)
    self.cguy.gridx = 2
    self.cguy.gridwidth = 1
    self.add(JLabel('Num bins'), self.cguy)
    self.cguy.gridx = 3
    self.transcsysval = JTextField('20')
    self.transcsysval.setColumns(4)
    self.add(self.transcsysval, self.cguy)

    self.cguy.gridy = 7
    self.cguy.gridx = 0
    self.cguy.gridwidth = 2
    transformcsystomatch = JButton('Transform to match DOM')
    self.add(transformcsystomatch, self.cguy)
    
    self.cguy.gridx=2
    self.cguy.gridwidth=1
    self.add(JLabel('Min speed (cm/s)'), self.cguy)
    self.cguy.gridx=3
    self.minspeedfortranf = JTextField('10.')
    self.minspeedfortranf.setColumns(4)
    self.add(self.minspeedfortranf, self.cguy)
    self.cguy.gridx=4
    self.add(JLabel('Num bins'), self.cguy)
    self.cguy.gridx=5
    self.numbinstocalculatedom = JTextField('50')
    self.numbinstocalculatedom.setColumns(4)
    self.add(self.numbinstocalculatedom, self.cguy)
    class transformcsystomatchlistener(ActionListener):
      def __init__(self, parentguy):
        self.parentguy = parentguy
      def actionPerformed(self, event):
        self.parentguy.parentguy.optimizefororientationstuff(float(self.parentguy.minspeedfortranf.getText()), int(round(float(self.parentguy.numbinstocalculatedom.getText()))))
    transformcsystomatch.addActionListener(transformcsystomatchlistener(self))


    self.cguy.gridy = 8
    # Check duplicate labelled markers
    checkDuplicateLabels = JButton('Check duplicates')
    class checkDuplicatesListener(ActionListener):
      def __init__(self, parentguy):
        self.parentguy = parentguy
      def actionPerformed(self, event):
        self.parentguy.parentguy.checkduplicatelabels()
        return
    checkDuplicateLabels.addActionListener(checkDuplicatesListener(self))
    self.cguy.gridx = 0
    self.cguy.gridwidth = 2    
    self.add(checkDuplicateLabels, self.cguy)

    # Remove label duplicate labelled markers
    removeDuplicateLabels = JButton('Remove duplicates')
    class removeDuplicatesListener(ActionListener):
      def __init__(self, parentguy):
        self.parentguy = parentguy
      def actionPerformed(self, event):
        self.parentguy.parentguy.removeduplicatelabels()
        return
    removeDuplicateLabels.addActionListener(removeDuplicatesListener(self))

    self.cguy.gridx = 2
    self.cguy.gridwidth = 2   
    self.add(removeDuplicateLabels, self.cguy)

    # find unlabelled markers
    findUnlabelled = JButton('Go to next unlabelled')
    class findUnlabelledListener(ActionListener):
      def __init__(self, parentguy):
        self.parentguy = parentguy
      def actionPerformed(self, event):
        self.parentguy.parentguy.findunlabelled()
        return
    findUnlabelled.addActionListener(findUnlabelledListener(self))
    self.cguy.gridx = 4
    self.cguy.gridwidth = 2   
    self.add(findUnlabelled, self.cguy)


    addalabelpoint = JButton('Add a labeled point')
    self.cguy.gridx = 0
    self.cguy.gridy = 9
    self.cguy.gridwidth = 4
    self.add(addalabelpoint, self.cguy)

    class addalabelpointlistener(ActionListener):
      def __init__(self, lilparentguy):
        self.lilparentguy = lilparentguy
      def actionPerformed(self, event):
        self.lilparentguy.addmearow(len(self.lilparentguy.combolist))

    addalabelpoint.addActionListener(addalabelpointlistener(self))

    statusbutton = JButton('Status')
    class statusbuttonlistener(ActionListener):
      def __init__(self, parentguy):
        self.parentguy = parentguy
      def actionPerformed(self, event):
        self.parentguy.parentguy.statusoflabeling()
        return
    statusbutton.addActionListener(statusbuttonlistener(self))
    self.cguy.gridx = 4
    self.cguy.gridwidth=2
    self.add(statusbutton, self.cguy)

    self.pack()
    #self.setVisible(True)

class trackeddatastruct(JPanel):

  def gotospecificframe(self, frameNum):
    self.jslider.setValue(frameNum)
    return

  def statusoflabeling(self):
    # clear();
    n = len(self.data.points)
    print n
    countlabeled = 0
    counttotal = 0
    counthead = 0
    countheadfinished = 0
    whichheads = []
    whichheads.append(0)
    whichheads.append(1)
    whichheads.append(2)
    whichheads.append(3)
    startlackingcsys = 0
    startlackingcsysoflongest = 0
    longesttripwithouthead = 0
    thresholdfordisplay = 5
    print 'Displaying all stretches of missed head that are longer than %d time points'%thresholdfordisplay
    for t in range(self.data.plen):
      if(self.data.headorigin != None and len(self.data.headorigin)>10):
        if(self.data.headorigin[t] != None):
          countheadfinished += 1
          if(t>1):
            if(self.data.headorigin[t-1] == None):
              dt = t-startlackingcsys
              if(dt>thresholdfordisplay):
                print 'Empty stretch of %d time points, starting at %d'%(dt, startlackingcsys)

              if(dt>longesttripwithouthead):
                longesttripwithouthead = dt
                startlackingcsysoflongest = startlackingcsys
        else:
          if(t>1):
            if(self.data.headorigin[t-1] != None):
              startlackingcsys = t

      for i in range(n-1):
        if( ((self.data.points[i])[3])[t] > -1 ):
          countlabeled += 1
          if( ((self.data.points[i])[3])[t] in whichheads ): ### FIX THIS SO IT GETS IT CORRECT!!!
            counthead += 1
        # else:
        #   print 'unlabled point %d in timeframe %d'%(i,t)
        if( ((self.data.points[i])[0])[t] > -1000 ):
          counttotal += 1
    perlab = 100. * float(countlabeled)/float(counttotal)
    perhead = 100. * float(counthead)/float(self.data.plen*4)
    perheadfinished = 100. * float(countheadfinished)/float(self.data.plen)
    if(perlab > 90 or perhead > 90):
      if(self.data.headorigin!=None and len(self.data.headorigin)>10):
        JOptionPane.showMessageDialog(None, 'Congratulations! You have %2.2f percent overall labeled,\n%2.2f percent of the head points labeled\nand %2.2f percent of the head positions determined\nwith longest stretch being %d time steps, starting at %d'%(perlab, perhead,perheadfinished,longesttripwithouthead, startlackingcsysoflongest))
      else:
        JOptionPane.showMessageDialog(None, 'Congratulations! You have %2.2f percent overall labeled \nand %2.2f percent of the head points labeled'%(perlab, perhead))
    else:
      if(self.data.headorigin!=None and len(self.data.headorigin)>10):
        JOptionPane.showMessageDialog(None, 'Unfortunately, You have just %2.2f percent overall labeled,\n%2.2f percent of the head points labeled\nand %2.2f percent of the head positions determined\nwith longest stretch being %d time steps, starting at %d'%(perlab, perhead,perheadfinished,longesttripwithouthead, startlackingcsysoflongest))
      else:
        JOptionPane.showMessageDialog(None, 'Unfortunately, You have %2.2f percent overall labeled \nand %2.2f percent of the head points labeled'%(perlab, perhead))

# Check for the duplicate markers
  def checkduplicatelabels(self):
    # clear();
    n = len(self.data.points)

    for t in range(self.data.plen):
      # check duplicate labels
      ls = [((self.data.points[f])[3])[t] for f in range(n)]
      # print ls
      dups = set()
      seen = set()    
      if len(ls) != len(set(ls)):
           for f in range(n):
              lbl = ((self.data.points[f])[3])[t]
              if lbl not in seen:
                  seen.add(lbl)
              else:
                  dups.add(lbl) 
                  # ((self.data.points[f])[3])[t] = -10000
      duplicates = list(sorted(dups))

      # if len(duplicates)>0:
      #   print duplicates,t
      for elem in duplicates:
        for f in range(n):
          if ((self.data.points[f])[3])[t] == elem:
            if (elem!=-10000):
              print elem,t
# Remove the labelling of duplicate markers
  def removeduplicatelabels(self):

    n = len(self.data.points)

    for t in range(self.data.plen):
      # check duplicate labels
      ls = [((self.data.points[f])[3])[t] for f in range(n)]
      # print ls
      dups = set()
      seen = set()    
      if len(ls) != len(set(ls)):
           for f in range(n):
              lbl = ((self.data.points[f])[3])[t]
              if lbl not in seen:
                  seen.add(lbl)
              else:
                  dups.add(lbl) 
                  # ((self.data.points[f])[3])[t] = -10000
      duplicates = list(sorted(dups))

      
      for elem in duplicates:
        for f in range(n):
          if ((self.data.points[f])[3])[t] == elem:
            ((self.data.points[f])[3])[t] = -10000
# find unlabelled markers
  def findunlabelled(self):
  # checking unlabelled markers

    n = len(self.data.points)
    startt = self.jslider.getValue()
    print startt
    for t in range(startt+1, self.data.plen, 1):
      where = []
      for i in range(n-1):
          if( ((self.data.points[i])[3])[t] == -10000 ):
            where.append(i)
            self.jslider.setValue(t)
            if where[0]!=n-2:
              print 'unlabelled:', where
              return
    return


  def gotonextwithnonamy(self, namy):
    ttt = self.jslider.getValue()
    n = len(self.data.points)
    for t in range(ttt+1, self.data.plen, 1):
      foundit = False
      for i in range(n-1):
        if( ((self.data.points[i])[3])[t] == -1 ):
          foundit = True
          print t
          self.jslider.setValue(t)
          break
      if(foundit == False):
        return
    return

  def getsidesforsuperhead(self, tt):
    n = len(self.data.points)
    sides = zeros(n*n, 'd')
    for i in range(n):
      for j in range(i):
        for xx in range(3):
          sides[i*n+j] +=  ( ((self.data.points[i])[xx])[tt] - ((self.data.points[j])[xx])[tt] )**2 
        sides[j*n+i] = sides[i*n+j]
    return(sides)

  def superheadfillin(self, thresh, debug=0):
    print 'Filling in guys within tolerance', thresh

    n = len(self.data.points)
    allcombos = []
    for i in range(n):
      for j in range(n):
        if(i==j):
          continue
        for k in range(n):
          if(i==k or j==k):
            continue
          for m in range(n):
            if(i==m or j==m or m==k):
              continue
            allcombos.append([i,j,k,m])
    
    headnames = []
    headnames.append(0)
    headnames.append(1)
    headnames.append(2)
    headnames.append(3)

    mindists = zeros(self.data.plen, 'd')
    howmanyofeach = zeros(len(allcombos), 'i')
    H0 = zeros(self.data.plen, 'i')
    H1 = zeros(self.data.plen, 'i')
    H2 = zeros(self.data.plen, 'i')
    H3 = zeros(self.data.plen, 'i')
    told = self.jslider.getValue()
    n = len(self.data.points)

    if(len(headnames)<4):
      print 'cant find head because not enough points are identified'
      return
    for t in range(self.data.plen):
      allsides = self.getsidesforsuperhead(t)
      mindists[t] = 100000000000.
      found = 0
      counter = -1
      tvals = zeros(6, 'd') 
      whichcanskip = zeros(len(allcombos), 'i')
      for ii in range(n):
        if(((self.data.points[ii])[4])[t] < -100):
          continue
        else:
          disname = ((self.data.points[ii])[3])[t]
          isaheadguy = False
          for i in range(len(headnames)):
            if(headnames[i] == disname):
              isaheadguy = True

          if(isaheadguy == True):
            for jj in range(len(allcombos)):
              keepme = False
              for kk in range(4):
                if(disname == headnames[kk] and (allcombos[jj])[kk] == ii):
                  keepme = True
              if(keepme == False):
                whichcanskip[jj] = 1
          else:
            for jj in range(len(allcombos)):
              keepme = True
              for kk in range(4):
                if((allcombos[jj])[kk] == ii):
                  keepme = False
              if(keepme == False):
                whichcanskip[jj] = 1
                print t, jj, 'skipped because point in place is something else'


      dists = zeros(len(allcombos), 'd')
      numfound = 0
      for xx in range(len(allcombos)):
        if(whichcanskip[xx] == 1):
          dists[xx] = 100000000000000000
          continue

        counter = 0
        dodo = zeros(6,'d')
        for ii in range(1,4,1):
          for jj in range(ii):
            counter += 1
            sidevalue = allsides[ ((allcombos[xx])[ii]) * n + (allcombos[xx])[jj] ]
            dodo[counter-1] = sidevalue
            dists[xx] += (sidevalue - self.avevals[counter-1])**2 
        
        
        dists[xx] = math.sqrt(dists[xx]/6.)
        if(dists[xx] < mindists[t]):
          mindists[t] = dists[xx]
          H0[t] = (allcombos[xx])[0]
          H1[t] = (allcombos[xx])[1]
          H2[t] = (allcombos[xx])[2]
          H3[t] = (allcombos[xx])[3]

        if(dists[xx] < thresh):
          numfound += 1
      howmanyofeach[numfound] += 1


      if((t%100)==0 or t==self.data.plen-1):
        self.jslider.setValue(t)

      if(debug==0):
          if(t==5000):
            strout = 'Out of the first 5000,\n'
            for i in range(len(howmanyofeach)):
              if(howmanyofeach[i] > 0):
                strout = '%s%d that passed the threshold %d times\n'%(strout, howmanyofeach[i], i)
            strout = '%sWould you like to continue and have it do the labeling?'%strout
            if(JOptionPane.showConfirmDialog(None,strout ,"Question",JOptionPane.YES_NO_OPTION) != JOptionPane.YES_OPTION):
              return

    if(len(headnames)<4):
      print 'cant find head because not enough points are identified'
      return
    for t in range(self.data.plen):
      if(mindists[t] < thresh):
        if(((self.data.points[H0[t]])[4])[t] != -1):
          ((self.data.points[H0[t]])[3])[t] = headnames[0]
          ((self.data.points[H0[t]])[4])[t] = mindists[t]
        if(((self.data.points[H1[t]])[4])[t] != -1):
          ((self.data.points[H1[t]])[3])[t] = headnames[1]
          ((self.data.points[H1[t]])[4])[t] = mindists[t]
        if(((self.data.points[H2[t]])[4])[t] != -1):
          ((self.data.points[H2[t]])[3])[t] = headnames[2]
          ((self.data.points[H2[t]])[4])[t] = mindists[t]
        if(((self.data.points[H3[t]])[4])[t] != -1):
          ((self.data.points[H3[t]])[3])[t] = headnames[3]
          ((self.data.points[H3[t]])[4])[t] = mindists[t]
      if((t%100)==0 or t==self.data.plen-1):
        self.jslider.setValue(t)
    self.jslider.setValue(told)


  def superheadfindaverage(self):
    headnames = []
    headnames.append(0)
    headnames.append(1)
    headnames.append(2)
    headnames.append(3)

    ### GET AVERAGE VALUES FROM THE FIRST 4 POINTS
    n = len(self.data.points)
    allvalues = []
    tinds = []
    for i in range(6):
      allvalues.append([])
    for t in range(self.data.plen):
      allsides = self.getsidesforsuperhead(t)
      found = 0
      counter = 0
      tvals = zeros(6, 'd') 
      for ii in range(1,4,1):
        ind0 = -10
        for yy in range(n):
          if(headnames[ii] == ((self.data.points[yy])[3])[t]):
            ind0 = yy
        for jj in range(ii):
          counter += 1
          ind1 = -10
          for xx in range(n):
            if(headnames[jj] == ((self.data.points[xx])[3])[t]):
              ind1 = xx
          if(ind0>-1 and ind1>-1):
            found += 1
            tvals[counter-1] = allsides[ind0*n+ind1]
      if(found == 6):
        tinds.append(t)
        for i in range(6):
          (allvalues[i]).append(tvals[i])

    self.avevals = zeros(6,'d')
    if(len(allvalues[0])>0):
      for i in range(6):
        self.avevals[i] = sum(allvalues[i])/float(len(allvalues[i]))
      print 'average values', self.avevals

      dists = zeros(len(allvalues[0]), 'd')
      mindist = 100000000.
      self.closestpointtoaveragepoints = None
      for i in range(len(allvalues[0])):
        for j in range(6):
          dists[i] += ((allvalues[j])[i] - self.avevals[j])**2
        dists[i] = math.sqrt(dists[i])
        if(dists[i] < mindist):
          pnts = []
          for xxx in range(4):
            pnt = []
            for poop in range(n):
              if(headnames[xxx] == ((self.data.points[poop])[3])[i]):
                for yyy in range(3):
                  pnt.append( ((self.data.points[poop])[yyy])[i] + 0. )
                pnts.append(pnt)
          if(len(pnts)==4):
            mindist = dists[i]
            self.closestpointtoaveragepoints = pnts
            
          
      mv = sum(dists)/float(len(dists))
      stddist = 0
      for i in range(len(allvalues[0])):
        stddist += (dists[i] - mv)**2
      stddist = math.sqrt(stddist/float(len(allvalues[0])))

      print 'max rms distance of values', max(dists)
      print 'min rms distance of values', min(dists)
      print 'mean rms distance of values', mv
      print 'std rms distance of values', stddist

      print 'closest point to the average (used for getting head coordinates)'
      print self.closestpointtoaveragepoints

      badindices = []
      for i in range(len(allvalues[0])):
        if(abs(dists[i]-mv)>4*stddist):
          badindices.append(tinds[i])
      print 'indices of those more than 4*std from the mean (if any):', badindices

  def adjustdisplaybox(self):  #### WOULDN'T IT MAKE MORE SENSE TO DO THIS IN ALL DEGREES A FREEDOM (ALL THREE ANGLES)
    t0 = Transform3D()
    t0.rotZ(self.data.boundingboxrotation)
    t1 = Transform3D()
    t1.setTranslation(Vector3f( self.data.boundingboxtransX, self.data.boundingboxtransY, -0.1))
    t2 = Transform3D()
    t2.setScale( Vector3d(self.data.boundingboxscaleX, self.data.boundingboxscaleY, 1.) ) ## note default box has side of '1'
    tt = Transform3D()
    tt.mul(t0,t1)
    tt.mul(t2)
    self.boxtgroup.setTransform(tt)


  def fitdisplayboxtopath(self):
    TT = len((self.data.points[0])[0])
    npts = len(self.data.points)

    def getextremesofpoints(checkang):
      minxxx = 100000000000.
      maxxxx = -100000000000.
      minyyy = 100000000000.
      maxyyy = -100000000000.
      cosguy = math.cos(checkang)
      singuy = math.sin(checkang)

      for i in range(npts):
        thingies = ((self.data.points[i])[3])
        xpts = ((self.data.points[i])[0])
        ypts = ((self.data.points[i])[1])
        for t in range(TT):
          if(thingies[t]>-1):
            tempX = (xpts[t])*cosguy - (ypts[t])*singuy
            tempY = (ypts[t])*cosguy + (xpts[t])*singuy
            if(tempX > maxxxx):
              maxxxx = tempX
            if(tempX < minxxx):
              minxxx = tempX
            if(tempY > maxyyy):
              maxyyy = tempY
            if(tempY < minyyy):
              minyyy = tempY
      return([maxxxx, minxxx, maxyyy, minyyy])

    def getarea(pp, dummy):
      vs = getextremesofpoints(pp[0])
      return( (vs[0]-vs[1])*(vs[2]-vs[3]) ) #return area of rectangle

    mmm = ij.measure.Minimizer()
    mmm.setFunction(getarea, 1)
    mmm.setMaxError(0.00001)
    mmm.setMaxRestarts(50)
    mmm.minimize([random.random()*0.1-0.05], [0.1])
    winval = getarea(mmm.getParams(), 1.)
    zeroval = getarea([0.], 0.)
    pp = mmm.getParams()


    vs = getextremesofpoints(pp[0])
    print 'Optimal rotation:', -pp[0], 'box extremes', vs

    self.data.boundingboxrotation = -pp[0]
    self.data.boundingboxtransX = (vs[0]+vs[1])/2.
    self.data.boundingboxtransY = (vs[2]+vs[3])/2.
    self.data.boundingboxscaleX = vs[0]-vs[1]
    self.data.boundingboxscaleY = vs[3]-vs[2]
    self.adjustdisplaybox()

  def fillinpoints(self, whichkind, thresh):
    ## GET THRESHOLD FROM GUI
    thresh2 = thresh**2
    TT = len((self.data.points[0])[0])
    npts = len(self.data.points)
    told = self.jslider.getValue()
    for t in range(TT):
      for i in range(npts):
        if( (whichkind==0 and ((self.data.points[i])[3])[t] > -1) or ( whichkind == 1 and abs(((self.data.points[i])[4])[t] + 1) < 0.001 ) ):
          ppp = [ ((self.data.points[i])[0])[t], ((self.data.points[i])[1])[t], ((self.data.points[i])[2])[t] ]
          if(t+1<TT):
            for ttt in range(t+1, TT, 1):
              minind = -100
              mindist = 1000000.
              for j in range(npts):
                dist = (ppp[0] - ((self.data.points[j])[0])[ttt])**2 + (ppp[1] - ((self.data.points[j])[1])[ttt])**2 + (ppp[2] - ((self.data.points[j])[2])[ttt])**2 
                if(dist < mindist):
                  mindist = dist
                  minind = j
              if( mindist < thresh2 ):
                if( ((self.data.points[minind])[3])[ttt] > -1 ):
                  if( ((self.data.points[minind])[3])[ttt] != ((self.data.points[i])[3])[t]):
                    print 'Conflicting guy at time', ttt
                  break
                ((self.data.points[minind])[3])[ttt] = ((self.data.points[i])[3])[t] + 0
                ((self.data.points[minind])[4])[ttt] = math.sqrt(mindist) + 0.
                ppp = [ ((self.data.points[minind])[0])[ttt], ((self.data.points[minind])[1])[ttt], ((self.data.points[minind])[2])[ttt] ]
              else:
                break

          ppp = [ ((self.data.points[i])[0])[t], ((self.data.points[i])[1])[t], ((self.data.points[i])[2])[t] ]
          if(t>0):
            for ttt in range(t-1, -1, -1):
              minind = -100
              mindist = 1000000.
              for j in range(npts):
                dist = (ppp[0] - ((self.data.points[j])[0])[ttt])**2 + (ppp[1] - ((self.data.points[j])[1])[ttt])**2 + (ppp[2] - ((self.data.points[j])[2])[ttt])**2 
                if(dist < mindist):
                  mindist = dist
                  minind = j
              if( mindist < thresh2 ):
                if( ((self.data.points[minind])[3])[ttt] > -1 ):
                  if( ((self.data.points[minind])[3])[ttt] != ((self.data.points[i])[3])[t]):
                    print 'Conflicting guy at time', ttt
                  break
                ((self.data.points[minind])[3])[ttt] = ((self.data.points[i])[3])[t] + 0
                ((self.data.points[minind])[4])[ttt] = math.sqrt(mindist) + 0.
                ppp = [ ((self.data.points[minind])[0])[ttt], ((self.data.points[minind])[1])[ttt], ((self.data.points[minind])[2])[ttt] ]
              else:
                break
      if( t%100 == 0 ):
        self.jslider.setValue(t)
    self.jslider.setValue(told)

  def synchwithratcam(self):
    fnamepoop = self.data.actualavifile
    if(os.path.isfile(fnamepoop)):

      centerpanel = JPanel()
      centerpanel.setLayout(GridLayout(2,2))

      centerpanel.add(JLabel("Convert to gray "))
      convtogray = JCheckBox("")
      convtogray.setSelected(True)
      centerpanel.add(convtogray)

      centerpanel.add(JLabel("Load virtually "))
      loadvirtually = JCheckBox("")
      loadvirtually.setSelected(True)
      centerpanel.add(loadvirtually)

      centerpanel.validate()
      centerpanel.setVisible(True)
      sel = JOptionPane.showConfirmDialog(None, centerpanel, 'Ratcam infomation', JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE)


      im0 = AVI_Reader().makeStack(fnamepoop, 1, 0, loadvirtually.isSelected(), convtogray.isSelected(), False)
      self.implus = ImagePlus('%s'%(fnamepoop),im0)
      self.implus.show()
      class ML(ImageListener):
        def setparentguy(self, parentguy):
          self.parentguy = parentguy
        def imageUpdated(self, eventimage):
          if(self.parentguy.avoidrecursionwithtimepoints == 0 or self.parentguy.avoidrecursionwithtimepoints == 1):
            return
          self.parentguy.avoidrecursionwithtimepoints = 1
          jj = eventimage.currentSlice
          self.parentguy.impluscurrentslice = jj
          timeinother = int(self.parentguy.data.framerate* (self.parentguy.data.startratcamtimestamp + float(jj)/self.parentguy.data.ratcamframerate - self.parentguy.data.starttrackingtimestamp) )
          if(timeinother<0):
            timeinother = 0
          if(timeinother>self.parentguy.data.plen-1):
            timeinother = self.parentguy.data.plen-1
          self.parentguy.jslider.setValue(int(timeinother))
          self.parentguy.avoidrecursionwithtimepoints = 2
      ml = ML()
      ml.setparentguy(self)
      self.implus.addImageListener(ml)

      print 'estimated number of seconds from rat cam', float(self.implus.getNSlices())/self.data.ratcamframerate
      print 'estimated number of seconds from tracking', float(self.data.plen)/self.data.framerate
      print 'estimated from ttl start and stop', self.data.stoptrackingtimestamp - self.data.starttrackingtimestamp
      print 'estimated from session start and stop', float(self.data.stopsessiontimestamp-self.data.startsessiontimestamp)/1000.
      print 'estimated from vt1 start and stop', float(self.data.stopratcamtimestamp-self.data.startratcamtimestamp)/1000.
      #print 'original number of frames', numoforiginalframes
      print 'number of frames in gui', self.implus.getNSlices()

  def settimepoint(self, t=-100,told=-100):

    if(self.avoidrecursionwithtimepoints == 0):
      return
    if(self.avoidrecursionwithtimepoints == 2):
      self.avoidrecursionwithtimepoints = 0
    if(t<0):
      if(self.jslider == None):
        self.avoidrecursionwithtimepoints = 2
        return
      t = self.jslider.getValue()

    if(t>self.data.plen-1):
      self.avoidrecursionwithtimepoints = 2
      return
    
    ####MOOOGOOO/datatable

    self.datatable.tablemodel.updatet(t)

    if(self.implus != None and self.avoidrecursionwithtimepoints == 0):
      timeinother = int( self.data.ratcamframerate *  ((float(t)/self.data.framerate) + self.data.starttrackingtimestamp - self.data.startratcamtimestamp)  )
      if(timeinother != self.impluscurrentslice):
        if(timeinother>-1 and timeinother<self.implus.getNSlices()):
          self.implus.setSlice(timeinother)

    if(len(self.data.headorigin)>5): ### CHECK THINGY!!
      if(self.data.headorigin[t] != None):
        self.coordsysSwitch.setWhichChild(Switch.CHILD_ALL)
        mm = Matrix3d()
        mm.setColumn(0, self.data.headX[t])
        mm.setColumn(1, self.data.headY[t])
        mm.setColumn(2, self.data.headZ[t])
        tt = Transform3D(mm, self.data.headorigin[t], 1.)
        self.wickedheadTG.setTransform(tt)
      else:
        self.coordsysSwitch.setWhichChild(Switch.CHILD_NONE)
    else:
      self.coordsysSwitch.setWhichChild(Switch.CHILD_NONE)

    self.data.pointlabels = {}
    for i in range(len(self.mysuperpointlabeler.combolist)):
      self.data.pointlabels[self.mysuperpointlabeler.combolist[i].namy] = [ (self.cnames.keys())[ self.mysuperpointlabeler.combolist[i].getSelectedIndex() ], self.pointtypes[ self.mysuperpointlabeler.pointtypecombolist[i].getSelectedIndex() ] ]

    chkchkpointboxes = {}
    for i in range(len(self.mysuperpointlabeler.combolist)):
      chkchkpointboxes[self.mysuperpointlabeler.combolist[i].namy] = (self.mysuperpointlabeler.jcheckboxpoints[i]).isSelected()

    #if(self.data.analysisprogression > 4):
    if(self.jcombonames!=None):
      ind = self.jcombonames.getSelectedIndex()
      self.spikesSwitches[ind].setWhichChild(Switch.CHILD_MASK)
      self.fadedspikesSwitches[ind].setWhichChild(Switch.CHILD_MASK)
      bs = BitSet(len(self.allcells[ind]))
      bs2 = BitSet(len(self.allcells[ind]))
      sesstime = float(t)/self.data.framerate + self.data.starttrackingtimestamp - self.data.startsessiontimestamp
      for i in range(len(self.allcells[ind])):
        if( (self.allcells[ind])[i] <= sesstime and (self.allcells[ind])[i] > sesstime-10.):
          bs.set(i)
        if( (self.allcells[ind])[i] < sesstime-10.):
          bs2.set(i)
        if(told>-0.1):
          oldsesstime = float(told)/self.data.framerate + self.data.starttrackingtimestamp - self.data.startsessiontimestamp
          #if(math.fabs((self.allcells[ind])[i] - sesstime)<= 1./self.data.framerate):
          if((self.allcells[ind])[i]>oldsesstime and (self.allcells[ind])[i]<=sesstime):
            self.AudioClip.stop()
            self.AudioClip.setFramePosition(0)
            self.AudioClip.start()

      self.spikesSwitches[ind].setChildMask(bs)
      self.fadedspikesSwitches[ind].setChildMask(bs2)


    tt = float(t)/(self.data.framerate)
    mm = math.floor(tt/60.)
    #self.currtime.setText('%02d minutes and %02.1f seconds, rotz = %f'%(mm, (tt-mm*60.), zzzzzz))
    self.currtime.setText('%02d minutes, %02.1f seconds, frame number %d    '%(mm, (tt-mm*60.), t))

    if(self.data.analysisprogression > -1):
      bs = BitSet(len(self.pointsTGarray))
      if(self.data.jcheckorigpoints.isSelected()==False): # and self.jchecknonheadpoints.isSelected()==False):
        self.pointsSwitch.setWhichChild(Switch.CHILD_NONE)
        #for i in range(len(self.pointsTGarray)):
          #bs.set(i)
      else:
        self.pointsSwitch.setWhichChild(Switch.CHILD_MASK)
        for i in range(len(self.pointsTGarray)):
          xx = ((self.data.points[i])[0])[t]
          if( xx < -1000 ):
            continue

          pp = ((self.data.points[i])[3])[t]
          if(pp > -1):
            if(chkchkpointboxes[pp]==False):
              continue

          bs.set(i)
          yy = ((self.data.points[i])[1])[t]
          zz = ((self.data.points[i])[2])[t]
          tt = Transform3D()
          tt.setTranslation( Vector3f(xx, yy, zz) )
          (self.pointsTGarray[i]).setTransform(tt)
          ap = Appearance()
          ca = ColoringAttributes()
          if(((self.data.points[i])[3])[t] > -1):
            ccind = (self.data.pointlabels[pp])[0]
            cc = self.cnames[ccind]
            ca.setColor(cc[0]/255., cc[1]/255., cc[2]/255.)
          else:
            ca.setColor(Color3f(0.1,0.1,0.1))
          ap.setColoringAttributes(ca)
          (self.pointsSParray[i]).setAppearance(ap)
        self.pointsSwitch.setChildMask(bs)

    self.avoidrecursionwithtimepoints = 2

  def getdirofmov(self):
    self.dirofmov = []
    dtguy = self.data.framerate  #### PARAMETER!!
    for t in range(self.data.plen):
      if(t<dtguy+1 or t>(self.data.plen-dtguy-1)):
        self.dirofmov.append(None)
      elif(math.fabs(self.dists[t-dtguy])>0.0001 or math.fabs(self.dists[t+dtguy])>0.0001 or math.fabs(self.dists[t])>0.0001): #### PARAMETER!!!!
        self.dirofmov.append(None)
      elif( (math.fabs((self.ddxx[0])[t]) + math.fabs((self.ddxx[1])[t]) + math.fabs((self.ddxx[2])[t]) < 0.01) ):
        self.dirofmov.append(None)
      else:
        xxdir = (self.adjpts[0])[t+dtguy] - (self.adjpts[0])[t-dtguy]
        yydir = (self.adjpts[1])[t+dtguy] - (self.adjpts[1])[t-dtguy]
        zzdir = (self.adjpts[2])[t+dtguy] - (self.adjpts[2])[t-dtguy]
        lenvec = math.sqrt(xxdir*xxdir + yydir*yydir + zzdir*zzdir)
        if(lenvec<=0.1): #### PARAMETER!!!!
          self.dirofmov.append(None)
        else:
          self.dirofmov.append(Vector3d(xxdir/lenvec, yydir/lenvec, zzdir/lenvec))

  def optimizefororientationstuff(self, minspeed, ddtt, debug=0):
    superXorients = []
    superYorients = []
    superZorients = []
    dirofmov = []
    avespeeds = []

    for t in range(ddtt, self.data.plen-ddtt, 1):
      if(self.data.headorigin[t] == None or self.data.headorigin[t-ddtt] == None or self.data.headorigin[t+ddtt] == None):
        continue

      xxdir = (self.data.headorigin[t+ddtt]).x - (self.data.headorigin[t-ddtt]).x
      yydir = (self.data.headorigin[t+ddtt]).y - (self.data.headorigin[t-ddtt]).y
      zzdir = (self.data.headorigin[t+ddtt]).z - (self.data.headorigin[t-ddtt]).z
      lenvec = math.sqrt(xxdir*xxdir + yydir*yydir + zzdir*zzdir)
      avespeed = 100.*lenvec*(self.data.framerate)/(2.*ddtt) # in cm/s

      if(avespeed > minspeed): ### only keep time points when he is really moving
        avespeeds.append(avespeed)
        dirofmov.append(Vector3d(xxdir/lenvec, yydir/lenvec, zzdir/lenvec))
        superXorients.append( self.data.headX[t] ) #Vector3d( (self.data.headX[t]).x, (self.data.headX[t]).y, (self.data.headX[t]).z ) )
        superYorients.append( self.data.headY[t] )# Vector3d( (self.data.headY[t]).x, (self.data.headY[t]).y, (self.data.headY[t]).z ) )
        superZorients.append( self.data.headZ[t] )# Vector3d( (self.data.headZ[t]).x, (self.data.headZ[t]).y, (self.data.headZ[t]).z ) )

    def rotatetheguys(xxx, yyy, zzz, ppp):
      #rotate about the 'x'
      rotate = Matrix3d()
      rotate.set(AxisAngle4d(xxx, ppp[0]))
      rotate.transform(yyy, yyy)
      rotate.transform(zzz, zzz)

      #rotate about the 'y'
      rotate = Matrix3d()
      rotate.set(AxisAngle4d(yyy, ppp[1]))
      rotate.transform(xxx, xxx)
      rotate.transform(zzz, zzz)

      #rotate about the 'z'
      rotate = Matrix3d()
      rotate.set(AxisAngle4d(zzz, ppp[2]))
      rotate.transform(yyy, yyy)
      rotate.transform(xxx, xxx)
      return(xxx, yyy, zzz)


    uupp = Vector3d(0., 0., 1.)
    def costfunctionforrotations(ppp, dummy): 
      totalcost = 0.

      superXorientsOPT = copy.deepcopy(superXorients)
      superYorientsOPT = copy.deepcopy(superYorients)
      superZorientsOPT = copy.deepcopy(superZorients)

      rat = 0.9
      ang1err = 0.
      ang2err = 0.
      for i in range(len(dirofmov)):
        superXorientsOPT[i], superYorientsOPT[i], superZorientsOPT[i] = rotatetheguys(superXorientsOPT[i], superYorientsOPT[i], superZorientsOPT[i], ppp)
        ang1 = (dirofmov[i]).angle(superXorientsOPT[i])
        ang2 = uupp.angle(superZorientsOPT[i])
        ang1err += math.fabs(ang1)
        ang2err += math.fabs(ang2)
        totalcost += (rat)*ang1*ang1 + (1.-rat)*ang2*ang2
      if(False):
        print rat, ppp[0], ppp[1], ppp[2], totalcost/float(len(dirofmov)), ang1err/float(len(dirofmov)), ang2err/float(len(dirofmov))
      return totalcost/float(len(dirofmov))

    mmm = ij.measure.Minimizer()
    mmm.setFunction(costfunctionforrotations, 3)
    mmm.setMaxError(0.001)
    mmm.setMaxRestarts(5)
    mmm.minimize([random.random()*2.*math.pi, random.random()*2.*math.pi, random.random()*2.*math.pi], [1.,1.,1.])
    ppp = mmm.getParams()
    winval = costfunctionforrotations(ppp, -1.)
    zeroval = costfunctionforrotations([0.,0.,0.], -1.)

    ## rotate them

    strout = 'Rotations = %f, %f, %f\n'%(ppp[0], ppp[1], ppp[2])
    strout = '%svalue at winner = %f\n'%(strout,winval)
    strout = '%svalue at zero = %f\n'%(strout, zeroval)
    if(debug==0):
        strout = '%sWould you like to use these?'%(strout)
        if(JOptionPane.showConfirmDialog(None,strout ,"Question",JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION):
          for t in range(self.data.plen):
            if(self.data.headorigin[t] == None):
              continue
            self.data.headX[t], self.data.headY[t], self.data.headZ[t] = rotatetheguys(self.data.headX[t], self.data.headY[t], self.data.headZ[t], ppp)
          self.settimepoint()
    else:
      print strout
      for t in range(self.data.plen):
        if(self.data.headorigin[t] == None):
          continue
        self.data.headX[t], self.data.headY[t], self.data.headZ[t] = rotatetheguys(self.data.headX[t], self.data.headY[t], self.data.headZ[t], ppp)
      self.settimepoint()

  def transformcsystomin(self, ddtt, debug=0):
    if(len(self.data.headorigin) < 5):
      print 'You need to get head coordinate thing going before you can transform them (of course)'
      return

    ddtt = int(ddtt)
    ooo = Array2DRowRealMatrix(self.data.plen,3)
    dddxxx = Array2DRowRealMatrix(self.data.plen,3)
    dddyyy = Array2DRowRealMatrix(self.data.plen,3)
    dddzzz = Array2DRowRealMatrix(self.data.plen,3)
    zzz = zeros(3, 'd')
    indo = []
    indp = []
    indm = []
    for t in range(self.data.plen):
      chk = False
      if(t>ddtt-1 and t<self.data.plen-ddtt):
        if(self.data.headorigin[t] != None):
          ooo.setRow(t, [(self.data.headorigin[t]).x, (self.data.headorigin[t]).y, (self.data.headorigin[t]).z])
          dddxxx.setRow(t, [(self.data.headX[t]).x, (self.data.headX[t]).y, (self.data.headX[t]).z] )
          dddyyy.setRow(t, [(self.data.headY[t]).x, (self.data.headY[t]).y, (self.data.headY[t]).z] )
          dddzzz.setRow(t, [(self.data.headZ[t]).x, (self.data.headZ[t]).y, (self.data.headZ[t]).z] )
          chk = True
        if(self.data.headorigin[t-ddtt] != None and self.data.headorigin[t] != None and self.data.headorigin[t+ddtt] != None ):
          indo.append(t)
          indp.append(t+ddtt)
          indm.append(t-ddtt)

      if(chk == False):
        ooo.setRow(t, zzz)
        dddxxx.setRow(t, zzz)
        dddyyy.setRow(t, zzz)
        dddzzz.setRow(t, zzz)

    subx = range(3)

    def supercostfunction(pp, dummy):
      newooo = ((ooo.add( dddxxx.scalarMultiply(pp[0]) )).add( dddyyy.scalarMultiply(pp[1]) )).add( dddzzz.scalarMultiply(pp[2]) )

      lilooo = newooo.getSubMatrix(indo,subx)
      lilppp = newooo.getSubMatrix(indp,subx)
      lilmmm = newooo.getSubMatrix(indm,subx)
      chkooo = (lilmmm.add(lilppp)).scalarMultiply(0.5)

      return (chkooo.subtract(lilooo)).getFrobeniusNorm()
    
    mmm = ij.measure.Minimizer()
    mmm.setFunction(supercostfunction, 3)
    mmm.setMaxError(0.00001)
    mmm.setMaxRestarts(50)
    mmm.minimize([random.random()*0.1-0.05, random.random()*0.1-0.05, random.random()*0.1-0.05], [0.1,0.1,0.1])
    winval = supercostfunction(mmm.getParams(), 1.)
    zeroval = supercostfunction([0.,0.,0.], 0.)
    pp = mmm.getParams()
    #print 'ALL, dt =', ddtt, 'params =', pp[0], pp[1], pp[2], 'win', winval, 'zero', zeroval, 'ratio', (zeroval-winval)/zeroval

    newheadorigin = []
    for t in range(0, self.data.plen, 1):
      if(self.data.headorigin[t] == None):
        newheadorigin.append(None)
      else:
        newp = Vector3d( [0.,0.,0.] )
        newp.scaleAdd(pp[0], self.data.headX[t], self.data.headorigin[t])
        newp.scaleAdd(pp[1], self.data.headY[t], newp)
        newp.scaleAdd(pp[2], self.data.headZ[t], newp)
        newheadorigin.append(newp)

    strout = 'Displacements = %f, %f, %f\n'%(pp[0], pp[1], pp[2])
    strout = '%svalue at winner = %f\n'%(strout,winval)
    strout = '%svalue at zero = %f\n'%(strout, zeroval)
    strout = '%sratio = %f\n'%(strout, (zeroval-winval)/zeroval)
    if(debug==0):
      strout = '%sWould you like to use these?'%(strout)
      if(JOptionPane.showConfirmDialog(None,strout ,"Question",JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION):
        self.data.headorigin = newheadorigin
        self.settimepoint()
    else:
      self.data.headorigin = newheadorigin
      self.settimepoint()

  def getfirstpartforcoordsys(self, pnt, skipone=-10):
    n = 4
    if(skipone>-1):
      n=3
    AA = Array2DRowRealMatrix(n,3)
    onefs = []
    for i in range(4):
      if(skipone == i):
        continue
      AA.setRow(len(onefs), pnt[i])
      onefs.append(1./float(n))
    onefourths = Array2DRowRealMatrix(1,n)
    onefourths.setRow(0, onefs)
    muA = onefourths.multiply(AA)
    cAs = Array2DRowRealMatrix(n,3)
    for i in range(n):
      cAs.setRow(i, ((AA.getRowMatrix(i)).subtract(muA)).getRow(0))

    #Asvd = SingularValueDecomposition(cAs)
    #AS = Asvd.getSingularValues()
    #AV = Asvd.getV()

    axisguys = Array2DRowRealMatrix(4,3)
    #axisguys.setRow(0,muA.getRow(0))
    #for i in range(3):
      #axisguys.setRow(i+1, (muA.add(AV.getRowMatrix(i))).getRow(0))
    for i in range(4):
      axisguys.setRow(i,muA.getRow(0))
    for i in range(3): # Add [1,0,0] to x-dir, etc....
      axisguys.addToEntry(i+1, i, 1.) 

    return cAs, muA, axisguys

  def rigidtransform(self, cAs, muA, axisguys, B):
    n = B.getRowDimension()
    onefs = []
    for i in range(n):
      onefs.append(1./float(n))
    onefourths = Array2DRowRealMatrix(1,n)
    onefourths.setRow(0, onefs)
    muB = onefourths.multiply(B)
    cBs = Array2DRowRealMatrix(n,3)
    for i in range(n):
      cBs.setRow(i, ((B.getRowMatrix(i)).subtract(muB)).getRow(0))
    H = (cAs.transpose()).multiply(cBs)
    Bsvd = SingularValueDecomposition(H)
    Ut = Bsvd.getUT()
    V = Bsvd.getV()
    R = V.multiply(Ut)

    if((LUDecomposition(R)).getDeterminant() < 0):
      vc = V.getColumn(2)
      for i in range(len(vc)):
        vc[i] = -1.*vc[i]
      V.setColumn(2, vc)
      R = V.multiply(Ut)

    temp = R.multiply( muA.transpose() )
    tt = (muB.transpose()).subtract(temp)
    RRtAX = (R.multiply(axisguys.transpose()))

    orig = Vector3d( ((RRtAX.getColumnMatrix(0)).add(tt)).getColumn(0) )
    headX = Vector3d( ((RRtAX.getColumnMatrix(1)).add(tt)).getColumn(0) )
    headX.sub(orig)
    headY = Vector3d( ((RRtAX.getColumnMatrix(2)).add(tt)).getColumn(0) )
    headY.sub(orig)
    headZ = Vector3d( ((RRtAX.getColumnMatrix(3)).add(tt)).getColumn(0) )
    headZ.sub(orig)

    return orig, headX, headY, headZ

  def getheadorigin(self):
    headnames = []
    headnames.append(0)
    headnames.append(1)
    headnames.append(2)
    headnames.append(3)

    self.superheadfindaverage()

    ### AS AN ALTERNATIVE APPROACH
    ### THIS WILL BE CLEANER IF POINTS ARE ARTIFICIALLY ADDED TO THE DATA TO COMPLETE THE
    ### RIGID BODY. THEY DO NOT HAVE TO BE DISPLAYED BUT THIS THING OF APPLYING THE COORDINATE
    ### SYSTEM BY CONSIDERING THEM DIFFERENTLY IS CONFUSING. I DONT SEE ANYTHING
    ### WRONG WITH THE WAY IT IS CURRENTLY (THOUGH MAYBE THE ACTUALLY POSITION OF THE HEAD MIGHT GET
    ### DISPLACED SLIGHTLY SINCE THE CENTER OF THE POINTS (IN FIRST PART) WOULD BE DIFFERENT IF IT IS
    ### FOR 3 POINTS OR 4. EITHER WAY, THOSE POINTS ARE NOT ACTUALLY USE TO CALULATE ANYTHING CURRENTLY
    ### IT IS THE ANGLES THAT ARE USED AND THE NECK POINT BUT MAYBE THE DIFFERENCE BETWEEN THE NECK POINT
    ### AND THE HEAD ORIGIN COULD BE IMPROVED, ASSUMING THIS IS LESS OPTIMAL.

    cAs, muA, axisguys = self.getfirstpartforcoordsys(self.closestpointtoaveragepoints)
    cAs0, muA0, axisguys0 = self.getfirstpartforcoordsys(self.closestpointtoaveragepoints, 0)
    cAs1, muA1, axisguys1 = self.getfirstpartforcoordsys(self.closestpointtoaveragepoints, 1)
    cAs2, muA2, axisguys2 = self.getfirstpartforcoordsys(self.closestpointtoaveragepoints, 2)
    cAs3, muA3, axisguys3 = self.getfirstpartforcoordsys(self.closestpointtoaveragepoints, 3)

    print 'axis guys'
    print axisguys

    self.data.headorigin = []
    self.data.headX = []
    self.data.headY = []
    self.data.headZ = []
    n = len(self.data.points)

    ### note, the 'axisguys' are the axis as they relate to the original points
    ### so we are rotating and translating them from a reference frame of when they have
    ### all four points to the other (so no need to have axisguys1, etc.)
    for i in range(self.data.plen):
      def getletter(ZZZ):
        pnt = [-100000000,0,0]
        for poop in range(n):
          if(headnames[ZZZ] == ((self.data.points[poop])[3])[i]):
            for yyy in range(3):
              pnt[yyy] = ((self.data.points[poop])[yyy])[i] + 0. 
        return(pnt)

      AA = getletter(0)
      BB = getletter(1)
      CC = getletter(2)
      DD = getletter(3)

      if(AA[0]>-10000 and BB[0]>-10000 and CC[0]>-10000 and DD[0]>-10000):
        coords = Array2DRowRealMatrix(4,3)
        coords.setRow(0,AA)
        coords.setRow(1,BB)
        coords.setRow(2,CC)
        coords.setRow(3,DD)
        orig, headX, headY, headZ = self.rigidtransform(cAs, muA, axisguys, coords)
      elif(AA[0]<-10000 and BB[0]>-10000 and CC[0]>-10000 and DD[0]>-10000):
        coords = Array2DRowRealMatrix(3,3)
        coords.setRow(0,BB)
        coords.setRow(1,CC)
        coords.setRow(2,DD)
        orig, headX, headY, headZ = self.rigidtransform(cAs0, muA0, axisguys, coords)
      elif(AA[0]>-10000 and BB[0]<-10000 and CC[0]>-10000 and DD[0]>-10000):
        coords = Array2DRowRealMatrix(3,3)
        coords.setRow(0,AA)
        coords.setRow(1,CC)
        coords.setRow(2,DD)
        orig, headX, headY, headZ = self.rigidtransform(cAs1, muA1, axisguys, coords)
      elif(AA[0]>-10000 and BB[0]>-10000 and CC[0]<-10000 and DD[0]>-10000):
        coords = Array2DRowRealMatrix(3,3)
        coords.setRow(0,AA)
        coords.setRow(1,BB)
        coords.setRow(2,DD)
        orig, headX, headY, headZ = self.rigidtransform(cAs2, muA2, axisguys, coords)
      elif(AA[0]>-10000 and BB[0]>-10000 and CC[0]>-10000 and DD[0]<-10000):
        coords = Array2DRowRealMatrix(3,3)
        coords.setRow(0,AA)
        coords.setRow(1,BB)
        coords.setRow(2,CC)
        orig, headX, headY, headZ = self.rigidtransform(cAs3, muA3, axisguys, coords)
      else:
        self.data.headorigin.append(None)
        self.data.headX.append(None)
        self.data.headY.append(None)
        self.data.headZ.append(None)
        continue

      self.data.headorigin.append(orig)
      self.data.headX.append(headX)
      self.data.headY.append(headY)
      self.data.headZ.append(headZ)

      if(i<100):
        print 'ABCD(0)', AA[0], BB[0], CC[0], DD[0]
        print 'AA', AA
        print 'headx', headX
        print 'heady', headY
        print 'headz', headZ

  def addspikestostuff(self, allcells, allcellnames):

    self.funfilter.tabbedpane.setEnabledAt(1, True)  

    self.spikesSwitches = []
    self.fadedspikesSwitches = []
    ap = Appearance()
    mat = Material()
    mat.setEmissiveColor( Color3f(1,0.35,0.35) )
    mat.setDiffuseColor( Color3f(1,0.1,0.1) )
    mat.setSpecularColor( Color3f(1,0.1,0.7) )
    mat.setShininess(100.) #[0,128]
    ap.setMaterial(mat)

    ap2 = Appearance()
    ap2.setMaterial(mat)
    #trans = TransparencyAttributes(TransparencyAttributes.FASTEST, 0.7)
    #ap2.setTransparencyAttributes(trans)

    ddddd =  self.data.startsessiontimestamp - self.data.starttrackingtimestamp
    newcells = []
    for i in range(len(allcells)):
      acellarray = []
      sw = Switch()
      sw.setCapability(Switch.ALLOW_SWITCH_WRITE)
      sw.setCapability(Switch.ALLOW_SWITCH_READ)
      sw.setCapability(Switch.ALLOW_CHILDREN_WRITE);
      sw.setCapability(Switch.ALLOW_CHILDREN_EXTEND);
      tt = Transform3D()
      sw2 = Switch()
      sw2.setCapability(Switch.ALLOW_SWITCH_WRITE)
      sw2.setCapability(Switch.ALLOW_SWITCH_READ)
      sw2.setCapability(Switch.ALLOW_CHILDREN_WRITE);
      sw2.setCapability(Switch.ALLOW_CHILDREN_EXTEND);
      tt2 = Transform3D()
      #print 'datime', (allcells[i])[0], (allcells[i])[len(allcells[i])-1], allcellnames[i]
      for j in range(len(allcells[i])):
        jjj = int(math.floor(((allcells[i])[j] + ddddd)*(self.data.framerate))) #### 120 because that is the hertz of the recording thing
        if(jjj > self.data.plen-1):
          jjj = self.data.plen-1
          print 'Cell', i, 'spike', j, 'happened after tracking ended, it will not be used'
          continue
        if(jjj < 0):
          jjj = 0
          print 'Cell', i, 'spike', j, 'happened before tracking started, it will not be used'
          continue
        ##sesstime = float(t)/120.+self.data.starttrackingtimestamp - self.data.startsessiontimestamp
        closest = -1
        closestval = 10000000000000.
        for k in range(jjj-24, jjj+25, 1):
          if(k<0 or k>self.data.plen-1):
            continue
          if(self.data.headorigin[k] == None):
            continue
          if(math.fabs(k-jjj)<closestval):
            closestval = math.fabs(k-jjj)
            closest = k
          elif(math.fabs(k-jjj)==closestval):
            if(random.random()<0.5):
              closest = k
        if(closest == -1):
          print 'Cell', i, 'spike', j, 'happened when there was no head point identified in the 200ms to either side of frame (%d), it will not be used in the visible display of the activity'%jjj
          continue

        acellarray.append((allcells[i])[j])
        tt = Transform3D()
        tt.setTranslation(Vector3d(  (self.data.headorigin[closest]).x,  (self.data.headorigin[closest]).y, (self.data.headorigin[closest]).z ))

        cc0 = Sphere(0.01, ap)
        cc0.setCapability(Sphere.ENABLE_APPEARANCE_MODIFY)
        tg = TransformGroup(tt)
        tg.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE)
        tg.addChild(cc0)
        sw.addChild(tg)

        cc02 = Sphere(0.01, ap2)
        cc02.setCapability(Sphere.ENABLE_APPEARANCE_MODIFY)
        tg2 = TransformGroup(tt)
        tg2.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE)
        tg2.addChild(cc02)
        sw2.addChild(tg2)

      newcells.append(acellarray)
      self.allcells = newcells
      sw.setWhichChild(Switch.CHILD_NONE)
      bg2 = BranchGroup() ### may not be necessary!!
      bg2.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE) 
      bg2.setCapability(BranchGroup.ALLOW_CHILDREN_EXTEND);
      bg2.addChild(sw);
      self.maingroup.addChild(bg2)
      self.spikesSwitches.append(sw)

      sw2.setWhichChild(Switch.CHILD_NONE)
      bg22 = BranchGroup() ### may not be necessary!!
      bg22.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE) 
      bg22.setCapability(BranchGroup.ALLOW_CHILDREN_EXTEND);
      bg22.addChild(sw2);
      self.maingroup.addChild(bg22)
      self.fadedspikesSwitches.append(sw2)

    class jcombocellname(ItemListener):
      def __init__(self, parentguy):
        self.parentguy = parentguy
        self.oldone = 0
      def itemStateChanged(self, e):
        ind = self.parentguy.jcombonames.getSelectedIndex()
        self.parentguy.spikesSwitches[self.oldone].setWhichChild(Switch.CHILD_NONE)
        self.parentguy.spikesSwitches[ind].setWhichChild(Switch.CHILD_ALL)
        self.parentguy.fadedspikesSwitches[self.oldone].setWhichChild(Switch.CHILD_NONE)
        self.parentguy.fadedspikesSwitches[ind].setWhichChild(Switch.CHILD_ALL)
        self.oldone = ind
        self.parentguy.settimepoint()

    temp = JPanel()

    self.jcombonames = JComboBox(allcellnames)
    self.jcombonames.addItemListener(jcombocellname(self))
    temp.add(self.jcombonames)

    temp.validate()
    temp.repaint()
    c = GridBagConstraints()
    c.insets = Insets(3, 3, 3, 3)
    c.gridy = 2
    c.gridx = 3
    c.gridwidth = 1
    c.anchor = GridBagConstraints.LINE_END
    c.weightx = 0.0000000000001
    self.add(temp, c)

    self.revalidate()
    self.repaint()
    self.settimepoint()
    SwingUtilities.windowForComponent(self).revalidate()
    SwingUtilities.windowForComponent(self).pack()

  def calculatefiringrates(self, binsize, winsize):
    celldata = self.allcells[self.jcombonames.getSelectedIndex()]
    totaltimeinms = 1000.*(self.data.stopsessiontimestamp-self.data.startsessiontimestamp)
    windowsize = winsize/binsize

    cellstuff = zeros(int(math.floor(totaltimeinms/binsize)), 'f')
    ## LENGTH OF CELL STUFF 1207500
    #  LENGTH OF CELL STUFF 1051567
    # [0.39741666666666664, 0.8207708333333333, 1.1029791666666666, 1.6942291666666667, 1.7385833333333334, 1.8427708333333332, 2.2607916666666665, 3.7404166666666665, ....

    
    for sss in range(len(celldata)):
      cellstuff[int(math.floor( celldata[sss] * 1000 / binsize))] += 1.

    firingrates = zeros(len(cellstuff), 'd')
    for ii in range(len(cellstuff)):
      starti = ii-int(round(windowsize/2.))
      if(starti<0):
        starti = 0
      endi = ii+int(round(windowsize/2.))
      if(endi>len(cellstuff)-1):
        endi = len(cellstuff)-1
      firingrates[ii] = 1000. * float(sum( cellstuff[starti:endi] )) / (float(endi-starti) * binsize)
    return(firingrates)

  def funfiltertimerstuff(self, inratespeedup, outratespeedup, slowdowntimesintrackingtime):
    class onesettimerperformer(ActionListener):
      def __init__(self, parentguy, inratespeedup, outratespeed, slowdowntimesintrackingtime):
        self.parentguy = parentguy
        self.inrate = inratespeedup
        self.outrate = outratespeedup
        self.slowdowntimesintrackingtime = slowdowntimesintrackingtime
        self.startervalue = self.parentguy.jslider.getValue()
        self.currenttime = self.startervalue
        self.totaltime = 0.
        
      def actionPerformed(self, a):
        if(self.parentguy.funfilter.isVisible() == False):
          self.parentguy.onesettimer.stop()
        oldcv = int(round(self.currenttime))
        incv = int(round(self.currenttime+ self.inrate))
        if( self.slowdowntimesintrackingtime[oldcv] == 1 or self.slowdowntimesintrackingtime[incv] == 1):
          cv = incv
          self.currenttime += self.inrate
          self.totaltime += self.inrate
        else:
          self.currenttime += self.outrate
          self.totaltime += self.outrate
          cv = int(round(self.currenttime))
        if(cv >= self.parentguy.data.plen-1):
          self.parentguy.jslider.setValue(0)
          self.currenttime = 0.
        else:
          self.parentguy.jslider.setValue(cv)

        if(self.totaltime>self.parentguy.data.plen):
          self.parentguy.jslider.setValue(self.startervalue)
          self.parentguy.onesettimer.stop()

    if(self.onesettimer == None):
      self.onesettimer = Timer(1, onesettimerperformer(self, inratespeedup, outratespeedup, slowdowntimesintrackingtime))
    else:
      acs = self.onesettimer.getActionListeners()
      for ac in acs:
        self.onesettimer.removeActionListener(ac)
        ac = 0.
      self.onesettimer.addActionListener( onesettimerperformer(self, inratespeedup, outratespeedup, slowdowntimesintrackingtime) )
    self.onesettimer.start()

  def funwithfiringratefilterfromfile(self, moviefilename, inratespeedup, outratespeedup):
    if(self.onesettimer != None):
      if(self.onesettimer.isRunning() == True):
        self.onesettimer.stop()
        return

    slowdowntimesintrackingtime = zeros(self.data.plen, 'i')

    dafile = open(moviefilename)
    reader = csv.reader(dafile)
    dafile.seek(0)
    slowdownsegments = []
    for row in reader:
      if(len(row)==2):
        ii = int(round(float(row[0])))
        jj = int(round(float(row[1])))
        if(jj<ii):
          print 'WTF? %s has a line with entries'%moviefilenam, row
          continue
        if(ii<0 or jj<0 or ii>self.data.plen-1 or jj>self.data.plen-1):
          print 'WTF? %s has a line with entries'%moviefilenam, row
          continue
        if(jj == self.data.plen-2):
          jj = self.data.plen-1
        for i in range(ii, jj+1, 1):
          slowdowntimesintrackingtime[i] = 1
      else:
        print 'Skipped row, due to unrecognized formatting:', row

    self.funfiltertimerstuff(inratespeedup, outratespeedup, slowdowntimesintrackingtime)

  def funwithfiringratefilter(self, binsize, winsize, minfr, tsustained, addedslowdowntime, inratespeedup, outratespeedup):
    if(self.onesettimer != None):
      if(self.onesettimer.isRunning() == True):
        self.onesettimer.stop()
        return

    if(binsize>winsize):
      print 'Bin size is larger than window size, that does not make sense'
      return
    if(binsize>tsustained):
      print 'Bin size is larger than the time sustained, that does not make sense'
      return
    firingrates = self.calculatefiringrates(binsize, winsize)
    sustainedwindowsize = int(round( (tsustained/binsize) / 2. ))
    addedslowdowntime = int(round( (addedslowdowntime) )) ### SHOULD THIS BE SCALED??

    slowdowntimes = zeros(len(firingrates), 'i')
    for i in range(sustainedwindowsize, len(firingrates)-sustainedwindowsize):
      mininwindow = min(firingrates[(i-sustainedwindowsize):(i+sustainedwindowsize)])
      if(mininwindow > minfr):
        #print i, 'Min firing rate', minfr, 'data min', mininwindow
        for j in range(i-sustainedwindowsize-addedslowdowntime, i+sustainedwindowsize+addedslowdowntime, 1):
          if(j<0 or j>len(slowdowntimes)-1):
            continue
          slowdowntimes[j] = 1
 
    if(max(slowdowntimes)<1):
      print 'No events found, try again'
      return

    slowdowntimesintrackingtime = zeros(self.data.plen, 'i')
    for i in range(len(slowdowntimesintrackingtime)):
      sesstime = 1000. * (float(i)/float(self.data.framerate) + self.data.starttrackingtimestamp - self.data.startsessiontimestamp)
      ind = int(math.floor( sesstime / binsize))
      if(ind<0 or ind>len(slowdowntimes)-1):
        print 'frame number', i, 'at tracking time', 1000.*(float(i)/float(self.data.framerate) + self.data.starttrackingtimestamp),
        print ', which minus the start session time gives you this', 1000. * (float(i)/float(self.data.framerate) + self.data.starttrackingtimestamp - self.data.startsessiontimestamp),
        print 'which is outside the bounds of the estimated firing rates with length =', len(slowdowntimes), 'and index =', ind
        print 'please check the that all the time stamps are correct!!'
        print 'estimated length (s) of the tracking data from the original csv data', float(self.data.plen)/float(self.data.framerate)
        print 'estimated length (s) of the tracking data from the time stamps', (self.data.stoptrackingtimestamp - self.data.starttrackingtimestamp)
        print 'frame rate', self.data.framerate, 'number of frames', self.data.plen
        print 'for now we just skip this point but there should be a mistake somewhere'
        continue
      if(slowdowntimes[ind]>0):
        slowdowntimesintrackingtime[i] = 1
        #print i, firingrates[ind]

    self.funfiltertimerstuff(inratespeedup, outratespeedup, slowdowntimesintrackingtime)
      

  def displayfiringratehistogram(self, binsize, winsize):
    if(binsize>winsize):
      print 'Bin size is larger than window size, that does not make sense'
      return
    firingrates = self.calculatefiringrates(binsize, winsize)

    dataset = HistogramDataset()
    dataset.setType(HistogramType.FREQUENCY)
    dataset.addSeries("Hist",firingrates,30)
    chart = ChartFactory.createHistogram('', 'Firing rate (Hz)', '', dataset, PlotOrientation.VERTICAL, False, False, False)
    #chartpanpan = JPanel()
    chartpan = ChartPanel(chart)
    #chartpanpan.add(chartpan)
    #chartpanpan.validate()
    #chartpanpan.setVisible(True)
    frame = JFrame('Firing rate histogram for cell %s, bin size %0.2f, smoothing size %0.2f'%(self.data.allcellnames[self.jcombonames.getSelectedIndex()], binsize, winsize))
    frame.add(chartpan)
    frame.setLocation(500,300)
    #frame.setResizable(False)
    frame.pack()
    frame.setVisible(True)



  def settemplatepoints(self):
    self.templatepointsSwitch.removeAllChildren()
    self.templatepointsTGarray = []
    self.templatepointsSParray = []
    
    for ii in range(len(self.data.templatepoints)):
      p = self.data.templatepoints[ii]
      tt = Transform3D()
      tt.setTranslation(Vector3f(p[0], p[1], p[2]))
      ap = Appearance()
      ca = ColoringAttributes()
      ca.setColor(178./255., 34./255., 34./255.) # firebrick
      ap.setColoringAttributes(ca)
      cc = Sphere(0.005, Sphere.ENABLE_APPEARANCE_MODIFY, ap)
      tg = TransformGroup(tt)
      tg.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE)
      tg.addChild(cc)
      bgstupid = BranchGroup()
      bgstupid.addChild(tg)
      bgstupid.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE)
      self.templatepointsSwitch.addChild(bgstupid)
      self.templatepointsTGarray.append(tg)
      self.templatepointsSParray.append(cc)

    self.templatepointsSwitch.setWhichChild(Switch.CHILD_ALL)


  def setsuperpoints(self):
    self.pointsSwitch.removeAllChildren()
    self.pointsTGarray = []
    self.pointsSParray = []
    
    for ii in range(len(self.data.points)):
      tt = Transform3D()
      tt.setTranslation(Vector3f(0.,0., 0.))
      ap = Appearance()
      mat = Material()
      mat.setEmissiveColor( Color3f(0.1,0.65,0.35) )
      mat.setDiffuseColor( Color3f(0.1,0.6,0.1) )
      mat.setSpecularColor( Color3f(0.1,0.1,0.7) )
      mat.setShininess(50.) #[0,128]
      ap.setMaterial(mat)
      cc = Sphere(0.015, Sphere.ENABLE_APPEARANCE_MODIFY, ap)
      tg = TransformGroup(tt)
      tg.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE)
      tg.addChild(cc)
      bgstupid = BranchGroup()
      bgstupid.addChild(tg)
      bgstupid.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE) ## THIS MIGHT DO WHAT I THINK IT DOES :)
      self.pointsSwitch.addChild(bgstupid)
      self.pointsTGarray.append(tg)
      self.pointsSParray.append(cc)
    #self.pointsSwitch.addChild(self.pointsbranchgroup)

    self.jslider = JSlider(JSlider.HORIZONTAL, 0, self.data.plen, 1)
    c = GridBagConstraints()
    c.insets = Insets(3, 3, 3, 3)
    c.gridx = 0
    c.gridy = 0
    c.fill = GridBagConstraints.HORIZONTAL
    c.gridx = 1
    c.gridy = 1
    c.gridwidth=8
    self.add(self.jslider, c)
    
    class sliderchanger(ChangeListener):
      def __init__(self, parentguy):
        self.parentguy = parentguy
        self.oldvalue = 0
      def stateChanged(self, e):
        currval = e.getSource().getValue()
        if((currval-self.oldvalue) < 50. and (currval-self.oldvalue)>0.):
          self.parentguy.settimepoint(currval, self.oldvalue)
        else:
          self.parentguy.settimepoint(currval)
        self.oldvalue = currval

    self.jslider.addChangeListener(sliderchanger(self))
    self.jslider.setPreferredSize(Dimension(500,40))

    class timerperformer(ActionListener):
      def __init__(self, parentguy):
        self.parentguy = parentguy
        self.skippies = 1
      def actionPerformed(self, a):
        cv = self.parentguy.jslider.getValue()
        if(cv == self.parentguy.data.plen-1):
          self.parentguy.jslider.setValue(0)
        else:
          self.parentguy.jslider.setValue(cv+self.skippies)

    self.timeractionperformer = timerperformer(self)
    self.timer = Timer(2, self.timeractionperformer)
    startstopbut = JButton(':P')
    #startstopbut.setPreferredSize(Dimension(40, 20));
        
    class startstoplistener(ActionListener):
      def __init__(self, parentguy):
        self.parentguy = parentguy
      def actionPerformed(self, event):
        if(self.parentguy.timer.isRunning()):
          self.parentguy.timer.stop()
        else:
          self.parentguy.timer.start()
    startstopbut.addActionListener(startstoplistener(self))
    c.gridx=0
    c.gridwidth=1
    self.add(startstopbut, c)
    self.data.addthingies()
    self.revalidate()
    self.repaint()
    self.settimepoint()
    SwingUtilities.windowForComponent(self).revalidate()
    SwingUtilities.windowForComponent(self).pack()

  def setdapointwithdacolorandstuff(self, frompicker, addorremove):
    if(self.currentpointassigner < 0):
      return
    t = self.jslider.getValue()
    #print t, len( ((self.data.points[0])[3]) )
    for i in range(len(self.pointsSParray)):
      if(frompicker != (self.pointsSParray[i]).getShape()):
        continue
      if(addorremove>0):
        ((self.data.points[i])[3])[t] = self.currentpointassigner
        ((self.data.points[i])[4])[t] = -1
      else:
        ((self.data.points[i])[3])[t] = -10
        ((self.data.points[i])[4])[t] = -10000000
    self.settimepoint(t)

  def __init__(self):

    self.avoidrecursionwithtimepoints = 2
    self.implus = None
    self.impluscurrentslice = 1

    soundName = '%s/Lib/spike.wav'%(getProperty('python.home'))
    self.AudioClip = AudioSystem.getClip()
    self.AudioSystemGuy = AudioSystem.getAudioInputStream(io.File(soundName).getAbsoluteFile())
    self.AudioClip.open(self.AudioSystemGuy)

    self.avevals = None
    self.jslider = None
    self.timer = None
    self.onesettimer = None
    self.numberofnamedpoints = 0
    self.currentpointassigner = -10
    self.jcombonames = None
    #self.setBorder(BorderFactory.createLineBorder(Color.black))
    self.pointtypes = ['first head',  'second head',  'third head',  'fourth head',  'neck',  'middle',  'ass',  'garbage',  'user defined (1)',  'user defined (2)',  'user defined (3)',  'user defined (4)',  'user defined (5)',  'user defined (6)',  'user defined (7)',  'user defined (8)',  'user defined (9)',  'user defined (10)' ]
    self.cnames = {'fire brick': (178, 34, 34), 'cadet blue': (95, 158, 160), 'indigo': (75, 0, 130), 'sea green': (46, 139, 87), 'medium violet red': (199, 21, 133), 'old lace': (253, 245, 230), 'yellow': (255, 255, 0), 
        'slate gray': (112, 128, 144), 'medium spring green': (0, 250, 154), 'medium slate blue': (123, 104, 238), 'light yellow': (255, 255, 224), 'pale turquoise': (175, 238, 238), 'navajo white': (255, 222, 173), 
        'orange red': (255, 69, 0), 'misty rose': (255, 228, 225), 'black': (0, 0, 0), 'dark sea green': (143, 188, 143), 'crimson': (220, 20, 60), 'brown': (165, 42, 42), 'turquoise': (64, 224, 208), 'yellow green': (154, 205, 50), 
        'pale goldenrod': (238, 232, 170), 'light slate gray': (119, 136, 153), 'dark olive green': (85, 107, 47), 'cyan': (0, 255, 255), 'green yellow': (173, 255, 47), 'silver': (192, 192, 192), 'gray': (128, 128, 128), 
        'dark violet': (148, 0, 211), 'teal': (0, 128, 128), 'dark gray': (169, 169, 169), 'dark orange': (255, 140, 0), 'peach puff': (255, 218, 185), 'deep pink': (255, 20, 147), 'steel blue': (70, 130, 180), 
        'forest green': (34, 139, 34), 'thistle': (216, 191, 216), 'violet': (238, 130, 238), 'navy': (0, 0, 128), 'orchid': (218, 112, 214), 'blue': (0, 0, 255), 'ghostwhite': (248, 248, 255), 'honeydew': (240, 255, 240), 
        'purple': (128, 0, 128), 'dark red': (139, 0, 0), 'pale violet red': (219, 112, 147), 'red': (255, 0, 0), 'bisque': (255, 228, 196), 'dim gray': (105, 105, 105), 'wheat': (245, 222, 179), 'corn silk': (255, 248, 220), 
        'royal blue': (65, 105, 225), 'golden rod': (218, 165, 32), 'gainsboro': (220, 220, 220), 'lemon chiffon': (255, 250, 205), 'light salmon': (255, 160, 122), 'midnight blue': (25, 25, 112), 'alice blue': (240, 248, 255), 
        'plum': (221, 160, 221), 'rosy brown': (188, 143, 143), 'aqua': (0, 255, 255), 'dark khaki': (189, 183, 107), 'pale green': (152, 251, 152), 'beige': (245, 245, 220), 'azure': (240, 255, 255), 'dark salmon': (233, 150, 122), 
        'sienna': (160, 82, 45), 'dodger blue': (30, 144, 255), 'sandy brown': (250, 164, 96), 'blue violet': (138, 43, 226), 'lime': (0, 255, 0), 'burlywood': (222, 184, 135), 'seashell': (255, 245, 238), 'light pink': (255, 182, 193), 
        'fuchsia': (255, 0, 255), 'dark goldenrod': (184, 134, 11), 'dark blue': (0, 0, 139), 'light steel blue': (176, 196, 222), 'peru': (205, 133, 63), 'white': (255, 255, 255), 'medium sea green': (60, 179, 113), 'olive drab': (107, 142, 35), 
        'ivory': (255, 255, 240), 'indian red': (205, 92, 92), 'cornflower blue': (100, 149, 237), 'chocolate': (210, 105, 30), 'light coral': (240, 128, 128), 'orange': (255, 165, 0), 'olive': (128, 128, 0), 'moccasin': (255, 228, 181), 
        'medium blue': (0, 0, 205), 'dark slate blue': (72, 61, 139), 'dark orchid': (153, 50, 204), 'light cyan': (224, 255, 255), 'floral white': (255, 250, 240), 'light green': (144, 238, 144), 'dark cyan': (0, 139, 139), 
        'coral': (255, 127, 80), 'hot pink': (255, 105, 180), 'medium turquoise': (72, 209, 204), 'light goldenrod yellow': (250, 250, 210), 'maroon': (128, 0, 0), 'light sea green': (32, 178, 170), 'spring green': (0, 255, 127), 
        'light blue': (173, 216, 230), 'lime green': (50, 205, 50), 'saddle brown': (139, 69, 19), 'magenta': (255, 0, 255), 'dark magenta': (139, 0, 139), 'pink': (255, 192, 203), 'lawn green': (124, 252, 0), 'medium aquamarine': (102, 205, 170), 
        'mint cream': (245, 255, 250), 'dark turquoise': (0, 206, 209), 'snow': (255, 250, 250), 'papaya whip': (255, 239, 213), 'lavender blush': (255, 240, 245), 'medium orchid': (186, 85, 211), 'salmon': (250, 128, 114), 
        'medium purple': (147, 112, 219), 'antique white': (250, 235, 215), 'deep sky blue': (0, 191, 255), 'dark slate gray': (47, 79, 79), 'tan': (210, 180, 140), 'light gray': (211, 211, 211), 'tomato': (255, 99, 71), 
        'white smoke': (245, 245, 245), 'light skyblue': (135, 206, 250), 'linen': (250, 240, 230), 'green': (0, 128, 0), 'slate blue': (106, 90, 205), 'powder blue': (176, 224, 230), 'dark green': (0, 100, 0)}

    self.filename = " "
    

    #self.allcells = allcells
    #self.allcellnames = allcellnames

    #self.data.plen = len(self.points)
    #self.makenormalratemaps(8, range(-150,150,10), self.adjpts)
    #self.getdirofmov()

    objroot = BranchGroup()
    objroot.setCapability(BranchGroup.ALLOW_DETACH)
    objroot.setCapability(BranchGroup.ALLOW_CHILDREN_READ)
    objroot.setCapability(BranchGroup.ALLOW_CHILDREN_WRITE)


    white = Color3f(0.9, 0.9, 0.9)
    bounds = BoundingSphere(Point3d(), 100.0) 
    backg = Background(white)
    backg.setApplicationBounds(bounds)
    objroot.addChild(backg)

    self.maingroup = TransformGroup(Transform3D())
    self.maingroup.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE)
    self.maingroup.setCapability(TransformGroup.ALLOW_TRANSFORM_READ)
    self.maingroup.setCapability(TransformGroup.ALLOW_CHILDREN_EXTEND)
    self.maingroup.setCapability(TransformGroup.ALLOW_CHILDREN_WRITE)

    tt = Transform3D()
    tt.setTranslation(Vector3f(0.,0., 0.))
    self.wickedheadTG = TransformGroup(tt)
    self.wickedheadTG.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE)
    self.wickedheadTG.setCapability(TransformGroup.ALLOW_TRANSFORM_READ)
    self.wickedheadTG.setCapability(TransformGroup.ALLOW_CHILDREN_EXTEND)
    self.wickedheadTG.setCapability(TransformGroup.ALLOW_CHILDREN_WRITE)

    self.coordsysSwitch = Switch()
    self.coordsysSwitch.setCapability(Switch.ALLOW_SWITCH_WRITE)
    self.coordsysSwitch.setCapability(Switch.ALLOW_SWITCH_READ)
    self.coordsysSwitch.setCapability(Switch.ALLOW_CHILDREN_WRITE);
    self.coordsysSwitch.setCapability(Switch.ALLOW_CHILDREN_EXTEND);
    linebranchgroup = BranchGroup()
    linebranchgroup.addChild(self.coordsysSwitch)
    self.maingroup.addChild(linebranchgroup)
    self.coordsysSwitch.addChild(self.wickedheadTG)

    iqa = IndexedQuadArray(8, IndexedQuadArray.COORDINATES | IndexedQuadArray.NORMALS, 24)
    coords = []
    scl = 0.08
    coords.append( Point3d(1.0*scl, 0.25*scl, 0.375*scl) )
    coords.append( Point3d(-0.2*scl, 0.5*scl, 0.5*scl) )
    coords.append( Point3d(-0.2*scl, -0.5*scl, 0.5*scl) )
    coords.append( Point3d(1.0*scl, -0.25*scl, 0.375*scl) )
    coords.append( Point3d(1.0*scl, 0.25*scl, 0.125*scl) )
    coords.append( Point3d(-0.2*scl, 0.5*scl, 0) )
    coords.append( Point3d(-0.2*scl, -0.5*scl, 0) )
    coords.append( Point3d(1.0*scl, -0.25*scl, 0.125*scl) )
    coordinds = [ 0, 1, 2, 3, 7, 6, 5, 4, 0, 3, 7, 4, 5, 6, 2, 1, 0, 4, 5, 1, 6, 7, 3, 2 ]
    iqa.setCoordinates(0, coords)
    iqa.setCoordinateIndices(0, coordinds)
    normals = []
    normals.append(Vector3f(0.0, 0.0, 1.0))
    normals.append(Vector3f(0.0, 0.0, -1.0))
    normals.append(Vector3f(1.0, 0.0, 0.0))
    normals.append(Vector3f(-1.0, 0.0, 0.0))
    normals.append(Vector3f(0.0, 1.0, 0.0) )
    normals.append(Vector3f(0.0, -1.0, 0.0))
    iqa.setNormals(0, normals)
    normalIndices = [ 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5 ]
    iqa.setNormalIndices(0, normalIndices)
    ap = Appearance()
    mat = Material()

    mat.setAmbientColor( Color3f(1.0,0.0,0.0) )
    mat.setEmissiveColor( Color3f(0.0,0.0,0.0) )
    mat.setSpecularColor( Color3f(1.0,1.0,1.0) )
    mat.setDiffuseColor( Color3f(1.0,0.0,0.0) )
    mat.setShininess(20) #[0,128]
    ap.setMaterial(mat)
    #ap.setTransparencyAttributes(TransparencyAttributes(TransparencyAttributes.NONE, 0.)) 
    #self.wickedheadTG.addChild(Shape3D(iqa, ap))
    tt = Transform3D()
    xjump = 0.07
    zjump = 0.03
    tt.setTranslation(Vector3f(xjump, 0, zjump))
    ttgg = TransformGroup(tt)
    ttgg.addChild(Shape3D(iqa, ap))
    self.wickedheadTG.addChild(ttgg)

    tt = Transform3D()
    tt.setTranslation(Vector3f(0.1*scl+xjump, -0.3*scl, 0.5*scl+zjump))
    ttgg = TransformGroup(tt)
    ap = Appearance()
    ca = ColoringAttributes()
    ca.setColor(Color3f(0.5,0.5,0.1))
    ap.setColoringAttributes(ca)
    ttgg.addChild(Sphere(0.01, ap))
    self.wickedheadTG.addChild(ttgg)

    tt = Transform3D()
    tt.setTranslation(Vector3f(0.1*scl+xjump, 0.3*scl, 0.5*scl+zjump))
    ttgg = TransformGroup(tt)
    ap = Appearance()
    ca = ColoringAttributes()
    ca.setColor(Color3f(0.5,0.5,0.1))
    ap.setColoringAttributes(ca)
    ttgg.addChild(Sphere(0.01, ap))
    self.wickedheadTG.addChild(ttgg)

    tt = Transform3D()
    tt.setTranslation(Vector3f(1.02*scl+xjump, 0, 0.25*scl+zjump))
    ttgg = TransformGroup(tt)
    ap = Appearance()
    ca = ColoringAttributes()
    ca.setColor(Color3f(0.1,0.5,0.1))
    ap.setColoringAttributes(ca)
    ttgg.addChild(Sphere(0.01, ap))
    self.wickedheadTG.addChild(ttgg)

    ap = Appearance()
    ap.setCapability(Appearance.ALLOW_COLORING_ATTRIBUTES_READ)
    ap.setCapability(Appearance.ALLOW_COLORING_ATTRIBUTES_WRITE)
    ca = ColoringAttributes()
    ca.setCapability(ColoringAttributes.ALLOW_COLOR_READ)
    ca.setCapability(ColoringAttributes.ALLOW_COLOR_WRITE)
    ca.setColor(Color3f(0.,1.,0.))
    ap.setColoringAttributes(ca)
    self.wickedheadTG.addChild(Sphere(0.01, ap))

    self.pointsTGarray = []
    self.pointsSParray = []
    self.pointsSwitch = Switch()
    self.pointsSwitch.setCapability(Switch.ALLOW_SWITCH_WRITE)
    self.pointsSwitch.setCapability(Switch.ALLOW_SWITCH_READ)
    self.pointsSwitch.setCapability(Switch.ALLOW_CHILDREN_WRITE);
    self.pointsSwitch.setCapability(Switch.ALLOW_CHILDREN_EXTEND);
    pointsbranchgroup = BranchGroup() ### may not be necessary!!
    pointsbranchgroup.addChild(self.pointsSwitch)
    pointsbranchgroup.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE)
    self.maingroup.addChild(pointsbranchgroup)
    self.pointsSwitch.setWhichChild(Switch.CHILD_MASK)

    self.templatepointsTGarray = []
    self.templatepointsSParray = []
    self.templatepointsSwitch = Switch()
    self.templatepointsSwitch.setCapability(Switch.ALLOW_SWITCH_WRITE)
    self.templatepointsSwitch.setCapability(Switch.ALLOW_SWITCH_READ)
    self.templatepointsSwitch.setCapability(Switch.ALLOW_CHILDREN_WRITE);
    self.templatepointsSwitch.setCapability(Switch.ALLOW_CHILDREN_EXTEND);
    templatepointsbranchgroup = BranchGroup() ### may not be necessary!!
    templatepointsbranchgroup.addChild(self.templatepointsSwitch)
    templatepointsbranchgroup.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE)
    self.maingroup.addChild(templatepointsbranchgroup)
    self.templatepointsSwitch.setWhichChild(Switch.CHILD_MASK)
    tranny1 = Transform3D()
    tranny1.setTranslation(Vector3f(0.,0., 0.))
    self.boxtgroup = TransformGroup(tranny1)
    self.boxtgroup.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE)
    self.boxtgroup.setCapability(TransformGroup.ALLOW_TRANSFORM_READ)
    self.boxtgroup.setCapability(TransformGroup.ALLOW_CHILDREN_EXTEND)
    self.boxtgroup.setCapability(TransformGroup.ALLOW_CHILDREN_WRITE)

    tt = Transform3D()
    tt.setTranslation(Vector3f(0.,0., -0.1))
    self.boxtgroup.setTransform(tt)

    ap = Appearance()
    mat = Material()
    mat.setEmissiveColor( Color3f(0.5,0.55,0.55) )
    mat.setDiffuseColor( Color3f(0.3,0.3,0.3) )
    mat.setSpecularColor( Color3f(0,0,0.7) )
    mat.setShininess(50.) #[0,128]
    ap.setMaterial(mat)
    #ap.setColoringAttributes( ColoringAttributes (Color3f(0.1, 0.1, 1.0), ColoringAttributes.NICEST) ) ## NOTE NICEST MIGHT BE COOL
    self.superboxfloor = Box(0.5,0.5, 0.01, ap)
    self.superboxfloor.setCapability(Box.ENABLE_APPEARANCE_MODIFY);
    self.boxtgroup.addChild(self.superboxfloor)
    self.maingroup.addChild(self.boxtgroup)
    #objroot.addChild(tgroup1)

    objroot.addChild(self.maingroup)

    mr = MouseRotate(self.maingroup)
    mx = MouseZoom(self.maingroup)
    mt = MouseTranslate(self.maingroup)
    mr.setSchedulingBounds(bounds)
    mx.setSchedulingBounds(bounds)
    mt.setSchedulingBounds(bounds)
    objroot.addChild(mr)
    objroot.addChild(mx)
    objroot.addChild(mt)

    #lightD = DirectionalLight(Color3f(1,1,1), Vector3f(0,0,-1))
    #lightD.setInfluencingBounds(bounds)
    #objroot.addChild(lightD)

    objroot.compile()

    template = GraphicsConfigTemplate3D()
    template.setDoubleBuffer(GraphicsConfigTemplate3D.REQUIRED)
    env = GraphicsEnvironment.getLocalGraphicsEnvironment()
    dev = env.getDefaultScreenDevice()
    self.canvas3d = Canvas3D(dev.getBestConfiguration(template))
    self.canvas3d.setDoubleBufferEnable(True)

    #canvas3d = Canvas3D(SimpleUniverse.getPreferredConfiguration())
    self.canvas3d.setFocusable(True)
    self.canvas3d.setSize(1000,1000)
    self.su = SimpleUniverse(self.canvas3d)
    self.su.addBranchGraph(objroot)
    (self.su.getViewingPlatform()).setNominalViewingTransform()

    self.su.getViewer().getView().setFrontClipDistance(0.1)
    self.su.getViewer().getView().setBackClipDistance(100.)
    self.su.getViewer().getView().setFrontClipPolicy(View.VIRTUAL_EYE)
    self.su.getViewer().getView().setBackClipPolicy(View.VIRTUAL_EYE)
    self.su.getViewer().getView().setDepthBufferFreezeTransparent(True) 


    self.setLayout(GridBagLayout())
    c = GridBagConstraints()
    #c.anchor = GridBagConstraints.WEST
    c.insets = Insets(3, 3, 3, 3)
    c.gridx = 0
    c.gridy = 0
    c.fill = GridBagConstraints.BOTH
    c.gridwidth=9
    self.add(self.canvas3d, c)
    self.validate()

    pickcanvas = PickCanvas(self.canvas3d, pointsbranchgroup)
    pickcanvas.setMode(PickCanvas.BOUNDS)
    self.canvas3d.addMouseListener(pickguy(pickcanvas, self))

    c.gridy=2
    c.gridx = 0
    c.gridwidth=2
    c.fill = GridBagConstraints.NONE
    c.weightx = 0.9999999
    self.currtime = JLabel('Currently no tracking data')
    self.add(self.currtime, c)

    self.analysisstuffthingy = JDialog()
    self.analysisstuffthingy.setPreferredSize(Dimension(1700, 1000))
    self.datatable = analysistable()
    self.analysisstuffthingy.getContentPane().add(self.datatable)
    self.analysisstuffthingy.pack()
    self.analysisstuffthingy.setVisible(False)

    class jcombospeedupslistener(ItemListener):
      def __init__(self, parentguy):
        self.parentguy = parentguy
        self.oldone = 0
      def itemStateChanged(self, e):
        value = int(round(1./float(e.getSource().getSelectedItem())))
        self.parentguy.timer.setDelay(value)

    self.jcombospeedups = JComboBox(['0.001','0.01','0.05','0.1','0.5','1'])
    self.jcombospeedups.addItemListener(jcombospeedupslistener(self))
    c.gridwidth=1
    c.anchor = GridBagConstraints.LINE_END
    c.weightx = 0.0000000000001
    c.gridx = 5
    self.add(self.jcombospeedups, c)

    c.gridx = 6
    class jcomboskippieslistener(ItemListener):
      def __init__(self, parentguy):
        self.parentguy = parentguy
        self.oldone = 0
      def itemStateChanged(self, e):
        value = int(round(float(e.getSource().getSelectedItem())))
        self.parentguy.timeractionperformer.skippies = value

    self.jcomboskippies = JComboBox(['1','2','5','10','20','50','100','200'])
    self.jcomboskippies.addItemListener(jcomboskippieslistener(self))
    self.add(self.jcomboskippies, c)
    self.jcomboskippies.setEnabled(False)
    self.jcombospeedups.setEnabled(False)

    c.gridx = 7
    Abutton = JButton('A')
    class Abuttonlistener(ActionListener):
      def __init__(self, parentguy):
        self.parentguy = parentguy
      def actionPerformed(self, event):
        self.parentguy.analysisstuffthingy.setVisible(True)
    Abutton.addActionListener(Abuttonlistener(self))
    self.add(Abutton, c)

    self.data = crazydatafileio(self)
    self.openfilerthing = JDialog()

    self.openfilerthing.getContentPane().add(self.data)
    self.openfilerthing.pack()
    self.openfilerthing.setLocationRelativeTo(None)
    self.openfilerthing.setVisible(False)

    c.gridx = 8
    Fbutton = JButton('F')
    class Fbuttonlistener(ActionListener):
      def __init__(self, parentguy):
        self.parentguy = parentguy
      def actionPerformed(self, event):
        self.parentguy.openfilerthing.setVisible(True)
    Fbutton.addActionListener(Fbuttonlistener(self))
    self.add(Fbutton, c)

    c.gridx = 4
    self.funfilter = superfunfilter(self)
    self.funfilter.setVisible(False)
    class makefunlistener(ActionListener):
      def __init__(self, jguy):
        self.jguy = jguy
      def actionPerformed(self, event):
        self.jguy.funfilter.setVisible(True)
    self.jbutfun = JButton(':)')
    self.jbutfun.addActionListener(makefunlistener(self))
    self.add(self.jbutfun, c)
    self.jbutfun.setVisible(True)
    self.jbutfun.setEnabled(False)
    
    self.mysuperpointlabeler = superpointlabeler(self)
    self.settimepoint(1)

td = trackeddatastruct()
frame = JFrame("Data tracker thing")
#frame.getContentPane().add(JScrollPane(td))
frame.getContentPane().add(td)

class keyeventguy(KeyEventDispatcher):
  def dispatchKeyEvent(self, e):
    if(self.parentguy.timer == None):
      return
    if(e.getKeyCode() == KeyEvent.VK_DOWN):
      if(e.getID() == KeyEvent.KEY_PRESSED):
        if(self.stepsize==5):
          self.stepsize = 2
        elif(self.stepsize==2):
          self.stepsize = 1
        elif(self.stepsize==10):
          self.stepsize = 5
        elif(self.stepsize==500):
          self.stepsize = 100
        elif(self.stepsize==100):
          self.stepsize = 10
    elif(e.getKeyCode() == KeyEvent.VK_UP):
      if(e.getID() == KeyEvent.KEY_PRESSED):
        if(self.stepsize==5):
          self.stepsize = 10
        elif(self.stepsize==1):
          self.stepsize = 2
        elif(self.stepsize==2):
          self.stepsize = 5
        elif(self.stepsize==10):
          self.stepsize = 100
        elif(self.stepsize==100):
          self.stepsize = 500
    elif(e.getKeyCode() == KeyEvent.VK_LEFT):
      if(e.getID() == KeyEvent.KEY_PRESSED):
        if(self.parentguy.data.plen>5):
          val = self.parentguy.jslider.getValue()
          if(val-self.stepsize>-1):
            self.parentguy.jslider.setValue(val-self.stepsize)
    elif(e.getKeyCode() == KeyEvent.VK_RIGHT):
      if(e.getID() == KeyEvent.KEY_PRESSED):
        if(self.parentguy.data.plen>5):
          val = self.parentguy.jslider.getValue()
          if(val+self.stepsize<self.parentguy.data.plen):
            self.parentguy.jslider.setValue(val+self.stepsize)
  def __init__(self, parentguy):
    self.parentguy = parentguy
    self.stepsize = 1

keything = keyeventguy(td)
KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(keything)

class windowthing(WindowAdapter):
  def windowClosing(self, e):
    KeyboardFocusManager.getCurrentKeyboardFocusManager().removeKeyEventDispatcher(self.keything) 
    self.td.AudioSystemGuy.close()
    self.td.AudioClip.close()
    self.td.su.cleanup()
    self.td.su = None
    e.getSource().dispose()
    self.td = 0.

  def __init__(self, keything, td):
    self.keything = keything
    self.td = td
    

frame.addWindowListener(windowthing(keything, td))

frame.pack()
frame.setVisible(True)


