#include "slider.hpp"
LooperSlider::LooperSlider(const char *name, const char *label, double min, double max, double tick, bool logarithmic, QWidget *parent) : QWidget(parent) {
	root_layout = new QBoxLayout(QBoxLayout::LeftToRight, this);
	text_layout_view = new QBoxLayout(QBoxLayout::TopToBottom);
	QWidget *text_layout_widget = new QWidget(this);
	text_layout_widget->setLayout(text_layout_view);
	root_layout->addWidget(text_layout_widget);
	text_label = new QLabel(text_layout_widget);
	slider = new _looperSlider(Qt::Orientation::Horizontal, text_layout_widget);
	slider->connect(slider, &_looperSlider::mousePressed, [=,this]() {
		pressed = true;
		slider_value_changed_after_release = false;
		emit(mousePressed());
	});
	slider->connect(slider, &_looperSlider::mouseReleased, [=,this]() {
		emit(mouseReleased());
		pressed = false;
	});
	slider->connect(slider, &QSlider::valueChanged, [=,this](int value) {
		if (slider_value_updating) return;
		double actual_value = value * tick;
		if (logarithmic) actual_value = scaler->unscale_log(actual_value);
		this->SetValue(actual_value);
		emit(changed(actual_value));
		slider_value_changed_after_release = true;
	});
	text_layout_view->addWidget(slider);
	btn = new QPushButton(this);
	btn->connect(btn, &QPushButton::pressed, [=,this]() {
		SwitchModes();
	});
	root_layout->addWidget(btn);
	text = new QLineEdit(text_layout_widget);
	text->setVisible(false);
	text_layout_view->addWidget(text);
	text->connect(text, &QLineEdit::textChanged, [=,this]() {
		const char *value = text->text().toLocal8Bit().constData();
		bool ok = true;
		double output = this->Value();
		try {
			output = std::stod(value);
		} catch (std::exception) {
			ok = false;
		}
		if (ok) {
			textChanged = true;
			emit(changed(output));
			this->SetValue(output);
		}
	});
	limits_view = new QBoxLayout(QBoxLayout::LeftToRight, text_layout_widget);
	min_label_view = new QLabel(text_layout_widget);
	limits_view->addWidget(min_label_view, 0, Qt::Alignment::enum_type::AlignLeft);
	max_label_view = new QLabel(text_layout_widget);
	limits_view->addWidget(max_label_view, 0, Qt::Alignment::enum_type::AlignRight);
	scaler = new LooperLogScaler(min, max);
	set_min(min);
	set_max(max);
	set_tick(tick);
	set_logarithmic(logarithmic);
	this->label = strdup(label);
	this->value = min;
	UpdateSlider(true);
	
}
bool LooperSlider::IsPressed() {
	return pressed;
}
double LooperSlider::Value() {
	return value;
}
void LooperSlider::set_value(double value) {
	if (!pressed && slider_value_changed_after_release) this->value = value;
	this->UpdateSlider(true);
}
void LooperSlider::SetValue(double value) {
	set_value(value);
}
void LooperSlider::set_min(double min) {
	settings_changed = true;
	this->min = min;
}
void LooperSlider::set_max(double max) {
	settings_changed = true;
	this->max = max;
}
void LooperSlider::set_logarithmic(bool logarithmic) {
	settings_changed = true;
	this->logarithmic = true;
}
void LooperSlider::UpdateLogScaler() {
	this->scaler->update_min_max(this->min, this->max);
}
void LooperSlider::SetMin(double min) {
	this->set_min(min);
	UpdateSlider(false);
}
void LooperSlider::SetMax(double max) {
	this->set_max(max);
	UpdateSlider(false);
}
double LooperSlider::Min() {
	return this->min;
}
double LooperSlider::Max() {
	return this->max;
}
void LooperSlider::SetLimits(double min, double max) {
	set_min(min);
	set_max(max);
	UpdateSlider(false);
}
void LooperSlider::SetMinLabel(const char *label) {
	if (this->min_label) free((void*)this->min_label);
	this->min_label = strdup(label);
	UpdateSlider();
}
void LooperSlider::SetMaxLabel(const char *label) {
	if (this->max_label) free((void*)this->max_label);
	this->max_label = strdup(label);
	UpdateSlider();
}
void LooperSlider::SetLimitLabels(const char *min, const char *max) {
	SetMinLabel(min);
	SetMaxLabel(max);
}
LooperSlider::~LooperSlider() {
	if (this->min_label) free((void*)this->min_label);
	if (this->max_label) free((void*)this->max_label);
	if (this->label) free((void*)this->label);
}
const char *LooperSlider::MinLabel() {
	return this->min_label;
}
const char *LooperSlider::MaxLabel() {
	return this->max_label;
}
void LooperSlider::SetLogarithmic(bool logarithmic) {
	set_logarithmic(logarithmic);
	UpdateSlider(false);
}
bool LooperSlider::IsLogarithmic() {
	return this->logarithmic;
}
void LooperSlider::SetLabel(const char *label) {
	if (this->label) free((void*)this->label);
	this->label = strdup(label);
}
const char *LooperSlider::Label() {
	return this->label;
}
double LooperSlider::Tick() {
	return this->tick;
}
void LooperSlider::SetMode(bool use_text_editor) {
	this->text_edit_mode = use_text_editor;
	UpdateSlider(true);
}
void LooperSlider::EnableModeButton(bool enabled) {
	btn->setVisible(enabled);
}
void LooperSlider::SetTick(double value) {
	set_tick(value);
	UpdateSlider(false);
}
void LooperSlider::set_tick(double value) {
	this->settings_changed = true;
	this->tick = value;
}
void LooperSlider::UpdateSlider(bool update_value) {
	UpdateLogScaler();
	if (this->min_label == NULL) {
		this->min_label_view->setText("");
	} else {
		this->min_label_view->setText(this->min_label);
	}
	if (this->max_label == NULL) {
		this->max_label_view->setText("");
	} else {
		this->max_label_view->setText(this->max_label);
	}
	limits_visible = (this->min_label == NULL && this->max_label == NULL);
	if (limits_visible) {
		if (!limits_actually_visible) {
			this->text_layout_view->addItem(this->limits_view);
			limits_actually_visible = true;
		}
	} else {
		if (limits_actually_visible) {
			this->text_layout_view->removeItem(this->limits_view);
			limits_actually_visible = false;
		}
	}
	if (this->label == NULL) {
		if (text_label_visible) {
			this->text_layout_view->removeWidget(this->text_label);
			text_label_visible = false;
		}
	} else {
		this->text_label->setText(this->label);
		if (!text_label_visible) {
			this->text_layout_view->insertWidget(0, this->text_label);
			text_label_visible = true;
		}
	}
	if (this->text_edit_mode) {
		if (!text_editor_visible) {
			this->text_layout_view->insertWidget(1, this->text);
			text_editor_visible = true;
		}
		if (slider_visible) {
			this->text_layout_view->removeWidget(this->slider);
			slider_visible = false;
		}
	} else {
		if (!slider_visible) {
			this->text_layout_view->insertWidget(1, this->slider);
			slider_visible = true;
		}
		if (text_editor_visible) {
			this->text_layout_view->removeWidget(this->text);
			text_editor_visible = false;
		}
	}
	auto icon = QIcon::fromTheme(text_edit_mode ? "slider_edit_mode" : "text_edit_mode", QIcon::fromTheme(text_edit_mode ? "dialog-ok" : "edit"));
	auto text = text_edit_mode ? "Imprecise" : "Precise";
	if (icon.isNull() || show_button_text) {
		this->btn->setText(text);
	} else {
		this->btn->setText("");
	}
	if (show_button_icon && !icon.isNull()) {
		this->btn->setIcon(icon);
	} else {
		QIcon emptyIcon;
		this->btn->setIcon(emptyIcon);
	}
	this->slider->setVisible(slider_visible);
	this->text->setVisible(text_editor_visible);
	this->text_label->setVisible(text_label_visible);
	this->min_label_view->setVisible(limits_actually_visible);
	this->max_label_view->setVisible(limits_actually_visible);
	if (update_value) {
		if (textChanged) {
			textChanged = false;
		} else {
			if (!pressed && !text_edit_mode) this->text->setText(fmt::to_string(this->value).c_str());
		}
		slider_value_updating = true;
		if (!pressed && slider_value_changed_after_release) {
			this->slider->setValue(this->logarithmic ? (this->scaler->scale_log(this->value) / this->tick) : (this->value / this->tick));
			this->slider->setMinimum(this->min / tick);
			this->slider->setMaximum(this->max / tick);
		}
		slider_value_updating = false;

	}
}
bool LooperSlider::ShowButtonText() {
	return show_button_text;
}
bool LooperSlider::ShowButtonIcon() {
	return show_button_icon;
}
void LooperSlider::SetShowButtonIcon(bool enable) {
	this->show_button_icon = enable;
	UpdateSlider();
}
void LooperSlider::SetShowButtonText(bool enable) {
	this->show_button_text = enable;
	UpdateSlider();
}
void LooperSlider::changeEvent(QEvent *event) {
	if (event->type() == QEvent::EnabledChange) {
		this->slider->setEnabled(isEnabled());
		this->text->setEnabled(isEnabled());
	}
}