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

    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 "GenericEditor.h"

#include "../Parameter/ParameterEditor.h"
#include "ChannelSelector.h"
#include "../ProcessorGraph/ProcessorGraph.h"
#include "../RecordNode/RecordNode.h"
#include "../../UI/ProcessorList.h"
#include "../../AccessClass.h"
#include "../../UI/EditorViewport.h"

#include <math.h>

#ifndef M_PI
#define M_PI 3.14159265359
#endif
GenericEditor::GenericEditor(GenericProcessor* owner, bool useDefaultParameterEditors=true)
    : AudioProcessorEditor(owner),
      desiredWidth(150), isFading(false), accumulator(0.0), acquisitionIsActive(false),
      drawerButton(0), drawerWidth(170),
      drawerOpen(false), channelSelector(0), isSelected(false), isEnabled(true), isCollapsed(false), tNum(-1)
{
    constructorInitialize(owner, useDefaultParameterEditors);
}


/*GenericEditor::GenericEditor (GenericProcessor* owner)
: AudioProcessorEditor (owner), isSelected(false),
desiredWidth(150), tNum(-1), isEnabled(true),
accumulator(0.0), isFading(false), drawerButton(0),
channelSelector(0)

{
    bool useDefaultParameterEditors=true;
    constructorInitialize(owner, useDefaultParameterEditors);
}
*/
GenericEditor::~GenericEditor()
{
    deleteAllChildren();
}

void GenericEditor::constructorInitialize(GenericProcessor* owner, bool useDefaultParameterEditors)
{

    name = getAudioProcessor()->getName();
    displayName = name;

    nodeId = owner->getNodeId();

    //MemoryInputStream mis(BinaryData::silkscreenserialized, BinaryData::silkscreenserializedSize, false);
    //Typeface::Ptr typeface = new CustomTypeface(mis);
    titleFont = Font ("Default", 14, Font::bold);

    if (!owner->isMerger() && !owner->isSplitter() && !owner->isUtility())
    {
        // std::cout << "Adding drawer button." << std::endl;

        drawerButton = new DrawerButton("name");
        drawerButton->addListener(this);
        addAndMakeVisible(drawerButton);

        if (!owner->isSink())
        {
            channelSelector = new ChannelSelector (true, titleFont);
        }
        else
        {
            channelSelector = new ChannelSelector (false, titleFont);
        }

        addChildComponent(channelSelector);
        channelSelector->setVisible(false);

        isSplitOrMerge=false;
    }
    else
    {
        isSplitOrMerge=true;
    }

    backgroundGradient = ColourGradient(Colour(190, 190, 190), 0.0f, 0.0f,
                                        Colour(185, 185, 185), 0.0f, 120.0f, false);
    backgroundGradient.addColour(0.2f, Colour(155, 155, 155));

    addParameterEditors(useDefaultParameterEditors);

    backgroundColor = Colour(10,10,10);

    //fadeIn();

}

void GenericEditor::updateName()
{
    nodeId = getProcessor()->getNodeId();
    repaint();
}

void GenericEditor::setDisplayName(const String& string)
{
    displayName = string;
    AccessClass::getGraphViewer()->updateNodeLocations();
    repaint();
}


String GenericEditor::getDisplayName()
{
    return displayName;
}


void GenericEditor::addParameterEditors(bool useDefaultParameterEditors=true)
{
    if (useDefaultParameterEditors)
    {
        const int xPosInitial = 2;
        const int yPosIntiial = 23;

        int xPos = 15;
        int yPos = 30;

        // std::cout << "Adding parameter editors." << std::endl;

        for (int i = 0; i < getProcessor()->getNumParameters(); i++)
        {
            ParameterEditor* p = new ParameterEditor(getProcessor(), getProcessor()->getParameterObject (i), titleFont);
            p->setChannelSelector (channelSelector);

            if (p->hasCustomBounds())
            {
                p->setBounds (p->getDesiredBounds().translated (xPosInitial, yPosIntiial));
            }
            else
            {
                const int dWidth  = p->desiredWidth;
                const int dHeight = p->desiredHeight;

                p->setBounds (xPos, yPos, dWidth, dHeight);

                yPos += dHeight;
                yPos += 10;
            }

            addAndMakeVisible (p);
            parameterEditors.add (p);
        }
    }
}




void GenericEditor::refreshColors()
{

    //std::cout << getName() << " refreshing colors." << std::endl;

    enum
    {
        PROCESSOR_COLOR = 801,
        FILTER_COLOR = 802,
        SINK_COLOR = 803,
        SOURCE_COLOR = 804,
        UTILITY_COLOR = 805,
    };

    if (getProcessor()->isSource())
        backgroundColor = AccessClass::getProcessorList()->findColour(SOURCE_COLOR);// Colour(255, 0, 0);//Colour(int(0.9*255.0f),int(0.019*255.0f),int(0.16*255.0f));
    else if (getProcessor()->isSink())
        backgroundColor = AccessClass::getProcessorList()->findColour(SINK_COLOR);//Colour(255, 149, 0);//Colour(int(0.06*255.0f),int(0.46*255.0f),int(0.9*255.0f));
    else if (getProcessor()->isSplitter() || getProcessor()->isMerger() || getProcessor()->isUtility())
        backgroundColor = AccessClass::getProcessorList()->findColour(UTILITY_COLOR);//Colour(40, 40, 40);//Colour(int(0.7*255.0f),int(0.7*255.0f),int(0.7*255.0f));
    else
        backgroundColor = AccessClass::getProcessorList()->findColour(FILTER_COLOR);//Colour(255, 89, 0);//Colour(int(1.0*255.0f),int(0.5*255.0f),int(0.0*255.0f));

    repaint();

}


void GenericEditor::resized()
{
    if (! isCollapsed)
    {
        if (drawerButton != 0)
            drawerButton->setBounds (getWidth() - 14, 40, 10, getHeight() - 60);

        if (channelSelector != 0)
            channelSelector->setBounds (desiredWidth - drawerWidth, 30, channelSelector->getDesiredWidth(), getHeight()-45);
    }
}


bool GenericEditor::keyPressed(const KeyPress& key)
{
    return false;
}

void GenericEditor::switchSelectedState()
{
    //std::cout << "Switching selected state" << std::endl;
    isSelected = !isSelected;
    repaint();
}

void GenericEditor::select()
{
    isSelected = true;
    repaint();
    //setWantsKeyboardFocus(true);
    //grabKeyboardFocus();

    editorWasClicked();
}

void GenericEditor::highlight()
{
    isSelected = true;
    repaint();
}

void GenericEditor::makeVisible()
{
    isSelected = true;
    repaint();
    AccessClass::getEditorViewport()->makeEditorVisible(this);
}

bool GenericEditor::getSelectionState()
{
    return isSelected;
}

void GenericEditor::deselect()
{
    isSelected = false;
    repaint();
    //setWantsKeyboardFocus(false);
}

void GenericEditor::enable()
{
    isEnabled = true;
    GenericProcessor* p = (GenericProcessor*) getProcessor();
    p->setEnabledState (true);
}

void GenericEditor::disable()
{
    isEnabled = false;
    GenericProcessor* p = (GenericProcessor*) getProcessor();
    p->setEnabledState (false);
}

bool GenericEditor::getEnabledState()
{
    GenericProcessor* p = (GenericProcessor*) getProcessor();
    return p->isEnabledState();
}

void GenericEditor::setEnabledState(bool t)
{
    GenericProcessor* p = (GenericProcessor*) getProcessor();
    p->setEnabledState(t);
    isEnabled = p->isEnabledState();
}

void GenericEditor::setDesiredWidth (int width)
{
    desiredWidth = width;
    repaint();
}

void GenericEditor::startRecording()
{
    if (channelSelector != 0)
        channelSelector->inactivateRecButtons();
}

void GenericEditor::stopRecording()
{
    if (channelSelector != 0)
        channelSelector->activateRecButtons();
}

void GenericEditor::startAcquisition()
{

    //std::cout << "GenericEditor received message to start acquisition." << std::endl;

    if (channelSelector != 0)
        channelSelector->startAcquisition();

    for (int n = 0; n < parameterEditors.size(); n++)
    {

        if (parameterEditors[n]->shouldDeactivateDuringAcquisition)
            parameterEditors[n]->setEnabled(false);

    }

    acquisitionIsActive = true;

}

void GenericEditor::stopAcquisition()
{
    if (channelSelector != 0)
        channelSelector->stopAcquisition();

    for (int n = 0; n < parameterEditors.size(); n++)
    {

        if (parameterEditors[n]->shouldDeactivateDuringAcquisition)
            parameterEditors[n]->setEnabled(true);

    }

    acquisitionIsActive = false;

}

void GenericEditor::fadeIn()
{
    isFading = true;
    startTimer(10);
}

void GenericEditor::paint(Graphics& g)
{
    int offset = 0;

    if (isEnabled)
        g.setColour (backgroundColor);
    else
        g.setColour (Colours::lightgrey);

    // draw colored background
    if (! isCollapsed)
    {
        g.fillRect (1, 1, getWidth() - (2 + offset), getHeight() - 2);
        // draw gray workspace
        g.setGradientFill (backgroundGradient);
        g.fillRect (1, 22, getWidth() - 2, getHeight() - 29);
    }
    else
    {
        g.fillAll();
    }

    g.setFont (titleFont);
    g.setFont (16);

    if (isEnabled)
    {
        g.setColour(Colours::white);
    }
    else
    {
        g.setColour(Colours::grey);
    }

    // draw title
    if (!isCollapsed)
    {
        // if (!getProcessor()->isMerger() && !getProcessor()->isSplitter())
        //      g.drawText(name+" ("+String(nodeId)+")", 6, 5, 500, 15, Justification::left, false);
        // else
        g.drawText (displayName.toUpperCase(), 10, 5, 500, 15, Justification::left, false);

    }
    else
    {
        g.addTransform(AffineTransform::rotation(-M_PI/2.0));
        g.drawText (displayName.toUpperCase(), - getHeight() + 6, 5, 500, 15, Justification::left, false);
        g.addTransform(AffineTransform::rotation(M_PI/2.0));
    }

    if (isSelected)
    {
        //g.setColour(Colours::yellow);
        //g.drawRect(0,0,getWidth(),getHeight(),1.0);
        g.setColour(Colours::yellow.withAlpha(0.5f));

    }
    else
    {
        g.setColour(Colours::black);
    }

    // draw highlight box
    g.drawRect(0,0,getWidth(),getHeight(),2.0);

    if (isFading)
    {
        g.setColour(Colours::black.withAlpha((float)(10.0-accumulator)/10.0f));
        if (getWidth() > 0 && getHeight() > 0)
            g.fillAll();
    }

}

void GenericEditor::timerCallback()
{
    accumulator++;

    repaint();

    if (accumulator > 10.0)
    {
        stopTimer();
        isFading = false;
    }
}

void GenericEditor::buttonClicked(Button* button)
{

    // std::cout << "Button clicked." << std::endl;

    checkDrawerButton(button);

    buttonEvent(button); // needed to inform subclasses of
    // button event
}


bool GenericEditor::checkDrawerButton(Button* button)
{
    if (button == drawerButton)
    {
        if (drawerButton->getToggleState())
        {

            channelSelector->setVisible(true);

            drawerWidth = channelSelector->getDesiredWidth() + 20;

            desiredWidth += drawerWidth;
            drawerOpen = true;

        }
        else
        {

            channelSelector->setVisible(false);

            desiredWidth -= drawerWidth;
            drawerOpen = false;
        }

        AccessClass::getEditorViewport()->makeEditorVisible(this);

        deselect();

        return true;
    }
    else
    {
        return false;
    }

}

void GenericEditor::sliderValueChanged(Slider* slider)
{
    sliderEvent(slider);
}

void GenericEditor::update()
{

    //std::cout << "Editor for ";

    GenericProcessor* p = (GenericProcessor*) getProcessor();

    // std::cout << p->getName() << " updating settings." << std::endl;

    int numChannels;

    if (channelSelector != 0)
    {
        if (!p->isSink())
            numChannels = p->getNumOutputs();
        else
            numChannels = p->getNumInputs();

        channelSelector->setNumChannels(numChannels);

        for (int i = 0; i < numChannels; i++)
        {
            // std::cout << p->channels[i]->getRecordState() << std::endl;
            channelSelector->setRecordStatus(i, p->channels[i]->getRecordState());
        }
    }

    if (numChannels == 0)
    {
        if (drawerButton != 0)
            drawerButton->setVisible(false);
    }
    else
    {
        if (drawerButton != 0)
            drawerButton->setVisible(true);
    }

    updateSettings();

    updateVisualizer(); // does nothing unless this method
    // has been implemented

}

Channel* GenericEditor::getChannel(int chan)
{
    return getProcessor()->channels[chan];

}

Channel* GenericEditor::getEventChannel(int chan)
{
    return getProcessor()->eventChannels[chan];
}

Array<int> GenericEditor::getActiveChannels()
{
    if (!isSplitOrMerge)
    {
        Array<int> a = channelSelector->getActiveChannels();
        return a;
    }
    else
    {
        Array<int> a;
        return a;
    }
}

bool GenericEditor::getRecordStatus(int chan)
{
    if (!isSplitOrMerge)
    {
        return channelSelector->getRecordStatus(chan);
    }
    else
    {
        return false;
    }
}

Array<bool> GenericEditor::getRecordStatusArray()
{

    Array<bool> recordStatuses;
    recordStatuses.resize(getProcessor()->getNumOutputs());

    for (int i = 0; i < getProcessor()->getNumOutputs(); i++)
    {
        if (channelSelector != nullptr)
            recordStatuses.set(i,channelSelector->getRecordStatus(i));
        else
            recordStatuses.set(i,false);
    }

    return recordStatuses;

}

bool GenericEditor::getAudioStatus(int chan)
{
    if (!isSplitOrMerge)
    {
        return channelSelector->getAudioStatus(chan);
    }
    else
    {
        return false;
    }
}

void GenericEditor::getChannelSelectionState(int chan, bool* p, bool* r, bool* a)
{
    if (!isSplitOrMerge)
    {
        *p = channelSelector->getParamStatus(chan);
        *r = channelSelector->getRecordStatus(chan);
        *a = channelSelector->getAudioStatus(chan);
    }
    else
    {
        *p = false;
        *r = false;
        *a = false;
    }
}

void GenericEditor::setChannelSelectionState(int chan, bool p, bool r, bool a)
{
    if (!isSplitOrMerge)
    {
        channelSelector->setParamStatus(chan+1, p);
        channelSelector->setRecordStatus(chan+1, r);
        channelSelector->setAudioStatus(chan+1, a);
    }
}

bool GenericEditor::getCollapsedState()
{
    return isCollapsed;
}

void GenericEditor::switchCollapsedState()
{

    if (!getProcessor()->isMerger() && !getProcessor()->isSplitter())
    {

        if (isCollapsed)
        {
            // open it up
            desiredWidth = originalWidth;
            isCollapsed = false;

        }
        else
        {
            originalWidth = desiredWidth;
            desiredWidth = 25;
            isCollapsed = true;
        }

        for (int i = 0; i < getNumChildComponents(); i++)
        {
            Component* c = getChildComponent(i);
            c->setVisible(!isCollapsed);
        }

        if (channelSelector != nullptr)
        {
            if (!drawerOpen)
                channelSelector->setVisible(false);
        }

        collapsedStateChanged();

        AccessClass::getEditorViewport()->refreshEditors();
    }
}

void GenericEditor::saveEditorParameters(XmlElement* xml)
{

    xml->setAttribute("isCollapsed", isCollapsed);
    xml->setAttribute("displayName", displayName);

    saveCustomParameters(xml);

}

void GenericEditor::loadEditorParameters(XmlElement* xml)
{

    bool isCollapsed = xml->getBoolAttribute("isCollapsed", false);

    if (isCollapsed)
    {
        switchCollapsedState();
    }

    displayName = xml->getStringAttribute("displayName", name);

    loadCustomParameters(xml);

}

GenericEditor* GenericEditor::getSourceEditor()
{

    GenericProcessor* sourceNode = getProcessor()->getSourceNode();

    if (sourceNode != nullptr)
        return sourceNode->getEditor();
    else
        return nullptr;
}

GenericEditor* GenericEditor::getDestEditor()
{
    GenericProcessor* destNode = getProcessor()->getDestNode();

    if (destNode != nullptr)
        return destNode->getEditor();
    else
        return nullptr;
}

bool GenericEditor::isSplitter()
{
    return getProcessor()->isSplitter();
}

bool GenericEditor::isMerger()
{
    return getProcessor()->isMerger();
}

bool GenericEditor::isUtility()
{
    return getProcessor()->isUtility();
}

void GenericEditor::buttonEvent(Button* button)
{

}


/////////////////////// BUTTONS ///////////////////////////////

DrawerButton::DrawerButton(const String& name) : Button(name)
{
    setClickingTogglesState(true);
}

DrawerButton::~DrawerButton()
{

}

void DrawerButton::paintButton(Graphics& g, bool isMouseOver, bool isButtonDown)
{
    if (isMouseOver)
        g.setColour(Colour(210,210,210));
    else
        g.setColour(Colour(110, 110, 110));

    g.drawVerticalLine(3, 0.0f, getHeight());
    g.drawVerticalLine(5, 0.0f, getHeight());
    g.drawVerticalLine(7, 0.0f, getHeight());

}

UtilityButton::UtilityButton(String label_, Font font_) :
    Button(label_), label(label_), font(font_)
{

    roundUL = true;
    roundUR = true;
    roundLL = true;
    roundLR = true;

    radius = 5.0f;

    font.setHeight(12.0f);

    setEnabledState(true);

}

UtilityButton::~UtilityButton()
{

}

bool UtilityButton::getEnabledState()
{
	return isEnabled;
}

void UtilityButton::setCorners(bool UL, bool UR, bool LL, bool LR)
{
    roundUL = UL;
    roundUR = UR;
    roundLL = LL;
    roundLR = LR;
}

void UtilityButton::setEnabledState(bool state)
{

    isEnabled = state;

    if (state)
    {
        selectedGrad = ColourGradient(Colour(240,179,12),0.0,0.0,
                                      Colour(207,160,33),0.0, 20.0f,
                                      false);
        selectedOverGrad = ColourGradient(Colour(209,162,33),0.0, 5.0f,
                                          Colour(190,150,25),0.0, 0.0f,
                                          false);
        neutralGrad = ColourGradient(Colour(220,220,220),0.0,0.0,
                                     Colour(170,170,170),0.0, 20.0f,
                                     false);
        neutralOverGrad = ColourGradient(Colour(180,180,180),0.0,5.0f,
                                         Colour(150,150,150),0.0, 0.0,
                                         false);
        fontColor = Colours::darkgrey;

    }
    else
    {

        selectedGrad = ColourGradient(Colour(240,240,240),0.0,0.0,
                                      Colour(200,200,200),0.0, 20.0f,
                                      false);
        selectedOverGrad = ColourGradient(Colour(240,240,240),0.0,0.0,
                                          Colour(200,200,200),0.0, 20.0f,
                                          false);
        neutralGrad = ColourGradient(Colour(240,240,240),0.0,0.0,
                                     Colour(200,200,200),0.0, 20.0f,
                                     false);
        neutralOverGrad = ColourGradient(Colour(240,240,240),0.0,0.0,
                                         Colour(200,200,200),0.0, 20.0f,
                                         false);
        fontColor = Colours::white;
    }

    repaint();
}

void UtilityButton::setRadius(float r)
{
    radius = r;
}

void UtilityButton::paintButton(Graphics& g, bool isMouseOver, bool isButtonDown)
{

    g.setColour(Colours::grey);
    g.fillPath(outlinePath);

    if (getToggleState())
    {
        if (isMouseOver)
            g.setGradientFill(selectedOverGrad);
        else
            g.setGradientFill(selectedGrad);
    }
    else
    {
        if (isMouseOver)
            g.setGradientFill(neutralOverGrad);
        else
            g.setGradientFill(neutralGrad);
    }

    AffineTransform a = AffineTransform::scale(0.98f, 0.94f, float(getWidth())/2.0f,
                                               float(getHeight())/2.0f);
    g.fillPath(outlinePath, a);


    //int stringWidth = font.getStringWidth(getName());

    g.setFont(font);

    g.setColour(fontColor);
    g.drawText(label,0,0,getWidth(),getHeight(),Justification::centred,true);

    //g.drawSingleLineText(getName(), getWidth()/2 - stringWidth/2, 12);

    // if (getToggleState() == true)
    //       g.setColour(Colours::orange);
    //   else
    //       g.setColour(Colours::darkgrey);

    //   if (isMouseOver)
    //       g.setColour(Colours::white);

    //   g.fillRect(0,0,getWidth(),getHeight());

    //   font.setHeight(10);
    //   g.setFont(font);
    //   g.setColour(Colours::black);

    //   g.drawRect(0,0,getWidth(),getHeight(),1.0);

    //g.drawText(getName(),0,0,getWidth(),getHeight(),Justification::centred,true);
    // if (isButtonDown)
    // {
    //     g.setColour(Colours::white);
    // }

    // int thickness = 1;
    // int offset = 3;

    // g.fillRect(getWidth()/2-thickness,
    //            offset,
    //            thickness*2,
    //            getHeight()-offset*2);

    // g.fillRect(offset,
    //            getHeight()/2-thickness,
    //            getWidth()-offset*2,
    //            thickness*2);
}

void UtilityButton::resized()
{

    outlinePath.clear();

    if (roundUL)
    {
        outlinePath.startNewSubPath(radius, 0);
    }
    else
    {
        outlinePath.startNewSubPath(0, 0);
    }

    if (roundUR)
    {
        outlinePath.lineTo(getWidth()-radius, 0);
        outlinePath.addArc(getWidth()-radius*2, 0, radius*2, radius*2, 0, 0.5*double_Pi);
    }
    else
    {
        outlinePath.lineTo(getWidth(), 0);
    }

    if (roundLR)
    {
        outlinePath.lineTo(getWidth(), getHeight()-radius);
        outlinePath.addArc(getWidth()-radius*2, getHeight()-radius*2, radius*2, radius*2, 0.5*double_Pi, double_Pi);
    }
    else
    {
        outlinePath.lineTo(getWidth(), getHeight());
    }

    if (roundLL)
    {
        outlinePath.lineTo(radius, getHeight());
        outlinePath.addArc(0, getHeight()-radius*2, radius*2, radius*2, double_Pi, 1.5*double_Pi);
    }
    else
    {
        outlinePath.lineTo(0, getHeight());
    }

    if (roundUL)
    {
        outlinePath.lineTo(0, radius);
        outlinePath.addArc(0, 0, radius*2, radius*2, 1.5*double_Pi, 2.0*double_Pi);
    }

    outlinePath.closeSubPath();

}

String UtilityButton::getLabel()
{
    return label;
}

void UtilityButton::setLabel(String label_)
{
    label = label_;
    repaint();
}

TriangleButton::TriangleButton(int direction_) : Button("Arrow")
{
	direction = direction_;
}

TriangleButton::~TriangleButton()
{

}

void TriangleButton::paintButton(Graphics& g, bool isMouseOver, bool isButtonDown)
{

    //  g.fillAll(Colours::orange);
    // g.setColour(Colours::black);
    // g.drawRect(0,0,getWidth(),getHeight(),1.0);

    if (isMouseOver)
    {
        g.setColour(Colours::grey);
    }
    else
    {
        g.setColour(Colours::black);
    }

    if (isButtonDown)
    {
        g.setColour(Colours::white);
    }

    int inset = 1;
    int x1, y1, x2, y2, x3;

    x1 = inset;
    x2 = getWidth()/2;
    x3 = getWidth()-inset;

    if (direction == 1) // up
    {
        y1 = getHeight()-inset;
        y2 = inset;

    }
    else if (direction == 2) // down
    {
        y1 = inset;
        y2 = getHeight()-inset;
    }

    g.drawLine(x1, y1, x2, y2);
    g.drawLine(x2, y2, x3, y1);
    g.drawLine(x3, y1, x1, y1);


}

LoadButton::LoadButton() : ImageButton("Load")
{

    Image icon = ImageCache::getFromMemory(BinaryData::upload2_png,
                                           BinaryData::upload2_pngSize);

    setImages(false, // resizeButtonNowToFitThisImage
              true,  // rescaleImagesWhenButtonSizeChanges
              true,  // preserveImageProprotions
              icon,  // normalImage
              1.0,   // imageOpacityWhenNormal
              Colours::white, // overlayColourWhenNormal
              icon,  // overImage
              1.0,   // imageOpacityWhenOver
              Colours::yellow, // overlayColourWhenOver
              icon,  // downImage
              1.0,   // imageOpacityWhenDown
              Colours::yellow // overlayColourWhenDown
             );

}

LoadButton::~LoadButton()
{

}

SaveButton::SaveButton() : ImageButton("Save")
{
    Image icon = ImageCache::getFromMemory(BinaryData::floppy5_png,
                                           BinaryData::floppy5_pngSize);

    setImages(false, // resizeButtonNowToFitThisImage
              true,  // rescaleImagesWhenButtonSizeChanges
              true,  // preserveImageProprotions
              icon,  // normalImage
              1.0,   // imageOpacityWhenNormal
              Colours::white, // overlayColourWhenNormal
              icon,  // overImage
              1.0,   // imageOpacityWhenOver
              Colours::yellow, // overlayColourWhenOver
              icon,  // downImage
              1.0,   // imageOpacityWhenDown
              Colours::yellow // overlayColourWhenDown
             );
}

SaveButton::~SaveButton()
{

}


void GenericEditor::updateParameterButtons(int parameterIndex)
{
    if (parameterEditors.size() == 0)
    {
        //Checks if there is a parameter editor, and stops a bug if there isn't.
        //std::cout << "No parameterEditors" << std::endl;
    }
    else
    {
        if (parameterIndex == -1)
        {
            for (int i = 0; i < parameterEditors.size(); ++i)
            {
                parameterEditors[i]->updateChannelSelectionUI();
            }
        }
        else
        {
            parameterEditors[parameterIndex]->updateChannelSelectionUI();
        }
        //std::cout << "updateParameterButtons" << std::endl;
    }
}

String GenericEditor::getName()
{
    return name;
}

void GenericEditor::tabNumber(int t)
{
    tNum = t;
}

int GenericEditor::tabNumber()
{
    return tNum;
}

void GenericEditor::switchSource(int) { }

void GenericEditor::switchSource() { }

GenericProcessor* GenericEditor::getProcessor() const
{
    return (GenericProcessor*)getAudioProcessor();
}

void GenericEditor::switchDest() { }


void GenericEditor::switchIO(int) { }

int GenericEditor::getPathForEditor(GenericEditor* editor)
{
    return -1;
}

void GenericEditor::sliderEvent(Slider* slider) {}

void GenericEditor::editorWasClicked() {}

Colour GenericEditor::getBackgroundColor()
{
    return backgroundColor;
}

ColourGradient GenericEditor::getBackgroundGradient()
{
    return backgroundGradient;
}

void GenericEditor::updateSettings() {}

void GenericEditor::updateVisualizer() {}

void GenericEditor::channelChanged (int channel, bool newState) {}

void GenericEditor::saveCustomParameters(XmlElement* xml) { }

void GenericEditor::loadCustomParameters(XmlElement* xml) { }

void GenericEditor::collapsedStateChanged() {}

Array<GenericEditor*> GenericEditor::getConnectedEditors()
{
    Array<GenericEditor*> a;
    return a;
}


/***************************/
ColorButton::ColorButton(String label_, Font font_) :
    Button(label_), label(label_), font(font_)
{
    userDefinedData = -1;
    fontColor = juce::Colours::white;
    backgroundColor = juce::Colours::darkgrey;
    vert = false;
    setEnabledState(true);
    showEnabledStatus = false;
}

ColorButton::~ColorButton()
{

}

bool ColorButton::getEnabledState()
{
	return isEnabled;
}

void ColorButton::setShowEnabled(bool state)
{
    showEnabledStatus = state;
    repaint();
}

void ColorButton::setEnabledState(bool state)
{

    isEnabled = state;

    repaint();
}

void ColorButton::setUserDefinedData(int d)
{
    userDefinedData = d;
}
int ColorButton::getUserDefinedData()
{
    return userDefinedData;
}

void ColorButton::setVerticalOrientation(bool state)
{
    vert = state;
    repaint();
}

void ColorButton::paintButton(Graphics& g, bool isMouseOver, bool isButtonDown)
{

    if (isEnabled)
    {
        g.fillAll(backgroundColor);
    }
    else
    {
        int fac = 3;
        g.fillAll(Colour::fromRGB(backgroundColor.getRed() / fac, backgroundColor.getGreen() / fac, backgroundColor.getBlue() / fac));
    }


    /*
    if (getToggleState())
    {
    if (isMouseOver)
    g.setGradientFill(selectedOverGrad);
    else
    g.setGradientFill(selectedGrad);
    }
    else
    {
    if (isMouseOver)
    g.setGradientFill(neutralOverGrad);
    else
    g.setGradientFill(neutralGrad);
    }
    */

    if (isMouseOver)
    {
        g.setColour(Colours::white);
        g.drawRect(0, 0, getWidth(), getHeight());
    }

    g.setFont(font);
    g.setColour(fontColor);

    if (vert)
    {
        g.addTransform(AffineTransform::rotation(-M_PI / 2.0));
        g.drawText(label, 0, -getHeight(), getHeight(), getWidth(), Justification::left, false);
        g.addTransform(AffineTransform::rotation(M_PI / 2.0));
    }
    else
    {
        if (showEnabledStatus)
        {
            if (isEnabled)
                g.drawText("[+] " + label, 0, 0, getWidth(), getHeight(), Justification::left, true);
            else
                g.drawText("[-] " + label, 0, 0, getWidth(), getHeight(), Justification::left, true);
        }
        else
            g.drawText(label, 0, 0, getWidth(), getHeight(), Justification::centred, true);

    }

}


String ColorButton::getLabel()
{
    return label;
}

void ColorButton::setColors(Colour foreground, Colour background)
{
    fontColor = foreground;
    backgroundColor = background;
}

void ColorButton::setLabel(String label_)
{
    label = label_;
    repaint();
}


ThresholdSlider::ThresholdSlider(Font f) : Slider("name"), font(f)
{

	setSliderStyle(Slider::Rotary);
	setRange(-400, 400.0f, 10.0f);
	setValue(-20.0f);
	setTextBoxStyle(Slider::NoTextBox, false, 40, 20);

}

ThresholdSlider::~ThresholdSlider()
{

}

void ThresholdSlider::paint(Graphics& g)
{

	ColourGradient grad = ColourGradient(Colour(40, 40, 40), 0.0f, 0.0f,
		Colour(80, 80, 80), 0.0, 40.0f, false);

	Path p;
	p.addPieSegment(3, 3, getWidth() - 6, getHeight() - 6, 5 * double_Pi / 4 - 0.2, 5 * double_Pi / 4 + 3 * double_Pi / 2 + 0.2, 0.5);

	g.setGradientFill(grad);
	g.fillPath(p);

	String valueString;

	if (isActive)
	{
		p = makeRotaryPath(getMinimum(), getMaximum(), getValue());
		g.setColour(Colour(240, 179, 12));
		g.fillPath(p);

		valueString = String((int)getValue());
	}
	else
	{

		valueString = "";

		for (int i = 0; i < valueArray.size(); i++)
		{
			p = makeRotaryPath(getMinimum(), getMaximum(), valueArray[i]);
			g.setColour(Colours::lightgrey.withAlpha(0.4f));
			g.fillPath(p);
			valueString = String((int)valueArray.getLast());
		}

	}

	font.setHeight(9.0);
	g.setFont(font);
	int stringWidth = font.getStringWidth(valueString);

	g.setFont(font);

	g.setColour(Colours::darkgrey);
	g.drawSingleLineText(valueString, getWidth() / 2 - stringWidth / 2, getHeight() / 2 + 3);

}

Path ThresholdSlider::makeRotaryPath(double min, double max, double val)
{

	Path p;

	double start;
	double range;
	if (val > 0)
	{
		start = 0;
		range = (val) / (1.3*max)*double_Pi;
	}
	if (val < 0) {
		start = -(val) / (1.3*min)*double_Pi;
		range = 0;
	}
	p.addPieSegment(6, 6, getWidth() - 12, getHeight() - 12, start, range, 0.65);

	return p;

}

void ThresholdSlider::setActive(bool t)
{
	isActive = t;
	repaint();
}

void ThresholdSlider::setValues(Array<double> v)
{
	valueArray = v;
}