
#ifndef __train_H__
#define __train_H__

#include <Arduino.h>

class train
{
private:
    const uint8_t _MAX_FADE_STEP = 255;
    const uint8_t _MIN_FADE_STEP = 0;
    uint8_t _current_max_fade_step;
    uint8_t _current_min_fade_step;
    static const unsigned long  _FADE_DELAY_MS = 50;
    size_t _relais_pin;
    const char* _name;

    bool _switch_zero_relais;

    uint8_t _prev_pwm_value = 255;
    size_t _pwmpin;
    size_t _pwmchannel;
    uint8_t _fade_step;
    unsigned long  _last_faded_ms;
    unsigned long  _delay_ms;

    bool _fade(bool fade_up);

public:
    train(const char* name, size_t pwmpin , size_t pwmchannel, size_t relais_pin, unsigned long delay_ms = _FADE_DELAY_MS);
    ~train();
    void stop();
    bool fade_on();
    bool fade_off();
    void set_pwm(uint8_t pwm_value);
    void begin();
    bool is_stopped();
    bool is_up();
    bool is_down();
    uint8_t get_pwm();
    void switch_zero_relais(bool do_switch);
    bool fade_down_to(uint8_t pwm_value);
    bool fade_up_to(uint8_t pwm_value);
    
};

train::train(const char* name, size_t pwmpin, size_t pwmchannel, size_t relais_pin, unsigned long delay_ms)
{
    _pwmpin = pwmpin;
    _pwmchannel = pwmchannel;
    _fade_step = 0;
    _last_faded_ms = 0;
    _delay_ms = delay_ms;
    _relais_pin = relais_pin;
    _name = name;
    _switch_zero_relais = true;
    _current_max_fade_step = _MAX_FADE_STEP;
    _current_min_fade_step = _MIN_FADE_STEP;
}

void train::begin()
{
    //pinMode(_pwmpin, OUTPUT);
	ledcSetup(_pwmchannel, 100, 8);
	ledcAttachPin(_pwmpin, _pwmchannel);
    if(_relais_pin != -1)
    {
        pinMode(_relais_pin, OUTPUT);
        digitalWrite(_relais_pin, HIGH);
    }
}

train::~train()
{
}

void train::set_pwm(uint8_t pwm_value) {
    if(_prev_pwm_value != pwm_value)
    {
        _prev_pwm_value = pwm_value;
        if(_relais_pin != -1 )
        {
            if(pwm_value == 0 )
            {
                if( _switch_zero_relais == true)
                    digitalWrite(_relais_pin, HIGH);
            }
            else
            {
                digitalWrite(_relais_pin, LOW);
            }
        }
        _fade_step = pwm_value;
        ledcWrite(_pwmchannel, pwm_value); 
        Serial.printf("PWM '%s' set to value %d\n", _name, pwm_value);
    }
}

void train::stop() {
    set_pwm(0); 
}

bool train::_fade(bool fade_up)
{
    if(millis() - _last_faded_ms > _delay_ms)
    {
        _last_faded_ms = millis();
        if(true == fade_up)
        {
            if(_current_max_fade_step > _fade_step)
            {
                _fade_step++;
            }
            else
                return false;
        }
        else
        {
            if(_current_min_fade_step < _fade_step)
                _fade_step--;
            else
                return false;
        }
        set_pwm(_fade_step); 
    }
    return true;
}


bool train::fade_down_to(uint8_t pwm_value)
{   
    _current_min_fade_step = pwm_value;
    return _fade(false);
}

bool train::fade_up_to(uint8_t pwm_value)
{   
    _current_max_fade_step = pwm_value;
    return _fade(true);
}


bool train::fade_on()
{
    _current_max_fade_step = _MAX_FADE_STEP;
    return _fade(true);
}

bool train::fade_off()
{
    _current_min_fade_step = _MIN_FADE_STEP;
    return _fade(false);
}

void train::switch_zero_relais(bool do_switch)
{
    _switch_zero_relais = do_switch;
}

bool train::is_stopped()
{
    if(_prev_pwm_value == 0)
        return true;
    else
        return false;
}

bool train::is_up()
{
    if(_prev_pwm_value == _current_max_fade_step)
        return true;
    else 
        return false;
}

bool train::is_down()
{
    if(_prev_pwm_value == _current_min_fade_step)
        return true;
    else 
        return false;
}

uint8_t train::get_pwm()
{
    return _prev_pwm_value;
}

#endif
