#include "KeypadWidget.h"

#include <QGridLayout>
#include <QPushButton>
#include <QLabel>
#include <QMessageBox>
#include <QToolButton>
#include <QKeyEvent>
#include <QDebug>

KeypadWidget::KeypadWidget(QWidget *parent /*= 0*/)
	: QWidget(parent)
	, m_value(0)
	, m_defaultValue(0)
	, m_minimum(0)
	, m_maximum(255)
	, m_mode(Range)
{
	QVBoxLayout *mainLayout = new QVBoxLayout(this);
	QFrame *keypadWidget = new QFrame();
	QGridLayout *keypad = new QGridLayout(keypadWidget);

	mainLayout->setSpacing(0);
	mainLayout->setMargin(0);
	mainLayout->setContentsMargins(0,0,0,0);
	mainLayout->setStretchFactor(keypadWidget, 1);

	keypad->setSpacing(0);
	keypad->setVerticalSpacing(0);
    keypad->setContentsMargins(0,0,0,0);
	
	for(int row = 0; row < 3; row++)
	{
		keypad->setRowStretch(row, 1);
		keypad->setColumnStretch(row, 1);
		for(int column = 0; column < 3; column++)
		{
			int index = (2 - row) * 3 + column + 1;
			QPushButton *digitButton = new QPushButton(QString::number(index));
			digitButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
			connect(digitButton, SIGNAL(clicked()), this, SLOT(digitClicked()));
			keypad->addWidget(digitButton, row, column);
			m_digitButtons[index] = digitButton;
		}
	}

	keypad->setRowStretch(3, 1);

	QPushButton *digitButton = new QPushButton("0");
	digitButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
	connect(digitButton, SIGNAL(clicked()), this, SLOT(digitClicked()));
	keypad->addWidget(digitButton, 3, 1);
	m_digitButtons[0] = digitButton;
	
	m_deleteButton = new QPushButton("DEL");
	m_deleteButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
	connect(m_deleteButton, SIGNAL(clicked()), this, SLOT(backClicked()));
	keypad->addWidget(m_deleteButton, 3, 0);

	m_resetButton = new QPushButton("RESET");
	m_resetButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
	connect(m_resetButton, SIGNAL(clicked()), this, SLOT(reset()));
	keypad->addWidget(m_resetButton, 3, 2);
	
	m_valueLabel = new QLabel("0");
	m_valueLabel->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
	m_valueLabel->setStyleSheet("border: 2px solid black; border-radius: 8px;");

	mainLayout->addWidget(m_valueLabel);
	mainLayout->addWidget(keypadWidget);
}

void KeypadWidget::setValue(int value)
{
	if (m_mode == Selection)
	{
		QSetIterator<int> itr(m_selections);
		if (itr.hasNext())
		{
			// Seek nearest value
			int nearestValue = itr.next();
			while (itr.hasNext() && nearestValue != value)
			{
				int nextValue = itr.next();
				int length = qAbs(nextValue - value);
				if (length < qAbs(nearestValue - value))
					nearestValue = nextValue;
			}
			// Approximate match, update the value
			value = nearestValue;
		}
		else
		{
			this->setEnabled(false);
			m_valueLabel->setText("");
			m_valueLabel->update();
			return;
		}
	}
	else // m_mode == Range
	{
		if (value > m_maximum)
			value = m_maximum;
		else if (value < m_minimum)
			value = m_minimum;
	}
	this->setEnabled(true);
	if (m_value == value)
		return;

	if (m_mode == Selection)
	{
		m_deleteButton->setEnabled(true);
		for(int index = 0; index < 10; index++)
			m_digitButtons[index]->setEnabled(m_selections.contains(value * 10 + index));
		m_deleteButton->setEnabled(value != m_minimum);
	}
	else
	{
		for(int index = 0; index < 10; index++)
			m_digitButtons[index]->setEnabled(value * 10 + index <= m_maximum);
		m_deleteButton->setEnabled(value != m_minimum && value / 10 >= m_minimum);
	}
	if (value == 0)
		m_digitButtons[0]->setEnabled(false);
	m_resetButton->setEnabled(value != m_defaultValue);
	
	m_value = value;
	
	emit valueChanged(value);

	if (m_mode == Selection && !m_selections.contains(value))
	{
		m_valueLabel->setText(""); // hide the selection hack
		m_valueLabel->update();
	}
	else
	{
		m_valueLabel->setText(QString::number(value));
		m_valueLabel->update();
	}
}

void KeypadWidget::setDefaultValue(int defaultValue)
{
	m_defaultValue = defaultValue;
}
void KeypadWidget::setMinimum(int minimum)
{
	m_minimum = minimum;
}
void KeypadWidget::setMaximum(int maximum)
{
	m_maximum = maximum;
}
void KeypadWidget::setSelections(QSet<int> selections)
{
	m_selections = selections;
}
void KeypadWidget::setMode(ModeType mode)
{
	m_mode = mode;
}

void KeypadWidget::digitClicked()
{
	QPushButton *digitButton = qobject_cast<QPushButton *>(sender());
	Q_ASSERT(digitButton);
	bool isDigit = false;
	int digit = digitButton->text().toInt(&isDigit);
	Q_ASSERT(isDigit);
	setValue(m_value * 10 + digit);
}

void KeypadWidget::reset()
{
	setValue(m_defaultValue);
}

void KeypadWidget::backClicked()
{
	// Allow backspace in selection mode for 0 - 9
	if (m_value < m_minimum + 10 && m_mode == Selection && !m_selections.contains(0))
	{
		m_value = 0;
		// Hack: Hide the ninja value and don't report value update
		m_valueLabel->setText("");
		for(int i = 0; i < 10; i++)
			m_digitButtons[i]->setEnabled(m_selections.contains(m_value * 10 + i));
		m_deleteButton->setEnabled(false);
	}
	else
	{
		setValue(m_value / 10);
	}
}

void KeypadWidget::keyPressEvent ( QKeyEvent * args )
{
	int key = args->key();
	if (key <= Qt::Key_9 && key >= Qt::Key_0)
		m_digitButtons[key - Qt::Key_0]->click();
	else switch(key)
	{
		case Qt::Key_Backspace:
		case Qt::Key_Delete:
			m_deleteButton->click();
			break;
		case Qt::Key_Escape:
			m_resetButton->click();
			break;
		default:
			QWidget::keyPressEvent( args );
			return;
	}
	args->accept();
}
