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

    This file is part of the Open Ephys GUI
    Copyright (C) 2024 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 "SpikeDisplayNode.h"

#include "SpikeDisplayEditor.h"
#include "SpikePlots.h"

#include <stdio.h>

SpikeDisplayNode::SpikeDisplayNode()
    : GenericProcessor ("Spike Viewer"),
      displayBufferSize (5),
      redrawRequested (false)
{
}

AudioProcessorEditor* SpikeDisplayNode::createEditor()
{
    editor = std::make_unique<SpikeDisplayEditor> (this);
    return editor.get();
}

void SpikeDisplayNode::updateSettings()
{
    electrodes.clear();
    electrodeMap.clear();

    for (auto spikeChannel : spikeChannels)
    {
        if (spikeChannel->isValid())
        {
            Electrode* elec = new Electrode();
            elec->numChannels = spikeChannel->getNumChannels();
            elec->name = spikeChannel->getName();
            elec->spikeChannel = spikeChannel;

            electrodes.add (elec);
        }
    }
}

bool SpikeDisplayNode::startAcquisition()
{
    SpikeDisplayEditor* editor = (SpikeDisplayEditor*) getEditor();

    for (int i = 0; i < spikeChannels.size(); i++)
    {
        Electrode* elec = electrodes[i];
    }

    if (! headlessMode)
        editor->enable();

    totalCallbacks = 0;
    spikeCount = 0;

    return true;
}

bool SpikeDisplayNode::stopAcquisition()
{
    SpikeDisplayEditor* editor = (SpikeDisplayEditor*) getEditor();

    if (! headlessMode)
        editor->disable();

    return true;
}

void SpikeDisplayNode::setParameter (int param, float val)
{
    if (param == 10)
    {
        String msg = "AUDIO SELECT ";
        
        if (val >= 0 && val < spikeChannels.size())
        {
            SpikeChannel* chan = spikeChannels[int (val)];

            msg += String (chan->getStreamId()) + " ";

            for (auto ch : chan->localChannelIndexes)
            {
                msg += String (ch + 1) + " ";
            }

        }
        else
        {
            msg += "NONE";
        }

        //std::cout << "MESSAGE: " << msg << std::endl;
        broadcastMessage (msg);
        
    }
}

int SpikeDisplayNode::getNumberOfChannelsForElectrode (int i) const
{
    if (i > -1 && i < electrodes.size())
    {
        return electrodes[i]->numChannels;
    }
    else
    {
        return 0;
    }
}

Array<String> SpikeDisplayNode::getChannelNamesForElectrode (int i) const
{
    
    Array<String> channelNames;
    
    if (i > -1 && i < electrodes.size())
    {
        for (int j = 0; j < electrodes[i]->numChannels; j++)
        {
            channelNames.add(electrodes[i]->spikeChannel->getSourceChannels()[j]->getName());
        }
    }

    return channelNames;
    
}

String SpikeDisplayNode::getNameForElectrode (int i) const
{
    if (i > -1 && i < electrodes.size())
    {
        return electrodes[i]->name;
    }
    else
    {
        return " ";
    }
}

void SpikeDisplayNode::addSpikePlotForElectrode (SpikePlot* sp, int i)
{
    Electrode* electrode = electrodes[i];
    electrode->spikePlot = sp;

    electrodeMap[electrode->spikeChannel] = sp;
}

void SpikeDisplayNode::removeSpikePlots()
{
    for (int i = 0; i < getNumElectrodes(); ++i)
    {
        Electrode* e = electrodes[i];
        e->spikePlot = nullptr;
    }
}

int SpikeDisplayNode::getNumElectrodes() const
{
    return electrodes.size();
}

void SpikeDisplayNode::process (AudioBuffer<float>& buffer)
{
    checkForEvents (true); // automatically calls 'handleEvent()'

    totalCallbacks++;
}

void SpikeDisplayNode::handleSpike (SpikePtr spike)
{
    if (electrodeMap.count (spike->getChannelInfo()) > 0)
        electrodeMap.at (spike->getChannelInfo())->addSpikeToBuffer (spike);
}
