//
//  Graph.hpp
//  RapidVisualizerOSC
//
//  Created by James on 09/11/2017.
//
//

#ifndef Graph_h
#define Graph_h

#include <string>
#include <vector>
#include <list>
#include "ofMain.h"
#include "ofxGui.h"

// TODO: add namespace, move funcs and struct to other header(s)
enum class TextAlignment {
    LEFT,
    CENTER,
    RIGHT
};

static inline void drawTextLabel ( std::string label, ofVec2f position, ofColor labelBackgroundColor, ofColor stringColor, TextAlignment alignment, bool drawAbove )
{
    uint32_t strLenPix = label.length()*8;
    
    switch (alignment) {
        case TextAlignment::LEFT:
            // No exception
            break;
        case TextAlignment::CENTER:
            position.x -= strLenPix / 2;
            break;
        case TextAlignment::RIGHT:
            position.x -= strLenPix;
            break;
        default:
            break;
    }
    
    ofSetColor (labelBackgroundColor);
    ofRectangle bmpStringRect(position.x - 2,
                              position.y + ((drawAbove) ? -4 : 12) + 2,
                              strLenPix + 4, -12);
    ofDrawRectangle(bmpStringRect);
    
    ofSetColor (stringColor);
    ofDrawBitmapString(label, position.x, position.y + ((drawAbove) ? -4 : 12));
}

static inline double mapVals ( double x, double in_min, double in_max, double out_min, double out_max )
{
    return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

template <typename T>
struct DataContainer {
    T labelData;
    double minValue = 0.0;
    double maxValue = 1.0;
    uint32_t iteratorPos = 0;
    //ofColor graphColor;
    
    void updateMinMax ( void )
    {
        auto mm = std::minmax_element(labelData.begin(), labelData.end());
        double min = labelData[std::distance(labelData.begin(), mm.first)];
        double max = labelData[std::distance(labelData.begin(), mm.second)];
        
        if (min < minValue)
            minValue = min;
        if (max > maxValue)
            maxValue = max;
        if (fabs(min) > maxValue)
            maxValue = fabs(min);
    
    }
};

class Graph {
public:
    enum graphLayout {
        GRAPHS_STACKED,
        GRAPHS_VERTICAL
    };
    struct GraphState {
        std::string label;
        graphLayout layout = graphLayout::GRAPHS_STACKED;
        bool hasHistory = false;
        ofRectangle positionAndSize;
        uint32_t historySize;
    };
    
    Graph ( GraphState* state )
    : state(state)
    {
        graphColor = ofColor(24, 219, 92);
        textColor = ofColor(255, 157, 117);
    }
    
    virtual ~Graph ( void )
    {
        
    }
    
    virtual void updateRep ( void ) = 0; // update representation
    virtual void addData ( std::string subLabel, std::vector<double>& data ) = 0;
    virtual void reset ( void ) = 0;
    
    virtual void update ( void ) = 0;
    virtual void draw ( void ) = 0;

    virtual uint32_t getNumSubGraphs ( void ) const = 0;
protected:
    GraphState *state = nullptr;
    ofColor graphColor;
    ofColor textColor;
};

#endif /* Graph_h */