#include "StepSlider.h"

class StepSlider::_Slider : public Window {
    friend class StepSlider;
public:
    enum {
        NORMAL,
        ACTIVE,
        DISABLED
    };

    _Slider(Window* parent = 0);
    virtual ~_Slider();

    void enable(bool enabled);

protected:
    void onMouseLeftDown(Event& event);
    void onMouseLeftUp(Event& event);
    void onDrag(Event& event);
    void onEndDrag(Event& event);

    int _state;

    Texture *_normalTexture,
            *_activeTexture,
            *_disabledTexture;
};


StepSlider::_Slider::_Slider(Window* parent)
: Window(parent), _state(NORMAL),
_normalTexture(0), _activeTexture(0)
{
    setPosition(Point(0.0f, 0.0f));
    setSize(Size(10.0f, 18.0f));

    _normalTexture = ResourceManager::instance().loadTexture(L"textures/gui/slider.dds");
    _activeTexture = ResourceManager::instance().loadTexture(L"textures/gui/slider_active.dds");
    _disabledTexture = ResourceManager::instance().loadTexture(L"textures/gui/slider_disabled.dds");

    _texture = _normalTexture;

    connectEvent(Event::MOUSE_LEFT_DOWN, this, (EventHandler)&StepSlider::_Slider::onMouseLeftDown);
    connectEvent(Event::MOUSE_LEFT_UP,   this, (EventHandler)&StepSlider::_Slider::onMouseLeftUp);
    connectEvent(Event::DRAG,            this, (EventHandler)&StepSlider::_Slider::onDrag);
    connectEvent(Event::DRAG_END,        this, (EventHandler)&StepSlider::_Slider::onEndDrag);

    _draggable = true;
}

StepSlider::_Slider::~_Slider()
{

}


void StepSlider::_Slider::enable(bool enabled)
{
    Window::enable(enabled);
    
    if (_enabled) {
        _state = NORMAL;
        _texture = _normalTexture;
    }
    else {
        _state = DISABLED;
        _texture = _disabledTexture;
    }
}


void StepSlider::_Slider::onMouseLeftDown(Event& event)
{
    if (_enabled) {
        _state = ACTIVE;
        _texture = _activeTexture;
    }
}

void StepSlider::_Slider::onMouseLeftUp(Event& event)
{
    if (_enabled) {
        _state = NORMAL;
        _texture = _normalTexture;
    }
}

void StepSlider::_Slider::onDrag(Event& event)
{
    if (_enabled) {
        StepSlider* parent = (StepSlider*)_parent;

        float value = (_position.x() / (parent->getSize().w() - 10.0f)) * ((parent->_maxValue - parent->_minValue) / parent->_step) + parent->_minValue;

        float upper = ceil(value);
        float lower = floor(value);

        if (upper - value < value - lower)
            parent->setValue((int)upper);
        else
            parent->setValue((int)lower); 
    }
}

void StepSlider::_Slider::onEndDrag(Event& event)
{
    if (_enabled) {
        _state = NORMAL;
        _texture = _normalTexture;
    }
}


StepSlider::StepSlider(Window* parent)
: Window(parent), _slider(0), _minValue(1), _maxValue(10), _step(1)
{
    setPosition(Point(0.0f, 0.0f));
    setSize(Size(210.0f, 18.0f));
    
    _texture = ResourceManager::instance().loadTexture(L"textures/gui/slider_background.dds");

    _slider = new _Slider(this);

    connectEvent(Event::MOUSE_LEFT_DOWN, this, (EventHandler)&StepSlider::onMouseLeftDown);
}

StepSlider::~StepSlider()
{
    delete _slider;
}

int StepSlider::getMinValue()
{
    return _minValue;
}

int StepSlider::getMaxValue()
{
    return _maxValue;
}

int StepSlider::getStep()
{
    return _step;
}

void StepSlider::setMinValue(int minValue)
{
    _minValue = minValue;
}

void StepSlider::setMaxValue(int maxValue)
{
    _maxValue = maxValue;
}

void StepSlider::setStep(int step)
{
    _step = step;
}

int StepSlider::getValue()
{
    return (int)((_slider->getPosition().x() / (_size.w() - 10.0f)) * (_maxValue - _minValue) + _minValue);
}

void StepSlider::setValue(int value)
{
    float smoothValue = (float)(value - _minValue) / (float)((_maxValue - _minValue) / _step);
    _slider->setPosition(Point(smoothValue * (_size.w() - 10.0f), 0.0f));

    Event evtValueChanged;
    memset(&evtValueChanged, 0, sizeof(Event));
    evtValueChanged.type = Event::VALUE_CHANGED;
    handleEvent(evtValueChanged);
}

void StepSlider::onMouseLeftDown(Event& event)
{
    if (_enabled) {
        float sliderPosition = event.mouseX - getTranslatedPosition().x();

        if (sliderPosition + 10.0f > _size.w())
            sliderPosition = _size.w() - 10.0f;

        float value = (sliderPosition / (_size.w() - 10.0f)) * ((_maxValue - _minValue) / _step) + _minValue;

        float upper = ceil(value);
        float lower = floor(value);

        if (upper - value < value - lower)
            setValue((int)upper);
        else
            setValue((int)lower);
 
        Event evtValueChanged;
        memset(&evtValueChanged, 0, sizeof(Event));
        evtValueChanged.type = Event::VALUE_CHANGED;
        handleEvent(evtValueChanged);
    }
}