/*
    ------------------------------------------------------------------

    This file is part of the Open Ephys GUI
    Copyright (C) 2013 Open Ephys

    ------------------------------------------------------------------

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

*/

#include "SpikeSorterEditor.h"
#include "SpikeSorterCanvas.h"
#include "SpikeSorter.h"

#include <stdio.h>



SpikeSorterEditor::SpikeSorterEditor(GenericProcessor* parentNode, bool useDefaultParameterEditors=true)
    : VisualizerEditor(parentNode, 300, useDefaultParameterEditors), spikeSorterCanvas(nullptr), isPlural(true)

{
    tabText = "Spike Detector";

	int silksize;
	const char* silk = CoreServices::getApplicationResource("silkscreenserialized", silksize);
    MemoryInputStream mis(silk, silksize, false);
    Typeface::Ptr typeface = new CustomTypeface(mis);
    font = Font(typeface);

    desiredWidth = 300;

    //SpikeSorter* processor = (SpikeSorter*) getProcessor();

    advancerList = new ComboBox("Advancers");
    advancerList->addListener(this);
    advancerList->setBounds(10,95,130,20);
    addAndMakeVisible(advancerList);

    depthOffsetLabel = new Label("Depth Offset","Depth Offset");
    depthOffsetLabel->setFont(Font("Default", 10, Font::plain));
    depthOffsetLabel->setEditable(false);
    depthOffsetLabel->setBounds(125,115,80,20);
    depthOffsetLabel->setColour(Label::textColourId, Colours::grey);
    addAndMakeVisible(depthOffsetLabel);

    advancerLabel = new Label("Depth Offset","ADVANCER:");
    advancerLabel->setFont(Font("Default", 10, Font::plain));
    advancerLabel->setEditable(false);
    advancerLabel->setBounds(10,80,80,20);
    advancerLabel->setColour(Label::textColourId, Colours::grey);
    addAndMakeVisible(advancerLabel);

    depthOffsetEdit = new Label("Depth Offset","0.0");
    depthOffsetEdit->setFont(Font("Default", 10, Font::plain));
    depthOffsetEdit->setEditable(true);
    depthOffsetEdit->setBounds(145,95,40,20);
    depthOffsetEdit->addListener(this);
    depthOffsetEdit->setColour(Label::textColourId, Colours::white);
    depthOffsetEdit->setColour(Label::backgroundColourId, Colours::grey);

    addAndMakeVisible(depthOffsetEdit);

    electrodeList = new ComboBox("Electrode List");
    electrodeList->setEditableText(false);
    electrodeList->setJustificationType(Justification::centredLeft);
    electrodeList->addListener(this);
    electrodeList->setBounds(65,30,130,20);
    addAndMakeVisible(electrodeList);

    numElectrodes = new Label("Number of Electrodes","1");
    numElectrodes->setEditable(true);
    numElectrodes->addListener(this);
    numElectrodes->setBounds(30,30,25,20);
    addAndMakeVisible(numElectrodes);

    upButton = new TriangleButton(1);
    upButton->addListener(this);
    upButton->setBounds(50,30,10,8);
    addAndMakeVisible(upButton);

    downButton = new TriangleButton(2);
    downButton->addListener(this);
    downButton->setBounds(50,40,10,8);
    addAndMakeVisible(downButton);

    plusButton = new UtilityButton("+", titleFont);
    plusButton->addListener(this);
    plusButton->setRadius(3.0f);
    plusButton->setBounds(15,27,14,14);
    addAndMakeVisible(plusButton);

    audioMonitorButton = new UtilityButton("MONITOR", Font("Default", 12, Font::plain));
    audioMonitorButton->addListener(this);
    audioMonitorButton->setRadius(3.0f);
    audioMonitorButton->setBounds(80,65,65,15);
    audioMonitorButton->setClickingTogglesState(true);
    addAndMakeVisible(audioMonitorButton);

    removeElectrodeButton = new UtilityButton("-",font);
    removeElectrodeButton->addListener(this);
    removeElectrodeButton->setBounds(15,45,14,14);
    addAndMakeVisible(removeElectrodeButton);


    configButton = new UtilityButton("CONFIG",Font("Default", 12, Font::plain));
    configButton->addListener(this);
    configButton->setBounds(10,65,60,15);
    addAndMakeVisible(configButton);

    thresholdSlider = new ThresholdSlider(font);
    thresholdSlider->setBounds(210,25,65,65);
    addAndMakeVisible(thresholdSlider);
    thresholdSlider->addListener(this);
    thresholdSlider->setActive(false);
    Array<double> v;
    thresholdSlider->setValues(v);

    thresholdLabel = new Label("Name","Threshold");
    font.setHeight(10);
    thresholdLabel->setFont(font);
    thresholdLabel->setBounds(208, 85, 95, 15);
    thresholdLabel->setColour(Label::textColourId, Colours::grey);
    addAndMakeVisible(thresholdLabel);

    // create a custom channel selector
    deleteAndZero(channelSelector);

    channelSelector = new ChannelSelector(true, font);
    addChildComponent(channelSelector);
    channelSelector->setVisible(false);

    channelSelector->activateButtons();
    channelSelector->setRadioStatus(true);
    channelSelector->paramButtonsToggledByDefault(false);
    //	updateAdvancerList();

 /*   dacAssignmentLabel= new Label("DAC output","DAC output");
    dacAssignmentLabel->setFont(Font("Default", 10, Font::plain));
    dacAssignmentLabel->setEditable(false);
    dacAssignmentLabel->setBounds(210,115,80,20);
    dacAssignmentLabel->setColour(Label::textColourId, Colours::grey);
    addAndMakeVisible(dacAssignmentLabel);

    dacCombo = new ComboBox("DAC Assignment");
    dacCombo->addListener(this);
    dacCombo->setBounds(205,100,70,18);
    dacCombo->addItem("-",1);
    for (int k=0; k<8; k++)
    {
        dacCombo->addItem("DAC"+String(k+1),k+2);
    }
    dacCombo->setSelectedId(1);
    addAndMakeVisible(dacCombo);*/

}

Visualizer* SpikeSorterEditor::createNewCanvas()
{

    SpikeSorter* processor = (SpikeSorter*) getProcessor();
    spikeSorterCanvas = new SpikeSorterCanvas(processor);
    //ActionListener* listener = (ActionListener*) SpikeSorterCanvas;
    //getUIComponent()->registerAnimatedComponent(listener);
    return spikeSorterCanvas;
}


SpikeSorterEditor::~SpikeSorterEditor()
{

    for (int i = 0; i < electrodeButtons.size(); i++)
    {
        removeChildComponent(electrodeButtons[i]);
    }

}

void SpikeSorterEditor::sliderEvent(Slider* slider)
{
    int electrodeNum = -1;

    for (int i = 0; i < electrodeButtons.size(); i++)
    {
        if (electrodeButtons[i]->getToggleState())
        {
            electrodeNum = i;
            break;
        }
    }

    if (electrodeNum > -1)
    {
        SpikeSorter* processor = (SpikeSorter*) getProcessor();
        processor->setChannelThreshold(electrodeList->getSelectedItemIndex(),
                                       electrodeNum,
                                       slider->getValue());



     /*   //Array<int> dacChannels = processor->getDACassignments;
        int dacChannel = dacCombo->getSelectedId()-2;
        if (dacChannel >= 0)
        {
            // update dac threshold.
            processor->updateDACthreshold(dacChannel, slider->getValue());
        }*/

    }
    repaint();
    if (canvas!= nullptr)
        canvas->repaint();

}


void SpikeSorterEditor::buttonEvent(Button* button)
{
 
    SpikeSorter* processor = (SpikeSorter*) getProcessor();

    if (electrodeButtons.contains((ElectrodeButton*) button))
    {

        {
            for (int k=0; k<electrodeButtons.size(); k++)
            {
                if (electrodeButtons[k] != button)
                    electrodeButtons[k]->setToggleState(false,dontSendNotification);
            }
            if (electrodeButtons.size() == 1)
                electrodeButtons[0]->setToggleState(true,dontSendNotification);

            ElectrodeButton* eb = (ElectrodeButton*) button;
            int channelNum = eb->getChannelNum()-1;

            std::cout << "Channel number: " << channelNum << std::endl;
            Array<int> a;
            a.add(channelNum);
            channelSelector->setActiveChannels(a);

            SpikeSorter* processor = (SpikeSorter*) getProcessor();

            thresholdSlider->setActive(true);
            thresholdSlider->setValue(processor->getChannelThreshold(electrodeList->getSelectedItemIndex(),
                                                                     electrodeButtons.indexOf((ElectrodeButton*) button)));


        /*    if (processor->getAutoDacAssignmentStatus())
            {
                processor->assignDACtoChannel(0, channelNum);
                processor->assignDACtoChannel(1, channelNum);
            }
            Array<int> dacAssignmentToChannels = processor->getDACassignments();
            // search for channel[0]. If found, set the combo box accordingly...
            dacCombo->setSelectedId(1, sendNotification);
            for (int i=0; i<dacAssignmentToChannels.size(); i++)
            {
                if (dacAssignmentToChannels[i] == channelNum)
                {
                    dacCombo->setSelectedId(i+2, sendNotification);
                    break;
                }
            }*/

        }
    }


    int num = numElectrodes->getText().getIntValue();

    if (button == upButton)
    {
        numElectrodes->setText(String(++num), sendNotification);

        return;

    }
    else if (button == downButton)
    {

        if (num > 1)
            numElectrodes->setText(String(--num), sendNotification);

        return;

    }
    else if (button == configButton)
    {
        PopupMenu configMenu;
        PopupMenu waveSizeMenu;
        PopupMenu waveSizePreMenu;
        PopupMenu waveSizePostMenu;

        waveSizePreMenu.addItem(1,"8",true,processor->getNumPreSamples() == 8);
        waveSizePreMenu.addItem(2,"16",true,processor->getNumPreSamples() == 16);
        waveSizePostMenu.addItem(3,"32",true,processor->getNumPostSamples() == 32);
        waveSizePostMenu.addItem(4,"64",true,processor->getNumPostSamples() == 64);

        waveSizeMenu.addSubMenu("Pre samples",waveSizePreMenu);
        waveSizeMenu.addSubMenu("Post samples",waveSizePostMenu);
        waveSizeMenu.addItem(7,"Flip Signal",true,processor->getFlipSignalState());
        configMenu.addSubMenu("Waveform",waveSizeMenu,true);
        configMenu.addItem(5,"Current Channel => Audio",true,processor->getAutoDacAssignmentStatus());
        configMenu.addItem(6,"Threshold => All channels",true,processor->getThresholdSyncStatus());

        const int result = configMenu.show();
        switch (result)
        {
            case 1:
                processor->setNumPreSamples(8);
                break;
            case 2:
                processor->setNumPreSamples(16);
                break;
            case 3:
                processor->setNumPostSamples(32);
                break;
            case 4:
                processor->setNumPostSamples(64);
                break;
            case 5:
                processor->seteAutoDacAssignment(!processor->getAutoDacAssignmentStatus());
                refreshElectrodeList();
                break;
            case 6:
                processor->setThresholdSyncStatus(!processor->getThresholdSyncStatus());
                break;
            case 7:
                processor->setFlipSignalState(!processor->getFlipSignalState());
                break;
        }

    }
    else if (button == plusButton)
    {
        // std::cout << "Plus button pressed!" << std::endl;
        if (acquisitionIsActive)
        {
            CoreServices::sendStatusMessage("Stop acquisition before adding electrodes.");
            return;
        }

        //updateAdvancerList();
        PopupMenu probeMenu;
        probeMenu.addItem(1,"Single Electrode");
        probeMenu.addItem(2,"Stereotrode");
        probeMenu.addItem(3,"Tetrode");
        PopupMenu depthprobeMenu;
        depthprobeMenu.addItem(4,"8 ch, 125um");
        depthprobeMenu.addItem(5,"16 ch, 125um");
        depthprobeMenu.addItem(6,"24 ch, 125um");
        depthprobeMenu.addItem(7,"32 ch, 50um");
        depthprobeMenu.addItem(8,"32 ch, 25um");
        probeMenu.addSubMenu("Depth probe", depthprobeMenu,true);

        const int result = probeMenu.show();
        int nChansPerElectrode = 0;
        int nElectrodes = 0;
        double interelectrodeDistance = 0;
        double firstElectrodeOffset = 0;
        int numProbes = numElectrodes->getText().getIntValue();
        String ProbeType;

        switch (result)
        {
            case 0:
                return;
            case 1:
                ProbeType = "Single Electrode";
                nChansPerElectrode = 1;
                nElectrodes = 1;
                firstElectrodeOffset=0;
                break;
            case 2:
                ProbeType = "Stereotrode";
                nChansPerElectrode = 2;
                nElectrodes = 1;
                firstElectrodeOffset = 0;
                break;
            case 3:
                ProbeType = "Tetrode";
                nChansPerElectrode = 4;
                nElectrodes = 1;
                firstElectrodeOffset = 0;
                break;
            case 4:
                ProbeType = "Depth Probe";
                nChansPerElectrode = 1;
                nElectrodes = 8;
                interelectrodeDistance = 0.125;
                firstElectrodeOffset= -0.5;
                break;
            case 5:
                ProbeType = "Depth Probe";
                nChansPerElectrode = 1;
                nElectrodes = 16;
                interelectrodeDistance = 0.125;
                firstElectrodeOffset= -0.5;
                break;
            case 6:
                ProbeType = "Depth Probe";
                nChansPerElectrode = 1;
                nElectrodes = 24;
                interelectrodeDistance = 0.125;
                firstElectrodeOffset= -0.5;
                break;
            case 7:
                ProbeType = "Depth Probe";
                nChansPerElectrode = 1;
                nElectrodes = 32;
                interelectrodeDistance = 0.050;
                firstElectrodeOffset= -0.5;
                break;
            case 8:
                ProbeType = "Depth Probe";
                nChansPerElectrode = 1;
                nElectrodes = 32;
                interelectrodeDistance = 0.025;
                firstElectrodeOffset= -0.075;
                break;
        }

        processor->addProbes(ProbeType,numProbes, nElectrodes,nChansPerElectrode, firstElectrodeOffset,interelectrodeDistance);
        refreshElectrodeList();

        CoreServices::updateSignalChain(this);
        CoreServices::highlightEditor(this);

        return;

    }
    else if (button == removeElectrodeButton)   // DELETE
    {
        if (acquisitionIsActive)
        {
            CoreServices::sendStatusMessage("Stop acquisition before deleting electrodes.");
            return;
        }
        removeElectrode(electrodeList->getSelectedItemIndex());

        //getEditorViewport()->makeEditorVisible(this, true, true);

        return;
    }
    else if (button == audioMonitorButton)
    {

        channelSelector->clearAudio();

        SpikeSorter* processor = (SpikeSorter*) getProcessor();

        const OwnedArray<Electrode>& electrodes = processor->getElectrodes();
		int nElectrodes = electrodes.size();
		if (nElectrodes <= 0)
		{
			audioMonitorButton->setToggleState(false, dontSendNotification);
			return;
		}

        for (int i = 0; i < nElectrodes; i++)
        {
            Electrode* e = electrodes[i];
            e->isMonitored = false;
        }

        Electrode* e = processor->getActiveElectrode();
        e->isMonitored = audioMonitorButton->getToggleState();

        for (int i = 0; i < e->numChannels; i++)
        {
            int channelNum = e->channels[i];
            channelSelector->setAudioStatus(channelNum, audioMonitorButton->getToggleState());

        }

    }



}

void SpikeSorterEditor::setThresholdValue(int channel, double threshold)
{
    thresholdSlider->setActive(true);
    thresholdSlider->setValue(threshold);
    repaint();
}

void SpikeSorterEditor::channelChanged (int channel, bool newState)
{
    //std::cout << "New channel: " << chan << std::endl;
    if (channel <= 0)
        return;

    const int numElectrodeButtons = electrodeButtons.size();
    for (int i = 0; i < numElectrodeButtons; ++i)
    {
        if (electrodeButtons[i]->getToggleState())
        {
            electrodeButtons[i]->setChannelNum (channel);
            electrodeButtons[i]->repaint();

            Array<int> a;
            a.add (channel - 1);
            channelSelector->setActiveChannels (a);

            SpikeSorter* processor = (SpikeSorter*) getProcessor();
            processor->setChannel(electrodeList->getSelectedItemIndex(),
                                  i,
                                  channel - 1);

         /*   // if DAC is selected, update the mapping.
            int dacchannel = dacCombo->getSelectedId() - 2;
            if (dacchannel >=0)
            {
                processor->assignDACtoChannel (dacchannel, channel - 1);
            }
            if (processor->getAutoDacAssignmentStatus())
            {
                processor->assignDACtoChannel (0, channel - 1);
                processor->assignDACtoChannel (1, channel - 1);
                break;
            }*/
        }
    }
}

int SpikeSorterEditor::getSelectedElectrode()
{
    return electrodeList->getSelectedId();
}

void SpikeSorterEditor::setSelectedElectrode(int i)
{
    electrodeList->setSelectedId(i);
}

void SpikeSorterEditor::refreshElectrodeList(int selected)
{
    electrodeList->clear();

    SpikeSorter* processor = (SpikeSorter*) getProcessor();

    StringArray electrodeNames = processor->getElectrodeNames();

    for (int i = 0; i < electrodeNames.size(); i++)
    {
        electrodeList->addItem(electrodeNames[i], electrodeList->getNumItems()+1);
    }

    if (electrodeList->getNumItems() > 0)
    {
        if (selected == 0)
            selected = electrodeList->getNumItems();

        electrodeList->setSelectedId(selected);
        //        electrodeList->setText(electrodeList->getItemText(electrodeList->getNumItems()-1));
        lastId = electrodeList->getNumItems();
        electrodeList->setEditableText(true);

        drawElectrodeButtons(selected-1);
        Electrode* e = processor->getElectrode(selected - 1);

        int advancerIndex = 0;
        for (int k=0; k<advancerIDs.size(); k++)
        {
            if (advancerIDs[k] == e->advancerID)
            {
                advancerIndex = 1+k;
                break;
            }
        }

        advancerList->setSelectedId(advancerIndex);
        depthOffsetEdit->setText(String(e->depthOffsetMM,4),dontSendNotification);

        if (processor->getAutoDacAssignmentStatus())
        {
            processor->assignDACtoChannel(0, e->channels[0]);
            processor->assignDACtoChannel(1, e->channels[0]);
        }
     /*   Array<int> dacAssignmentToChannels = processor->getDACassignments();
        // search for channel[0]. If found, set the combo box accordingly...
        dacCombo->setSelectedId(1, sendNotification);
        for (int i=0; i<dacAssignmentToChannels.size(); i++)
        {
            if (dacAssignmentToChannels[i] == e->channels[0])
            {
                dacCombo->setSelectedId(i+2, sendNotification);
                processor->updateDACthreshold(i+2, e->thresholds[0]);
                break;
            }
        }*/




    }
    if (spikeSorterCanvas != nullptr)
        spikeSorterCanvas->update();
}


void SpikeSorterEditor::removeElectrode(int index)
{
    std::cout << "Deleting electrode number " << index << std::endl;
    SpikeSorter* processor = (SpikeSorter*) getProcessor();
    processor->removeElectrode(index);
    refreshElectrodeList();

    int newIndex = jmin(index, electrodeList->getNumItems()-1);
    newIndex = jmax(newIndex, 0);

    electrodeList->setSelectedId(newIndex, sendNotification);
    electrodeList->setText(electrodeList->getItemText(newIndex));

    if (electrodeList->getNumItems() == 0)
    {
        electrodeButtons.clear();
        electrodeList->setEditableText(false);
    }
}

void SpikeSorterEditor::labelTextChanged(Label* label)
{
    if (label == depthOffsetEdit)
    {
        // update electrode depth offset.
        //Value v = depthOffsetEdit->getTextValue();
        //double offset = v.getValue();

        //int electrodeIndex = electrodeList->getSelectedId()-1;
        //SpikeSorter* processor = (SpikeSorter*) getProcessor();
        //if (electrodeIndex >= 0)
        //	processor->setElectrodeAdvancerOffset(electrodeIndex, offset);

        if (spikeSorterCanvas != nullptr)
            spikeSorterCanvas->update();

    }
}

void SpikeSorterEditor::setElectrodeComboBox(int direction)
{
    int N = electrodeList->getNumItems();
    int C = electrodeList->getSelectedId();
    C+=direction;
    if (C <= 0)
        C = N;
    if (C > N)
        C = 1;
    electrodeList->setSelectedId(C, sendNotification);
}

void SpikeSorterEditor::comboBoxChanged(ComboBox* comboBox)
{
    SpikeSorter* processor = (SpikeSorter*) getProcessor();

   /* if (comboBox == dacCombo)
    {
        int selection = dacCombo->getSelectedId();
        // modify the dac channel assignment...
        if (selection > 1)
        {
            int selectedSubChannel = -1;
            for (int i = 0; i < electrodeButtons.size(); i++)
            {
                if (electrodeButtons[i]->getToggleState())
                {
                    selectedSubChannel = i;
                    break;
                }
            }
            Electrode* e = processor->getActiveElectrode();
            if (e != nullptr)
            {
                int dacchannel = selection-2;
                processor->assignDACtoChannel(dacchannel, e->channels[selectedSubChannel]);
            }
        }

    }
    else*/ if (comboBox == electrodeList)
    {
        int ID = comboBox->getSelectedId();

        if (ID == 0)
        {
            // modify electrode name
            processor->setElectrodeName(lastId, comboBox->getText());
            refreshElectrodeList();

        }
        else
        {
            // switch to a new electrode.
            SpikeSorter* processor = (SpikeSorter*) getProcessor();
            lastId = ID;
            Electrode* e= processor->setCurrentElectrodeIndex(ID-1);
            drawElectrodeButtons(ID-1);
            int advancerIndex = 0;

            audioMonitorButton->setToggleState(e->isMonitored, dontSendNotification);

            for (int k=0; k<advancerIDs.size(); k++)
            {
                if (advancerIDs[k] == e->advancerID)
                {
                    advancerIndex = 1+k;
                    break;
                }
            }
            advancerList->setSelectedId(advancerIndex, dontSendNotification);
            depthOffsetEdit->setText(String(e->depthOffsetMM,4),dontSendNotification);

            if (processor->getAutoDacAssignmentStatus())
            {
                processor->assignDACtoChannel(0, e->channels[0]);
                processor->assignDACtoChannel(1, e->channels[0]);
            }
         /*   Array<int> dacAssignmentToChannels = processor->getDACassignments();
            // search for channel[0]. If found, set the combo box accordingly...
            dacCombo->setSelectedId(1, sendNotification);
            for (int i=0; i<dacAssignmentToChannels.size(); i++)
            {
                if (dacAssignmentToChannels[i] == e->channels[0])
                {
                    dacCombo->setSelectedId(i+2, sendNotification);
                    break;
                }
            }*/

        }



    }
    else if (comboBox == advancerList)
    {
        // attach advancer to electrode.
        // int electrodeIndex = electrodeList->getSelectedId()-1;
        // SpikeSorter* processor = (SpikeSorter*) getProcessor();
        // int selectedAdvancer = advancerList->getSelectedId() ;
        // if (electrodeIndex >= 0 && selectedAdvancer > 0)
        // 	processor->setElectrodeAdvancer(electrodeIndex,advancerIDs[advancerList->getSelectedId()-1]);
        // else
        // 	advancerList->setSelectedId(0,dontSendNotification);
    }

}

void SpikeSorterEditor::checkSettings()
{
    electrodeList->setSelectedItemIndex(0);
}

void SpikeSorterEditor::drawElectrodeButtons(int ID)
{

    SpikeSorter* processor = (SpikeSorter*) getProcessor();

    electrodeButtons.clear();

    int width = 20;
    int height = 15;

    int numChannels = processor->getNumChannels(ID);
    int row = 0;
    int column = 0;

    Array<int> activeChannels;
    Array<double> thresholds;

    for (int i = 0; i < numChannels; i++)
    {
        ElectrodeButton* button = new ElectrodeButton(processor->getChannel(ID,i)+1);
        electrodeButtons.add(button);

        if (i == 0)
        {
            activeChannels.add(processor->getChannel(ID,i));
            thresholds.add(processor->getChannelThreshold(ID,i));
        }

        button->setToggleState(i == 0, dontSendNotification);
        button->setBounds(155+(column++)*width, 60+row*height, width, 15);
        addAndMakeVisible(button);
        button->addListener(this);

        if (column % 2 == 0)
        {
            column = 0;
            row++;
        }

    }

    channelSelector->setActiveChannels(activeChannels);

    thresholdSlider->setValues(thresholds);
    thresholdSlider->setActive(true);
    thresholdSlider->setEnabled(true);
    thresholdSlider->setValue(processor->getChannelThreshold(ID,0),dontSendNotification);
    repaint();
    if (spikeSorterCanvas != nullptr)
        spikeSorterCanvas->update();
}


// void SpikeSorterEditor::updateAdvancerList()
// {

// 	ProcessorGraph *g = getProcessor()->getProcessorGraph();
// 	Array<GenericProcessor*> p = g->getListOfProcessors();
// 	for (int k=0;k<p.size();k++)
// 	{
// 		if (p[k]->getName() == "Advancers")
// 		{
// 			AdvancerNode *node = (AdvancerNode *)p[k];
// 			if (node != nullptr)
// 			{
// 				advancerNames = node->getAdvancerNames();
// 				advancerIDs =  node->getAdvancerIDs();

// 				advancerList->clear(dontSendNotification);
// 				for (int i=0;i<advancerNames.size();i++)
// 				{
// 					advancerList->addItem(advancerNames[i],1+i);
// 				}
// 			}
// 		}
// 	}


//         int selectedElectrode = electrodeList->getSelectedId();
// 		if (selectedElectrode > 0) {
// 			SpikeSorter* processor = (SpikeSorter*) getProcessor();
// 			Electrode *e = processor->getElectrode( selectedElectrode-1);
// 			int advancerIndex = 0;
// 			for (int k=0;k<advancerIDs.size();k++)
// 			{
// 				if (advancerIDs[k] == e->advancerID)
// 				{
// 						advancerIndex = 1+k;
// 					break;
// 				}
// 			}
// 			advancerList->setSelectedId(advancerIndex);
// 			}
// 	repaint();
// }