/*
 ==============================================================================
 This file is part of the IEM plug-in suite.
 Author: Daniel Rudrich
 Copyright (c) 2017 - Institute of Electronic Music and Acoustics (IEM)
 https://iem.at
 
 The IEM plug-in suite 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.
 
 The IEM plug-in suite 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 software.  If not, see <https://www.gnu.org/licenses/>.
 ==============================================================================
 */
#pragma once


//==============================================================================
/*
*/
class ReflectionsVisualizer    : public Component, private Timer
{
    const float mL = 23.0f;
    const float mR = 10.0f;
    const float mT = 7.0f;
    const float mB = 15.0f;
    
public:
    ReflectionsVisualizer()
    {
        // In your constructor, you should add any child components, and
        // initialise any special settings that your component needs.

        startTimer(10); //TODO avoid using timer
    }
    ~ReflectionsVisualizer()
    {
    }

    void paint (Graphics& g) override
    {
        Rectangle<int> bounds = getLocalBounds();
        
        
        
        g.setColour(Colours::steelblue.withMultipliedAlpha(0.01f));
        g.fillAll();
        
        g.setColour (Colours::steelblue.withMultipliedAlpha(0.9f));
        g.strokePath (axes, PathStrokeType (1.0f));
        g.setColour (Colours::steelblue.withMultipliedAlpha(0.8f));
        g.strokePath (dBGrid, PathStrokeType (0.5f));
        
        
        g.setColour(Colours::white);
        g.setFont(getLookAndFeel().getTypefaceForFont (Font(12.0f, 2)));
        g.setFont(12.0f);
        
        
        for (int dB = 0; dB >= -60; dB -= 10)
        {
            float yPos = dBToY((float) dB);
            g.drawText (String(dB), 0, yPos-6, 18, 12.0f, Justification::right, false);
        }
        
        int msStep;
        if (xRangeInMs < 80)
            msStep = 5;
        else if (xRangeInMs < 200)
            msStep = 10;
        else msStep = 20;
        
        for (int timeInMs = 0; timeInMs <= xRangeInMs; timeInMs += msStep)
        {
            float xPos = timeToX((float) timeInMs);
            g.drawText (String(timeInMs), xPos-15.0f, mT+plotHeight+2.0f, 30, 12.0f, Justification::centred, false);
        }
        

        
        const float xFactor = 1000.0f/343.2f;
        
        
        if (radiusPtr != nullptr)
        {
            int numRef = roundToInt(*numReflPtr);
            
            float gainDb = Decibels::gainToDecibels(gainPtr[0]);
            
            float xPos = timeToX(radiusPtr[0]*xFactor);
            float yPos = dBToY(gainDb);
            
            g.drawLine(xPos, yPos, xPos, mT + plotHeight, 2.0f);
            
            g.setColour(Colours::white.withMultipliedAlpha(0.5f));
            
            for (int i = 1; i <= numRef; ++i)
            {
                float gainDb = Decibels::gainToDecibels(gainPtr[i]);
                if (gainDb > -60.0f)
                {
                    float xPos = timeToX(radiusPtr[i]*xFactor);
                    float yPos = dBToY(gainDb);
                    g.drawLine(xPos, yPos, xPos, mT + plotHeight, 1.5f);
                }
            }
        }
    }
    
    inline float timeToX (float timeInMs) {
        return mL + timeInMs/xRangeInMs*plotWidth;
    }
    
    inline float dBToY (float gainInDB) {
        const float dynRange = - 1.0f/60.0f;
        return mT + dynRange * gainInDB * plotHeight;
    }
    
    void mouseWheelMove(const MouseEvent &e, const MouseWheelDetails &wheel) override {
        const double delta = 100*(std::abs (wheel.deltaX) > std::abs (wheel.deltaY) ? -wheel.deltaX : wheel.deltaY);
        //bool positiveDelta = delta >= 0.0;

        xRangeInMs += roundToInt(delta);
        xRangeInMs = jmin(xRangeInMs, 550);
        xRangeInMs = jmax(xRangeInMs, 40);
    }
    void setDataPointers(float* Gain, float* Radius, float* NumRefl) {
        gainPtr = Gain;
        numReflPtr = NumRefl;
        radiusPtr = Radius;
    }
    
    void resized() override
    {
        plotWidth = getLocalBounds().getWidth() - mL - mR;
        plotHeight = getLocalBounds().getHeight() - mT - mB;
        
        axes.clear();
        //horizontal
        axes.startNewSubPath(timeToX(0.0f)-2, dBToY(-60.0f));
        axes.lineTo(timeToX(xRangeInMs), dBToY(-60.0f));
        
        //vertical
        axes.startNewSubPath(timeToX(0.0f), dBToY(-60.0f)+2.0f);
        axes.lineTo(timeToX(0.0f), mT-2.0f);
        
        dBGrid.clear();
        for (int dB = 0; dB >= -50; dB -= 10)
        {
            float yPos = dBToY((float) dB);
            dBGrid.startNewSubPath(mL-2.0f, yPos);
            dBGrid.lineTo(mL+plotWidth, yPos);
        }
    }
    void timerCallback() override
    {
        repaint();
    }
private:
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ReflectionsVisualizer)
    Path axes;
    Path dBGrid;
    float plotWidth = 1.0f;
    float plotHeight = 1.0f;
    int xRangeInMs = 100;
    float* numReflPtr = nullptr;
    float* gainPtr = nullptr;
    float* radiusPtr = nullptr;
};

