
#ifndef __PROGRESS_BAR_H__
#define __PROGRESS_BAR_H__

#include <cmath>
#include <cstdint>
#include <iostream>
#include <string>

class ProgressBar
{
public:
    
    ProgressBar(
        const std::string& label, 
        uint32_t bar_length, 
        uint8_t progress=0)
        : label(label),
          bar_length(bar_length),
          progress(progress)
    { }
    
    ~ProgressBar() = default;

    void update(uint8_t new_progress)
    {
        // Progress is defined between 0 and 100 inclusive
        if (this->progress >= 100)
        {
            return;
        }
        
        this->progress = new_progress;
        
        std::cout << this->label;
        std::cout << " [";
        uint32_t pos = std::lround((static_cast<double>(this->progress) / 100) 
                                   * this->bar_length);
        for (uint32_t idx = 0; idx < this->bar_length; ++idx) 
        {
            if (idx < pos)
            {
                std::cout << "=";
            }
            else if ((idx == pos) && (idx == this->bar_length)) 
            {
                std::cout << "=";
            }
            else if (idx == pos) 
            {
                std::cout << ">";
            }
            else 
            {
                std::cout << " ";
            }
        }
        std::cout << "] " << int(this->progress) << " %\r";
        
        // NOTE: normally newline would only be output when progress reaches
        //       100% but here we redrawing an entire section of lines so 
        //       we want a newline for each update() call 
        std::cout << std::endl;
    }
    
    ProgressBar& operator++()
    {
        this->update(this->progress + 1);
        return *this;
    }

private:

    std::string label;
    uint32_t bar_length;
    uint8_t progress;

};

#endif // __PROGRESS_BAR_H__
