#include <iostream>
#include <cstdlib>

#include <stdio.h>
#include <time.h>
#include <dos.h>
#include <windows.h>

#include <TGUI/TGUI.hpp>

#define THEME_CONFIG_FILE "data/widgets/Black.conf"

using namespace std;

// Done: //
/*

*	Knobs and sliders synced.
*	Correct rendering and positions of piano keys
*	Actual values shown
*	Sync hardware keypress <<== TODO

*	???
*/

bool piano_keys[25];

void reverse(char s[])
{
	int length = strlen(s);
	int c, i, j;

	for (i = 0, j = length - 1; i < j; i++, j--)
	{
		c = s[i];
		s[i] = s[j];
		s[j] = c;
	}
}

int main()
{
	std::cout << "\n RexKeyPad is provided as-is without any warranty.\n";
	std::cout << "\t\tCreated by Patrik356b\t\t\n\n";

	// GUI

	sf::RenderWindow window(sf::VideoMode(960, 600), "RexKeyPad");
	tgui::Gui gui(window);

	if (gui.setGlobalFont("data/DroidSansMono.ttf") == false)
		return 1;

	sf::Font VerticalFont;
	// Load it from a file
	if (!VerticalFont.loadFromFile("data/AachenVertical.ttf"))
	{
		return 1;
	}
	
#define CHECKBOX_INVERT 5

	tgui::Checkbox::Ptr syncbox(gui);
	syncbox->load(THEME_CONFIG_FILE);
	syncbox->setPosition(810, 20);
	syncbox->setText("Invert");
	syncbox->setSize(32, 32);
	syncbox->bindCallback(tgui::Checkbox::Checked);
	syncbox->setCallbackId(CHECKBOX_INVERT);
	syncbox->bindCallback(tgui::Checkbox::Unchecked);
	syncbox->setCallbackId(CHECKBOX_INVERT);
	
	syncbox->disable();
	syncbox->setTransparency(117);
	int sync_box_is_broken;

	const int vertical_control_separator = 100;
	char valText[4] = "";

	reverse(valText);
	tgui::Label::Ptr val1(gui);
	val1->load(THEME_CONFIG_FILE);
	val1->setTextFont(VerticalFont);
	val1->setText(valText);
	val1->setPosition(70, 21);
	val1->setTextColor(sf::Color(200, 200, 200));
	val1->setTextSize(28);	

#define SCROLLBAR_BTN_SIZE 6

	tgui::Scrollbar::Ptr scrollbar1(gui);
	scrollbar1->load(THEME_CONFIG_FILE);
	scrollbar1->setVerticalScroll(true);
	scrollbar1->setPosition(20, 20);
	scrollbar1->setSize(18, 256);
	scrollbar1->setMaximum(127 + SCROLLBAR_BTN_SIZE);
	scrollbar1->setLowValue(SCROLLBAR_BTN_SIZE);

	tgui::Knob::Ptr knob1(gui);
	knob1->load("data/widgets/Knob/Knob.conf");
	knob1->setPosition(55, 235);
	knob1->setSize(40, 40);
	knob1->setStartRotation(127 + 90);
	knob1->setEndRotation(-128 + 90);
	knob1->setMinimum(0);
	knob1->setMaximum(127 );

	/* Callback handling*/
#define Knob_CALLBACK_ID 10
#define KnobScroll_CALLBACK_ID 20

	bool invert_Knob_SYNC = false;

	knob1->bindCallback(tgui::Knob::ValueChanged);
	knob1->setCallbackId(Knob_CALLBACK_ID + 1);

	syncbox->bindCallback(tgui::Checkbox::Checked);
	syncbox->bindCallback(tgui::Checkbox::Unchecked);
	syncbox->setCallbackId(CHECKBOX_INVERT);

	scrollbar1->bindCallback(tgui::Scrollbar::ValueChanged);
	scrollbar1->setCallbackId(KnobScroll_CALLBACK_ID + 1);

	/* Piano keys */

#define PIANO_KEY_BLACK 30
#define PIANO_KEY_WHITE 50

#define WHITE_KEY_SEPARATOR 25
#define BLACK_KEY_SEPARATOR 25


	tgui::Button::Ptr PianoKey1(gui);
	PianoKey1->load("data/widgets/keys_lower.conf");
	PianoKey1->setPosition(15, 295);
	PianoKey1->bindCallback(tgui::Button::LeftMousePressed);
	PianoKey1->setCallbackId(PIANO_KEY_WHITE);
	PianoKey1->setSize(22, 92);

	tgui::Button::Ptr PianoKeyA(gui);
	PianoKeyA->load("data/widgets/keys_upper.conf");
	PianoKeyA->setPosition(5 + BLACK_KEY_SEPARATOR, 295);
	PianoKeyA->bindCallback(tgui::Button::LeftMousePressed);
	PianoKeyA->setCallbackId(PIANO_KEY_BLACK);
	PianoKeyA->setSize(17, 64);

	/* Misc */

	tgui::Label::Ptr label(gui);
	label->load(THEME_CONFIG_FILE);
	label->setText("Sync");
	label->setPosition(870, 57);
	label->setTextColor(sf::Color(200, 200, 200));
	label->setTextSize(24);

	/*
	tgui::ComboBox::Ptr comboBox(gui);
	comboBox->load(THEME_CONFIG_FILE);
	comboBox->setSize(120, 21);
	comboBox->setPosition(210, 440);
	comboBox->addItem("Item 1");
	comboBox->addItem("Item 2");
	comboBox->addItem("Item 3");
	comboBox->setSelectedItem("Item 2");

	tgui::ListBox::Ptr listBox(gui);
	listBox->load(THEME_CONFIG_FILE);
	listBox->setSize(150, 120);
	listBox->setItemHeight(20);
	listBox->setPosition(40, 440);
	listBox->addItem("Item 1");
	listBox->addItem("Item 2");
	listBox->addItem("Item 3");



	tgui::Tab::Ptr tab(gui);
	tab->load(THEME_CONFIG_FILE);
	tab->setPosition(40, 370);
	tab->add("Item 1");
	tab->add("Item 2");
	tab->add("Item 3"); */

	// initalize defaults
	knob1->setValue(0);

	scrollbar1->setValue(63);

	while (window.isOpen())
	{
		sf::Event event;
		while (window.pollEvent(event))
		{
			if (event.type == sf::Event::Closed)
				window.close();

			gui.handleEvent(event);
		}

		if (hw_sync)
		{
			knob1->setValue(hw_knob[0]);

			for (int k = 0; k < sizeof(piano_keys); k++)
			{
				if (piano_keys[k] == true)
				{
					switch (k)
					{
						case 0:
						{
							PianoKey1->mouseMoved(15, 295);
							PianoKey1->leftMousePressed(15, 295);
							break;
						}
						case 1:
						{
							PianoKeyA->mouseMoved(5 + BLACK_KEY_SEPARATOR, 295);
							PianoKeyA->leftMousePressed(5 + BLACK_KEY_SEPARATOR, 295);
							break;
						}
					}
				}
				else
				{
					switch (k)
					{
						case 0:
						{
							PianoKey1->mouseNotOnWidget();
							PianoKey1->leftMouseReleased(15, 295);
							break;
						}
						case 1:
						{
							PianoKeyA->mouseNotOnWidget();
							PianoKeyA->leftMouseReleased(5 + BLACK_KEY_SEPARATOR, 295);
							break;
						}
					}
				}
			}
		}

		// Callback handling

		tgui::Callback callback;
		while (gui.pollCallback(callback))
		{
			int value;

			switch (callback.id)
			{
				// Knobs
				case Knob_CALLBACK_ID + 1:
				{
					value = knob1->getValue();

					if (invert_Knob_SYNC == false) scrollbar1->setValue(127 - value); // works but sync is flipped
					else scrollbar1->setValue(value); // default
					_itoa_s(value, valText, 10);
					reverse(valText);
					char lvalue[7];
					lvalue[0] = valText[0];
					lvalue[1] = '\n';
					lvalue[2] = valText[1];
					lvalue[3] = '\n';
					lvalue[4] = valText[2];
					lvalue[5] = '\0';
					val1->setText(lvalue);
					break;
				}
				
				case CHECKBOX_INVERT:
				{
					invert_Knob_SYNC = !invert_Knob_SYNC;
					break;
				}
				
				case KnobScroll_CALLBACK_ID + 1:
				{
					value = scrollbar1->getValue();

					if (invert_Knob_SYNC == false) knob1->setValue(127 - value); // works but sync is flipped
					else knob1->setValue(value); // default
					break;
				}		

				case HWSYNC_CALLBACK_ID:
				{
					hw_sync = hwsyncbox->isChecked();
					break;
				}

				case PIANO_KEY_BLACK:
				{
					std::cout << "callback.id: " << callback.id << '\t';
					break;
				}

				case PIANO_KEY_WHITE:
				{
					std::cout << "callback.id: " << callback.id << '\t';
					break;
				}
			}
		}

		// misc

		window.clear();
		gui.draw();
		window.display();
	}

	return EXIT_SUCCESS; // Application exited successfully
}

