/// Copyright (c) 2010 Ruben Penalva. All rights reserved.
/// Redistribution and use in source and binary forms, with or without modification, 
/// are permitted provided that the following conditions are met:
///    1. Redistributions of source code must retain the above copyright notice, this 
///    list of conditions and the following disclaimer.
///    2. Redistributions in binary form must reproduce the above copyright notice,
///    this list of conditions and the following disclaimer in the documentation and/or
///    other materials provided with the distribution.
///    3. The name of the author may not be used to endorse or promote products derived
///    from this software without specific prior written permission.
///
/// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
/// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
/// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 
/// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 
/// TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
/// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
/// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 
/// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include "SettingsTab.hxx"

#include <QT\QApplication.h>
#include <QtGui\QLabel>
#include <QtGui\QGroupBox>

using namespace TaskBasedFlockSim;

SettingsTab::SettingsTab(TestFrameWork::UserEventQueue& eventQueue)	:	m_widget(new QWidget()), 
																		m_eventQueue(eventQueue)
{
	SetupWidget();
}

SettingsTab::~SettingsTab(void)
{
}

QWidget* SettingsTab::GetWidget(void) const
{
	return m_widget;
}

void SettingsTab::SetupWidget(void)
{
	m_widget->setObjectName(QString::fromUtf8("Settings"));
	m_widget->resize(181, 434);
	QMetaObject::connectSlotsByName(m_widget);
	m_widget->setWindowTitle(QApplication::translate("Settings", "Settings", 0, QApplication::UnicodeUTF8));

	QGroupBox* groupBox_2 = new QGroupBox(m_widget);
	groupBox_2->setObjectName(QString::fromUtf8("groupBox_2"));
	groupBox_2->setGeometry(QRect(3, 10, 192, 381));
	m_doubleSpinBox_angleIncrement = new QDoubleSpinBox(groupBox_2);
	m_doubleSpinBox_angleIncrement->setObjectName(QString::fromUtf8("doubleSpinBox_angleIncrement"));
	m_doubleSpinBox_angleIncrement->setGeometry(QRect(140, 80, 49, 20));
	m_doubleSpinBox_angleIncrement->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
	m_doubleSpinBox_angleIncrement->setMaximum(720.0f);
	m_doubleSpinBox_angleIncrement->setSingleStep(0.1f);
	QLabel* label_3 = new QLabel(groupBox_2);
	label_3->setObjectName(QString::fromUtf8("label_3"));
	label_3->setGeometry(QRect(10, 50, 61, 20));
	QLabel* label_10 = new QLabel(groupBox_2);
	label_10->setObjectName(QString::fromUtf8("label_10"));
	label_10->setGeometry(QRect(10, 80, 77, 16));
	m_spinBox_flockSize = new QSpinBox(groupBox_2);
	m_spinBox_flockSize->setObjectName(QString::fromUtf8("spinBox_flockSize"));
	m_spinBox_flockSize->setGeometry(QRect(120, 20, 70, 20));
	QSizePolicy sizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
	sizePolicy.setHorizontalStretch(0);
	sizePolicy.setVerticalStretch(0);
	sizePolicy.setHeightForWidth(m_spinBox_flockSize->sizePolicy().hasHeightForWidth());
	m_spinBox_flockSize->setSizePolicy(sizePolicy);
	m_spinBox_flockSize->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
	m_spinBox_flockSize->setMaximum(999999999);
	m_doubleSpinBox_maxSpeed = new QDoubleSpinBox(groupBox_2);
	m_doubleSpinBox_maxSpeed->setObjectName(QString::fromUtf8("doubleSpinBox_maxSpeed"));
	m_doubleSpinBox_maxSpeed->setGeometry(QRect(140, 50, 49, 20));
	m_doubleSpinBox_maxSpeed->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
	QLabel* label_2 = new QLabel(groupBox_2);
	label_2->setObjectName(QString::fromUtf8("label_2"));
	label_2->setGeometry(QRect(10, 20, 51, 20));
	QGroupBox* groupBox = new QGroupBox(groupBox_2);
	groupBox->setObjectName(QString::fromUtf8("groupBox"));
	groupBox->setGeometry(QRect(5, 220, 178, 141));
	m_doubleSpinBox_trefoilKnotPathWeight = new QDoubleSpinBox(groupBox);
	m_doubleSpinBox_trefoilKnotPathWeight->setObjectName(QString::fromUtf8("doubleSpinBox_trefoilKnotPathWeight"));
	m_doubleSpinBox_trefoilKnotPathWeight->setGeometry(QRect(120, 110, 49, 20));
	m_doubleSpinBox_trefoilKnotPathWeight->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
	m_doubleSpinBox_trefoilKnotPathWeight->setSingleStep(0.1f);
	QLabel* label_7 = new QLabel(groupBox);
	label_7->setObjectName(QString::fromUtf8("label_7"));
	label_7->setGeometry(QRect(10, 50, 72, 20));
	m_doubleSpinBox_separationWeight = new QDoubleSpinBox(groupBox);
	m_doubleSpinBox_separationWeight->setObjectName(QString::fromUtf8("doubleSpinBox_separationWeight"));
	m_doubleSpinBox_separationWeight->setGeometry(QRect(120, 20, 51, 20));
	m_doubleSpinBox_separationWeight->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
	m_doubleSpinBox_separationWeight->setSingleStep(0.1f);
	QLabel* label_6 = new QLabel(groupBox);
	label_6->setObjectName(QString::fromUtf8("label_6"));
	label_6->setGeometry(QRect(10, 20, 80, 20));
	m_doubleSpinBox_cohesionWeight = new QDoubleSpinBox(groupBox);
	m_doubleSpinBox_cohesionWeight->setObjectName(QString::fromUtf8("doubleSpinBox_cohesionWeight"));
	m_doubleSpinBox_cohesionWeight->setGeometry(QRect(120, 50, 49, 20));
	m_doubleSpinBox_cohesionWeight->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
	m_doubleSpinBox_cohesionWeight->setSingleStep(0.1f);
	m_doubleSpinBox_alignmentWeight = new QDoubleSpinBox(groupBox);
	m_doubleSpinBox_alignmentWeight->setObjectName(QString::fromUtf8("doubleSpinBox_alignmentWeight"));
	m_doubleSpinBox_alignmentWeight->setGeometry(QRect(120, 80, 49, 20));
	m_doubleSpinBox_alignmentWeight->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
	m_doubleSpinBox_alignmentWeight->setSingleStep(0.1f);
	QLabel* label_8 = new QLabel(groupBox);
	label_8->setObjectName(QString::fromUtf8("label_8"));
	label_8->setGeometry(QRect(10, 80, 75, 20));
	QLabel* label_9 = new QLabel(groupBox);
	label_9->setObjectName(QString::fromUtf8("label_9"));
	label_9->setGeometry(QRect(10, 110, 81, 16));
	QGroupBox* groupBox_3 = new QGroupBox(groupBox_2);
	groupBox_3->setObjectName(QString::fromUtf8("groupBox_3"));
	groupBox_3->setGeometry(QRect(5, 120, 178, 81));
	m_doubleSpinBox_groupDistance = new QDoubleSpinBox(groupBox_3);
	m_doubleSpinBox_groupDistance->setObjectName(QString::fromUtf8("doubleSpinBox_groupDistance"));
	m_doubleSpinBox_groupDistance->setGeometry(QRect(130, 50, 45, 20));
	m_doubleSpinBox_groupDistance->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
	m_doubleSpinBox_groupDistance->setSingleStep(0.1f);
	m_doubleSpinBox_separationDistance = new QDoubleSpinBox(groupBox_3);
	m_doubleSpinBox_separationDistance->setObjectName(QString::fromUtf8("doubleSpinBox_separationDistance"));
	m_doubleSpinBox_separationDistance->setGeometry(QRect(130, 20, 45, 20));
	m_doubleSpinBox_separationDistance->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
	m_doubleSpinBox_separationDistance->setSingleStep(0.1f);
	QLabel* label_4 = new QLabel(groupBox_3);
	label_4->setObjectName(QString::fromUtf8("label_4"));
	label_4->setGeometry(QRect(10, 20, 101, 20));
	QLabel* label_5 = new QLabel(groupBox_3);
	label_5->setObjectName(QString::fromUtf8("label_5"));
	label_5->setGeometry(QRect(10, 50, 91, 20));
	QGroupBox* groupBox_7 = new QGroupBox(m_widget);
	groupBox_7->setObjectName(QString::fromUtf8("groupBox_7"));
	groupBox_7->setGeometry(QRect(3, 400, 190, 50));
	QLabel* label = new QLabel(groupBox_7);
	label->setObjectName(QString::fromUtf8("label"));
	label->setGeometry(QRect(10, 20, 78, 16));
	m_spinBox_tasksCount = new QSpinBox(groupBox_7);
	m_spinBox_tasksCount->setObjectName(QString::fromUtf8("spinBox_tasksCount"));
	m_spinBox_tasksCount->setGeometry(QRect(135, 20, 50, 20));
	m_spinBox_tasksCount->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
	m_spinBox_tasksCount->setMinimum(1);
	m_spinBox_tasksCount->setMaximum(999999999);

	groupBox_2->setTitle(QApplication::translate("Settings", "Flock Properties", 0, QApplication::UnicodeUTF8));
	label_3->setText(QApplication::translate("Settings", "Max speed", 0, QApplication::UnicodeUTF8));
	label_10->setText(QApplication::translate("Settings", "Angle increment", 0, QApplication::UnicodeUTF8));
	label_2->setText(QApplication::translate("Settings", "Flock size", 0, QApplication::UnicodeUTF8));
	groupBox->setTitle(QApplication::translate("Settings", "Flock Forces Weights", 0, QApplication::UnicodeUTF8));
	label_7->setText(QApplication::translate("Settings", "Cohesion", 0, QApplication::UnicodeUTF8));
	label_6->setText(QApplication::translate("Settings", "Separation", 0, QApplication::UnicodeUTF8));
	label_8->setText(QApplication::translate("Settings", "Alignment", 0, QApplication::UnicodeUTF8));
	label_9->setText(QApplication::translate("Settings", "TrefoilKnotPath", 0, QApplication::UnicodeUTF8));
	groupBox_3->setTitle(QApplication::translate("Settings", "Distances", 0, QApplication::UnicodeUTF8));
	label_4->setText(QApplication::translate("Settings", "Separation", 0, QApplication::UnicodeUTF8));
	label_5->setText(QApplication::translate("Settings", "Group", 0, QApplication::UnicodeUTF8));
	label->setText(QApplication::translate("Settings", "Number of tasks", 0, QApplication::UnicodeUTF8));
	groupBox_7->setTitle(QApplication::translate("Settings", "Task system", 0, QApplication::UnicodeUTF8));

	QObject::connect(m_spinBox_tasksCount, SIGNAL(valueChanged(int)), this, SLOT(TasksCountChanged(int)));
	QObject::connect(m_spinBox_flockSize, SIGNAL(valueChanged(int)), this, SLOT(SizeChange(int)));
	QObject::connect(m_doubleSpinBox_separationDistance, SIGNAL(valueChanged(double)), this, SLOT(SeparationDistanceChanged(double)));
	QObject::connect(m_doubleSpinBox_groupDistance, SIGNAL(valueChanged(double)), this, SLOT(GroupDistanceChanged(double)));
	QObject::connect(m_doubleSpinBox_separationWeight, SIGNAL(valueChanged(double)), this, SLOT(SeparationWeightChanged(double)));
	QObject::connect(m_doubleSpinBox_cohesionWeight, SIGNAL(valueChanged(double)), this, SLOT(CohesionWeightChanged(double)));
	QObject::connect(m_doubleSpinBox_alignmentWeight, SIGNAL(valueChanged(double)), this, SLOT(AlignmentWeightChanged(double)));
	QObject::connect(m_doubleSpinBox_maxSpeed, SIGNAL(valueChanged(double)), this, SLOT(MaxSpeedChanged(double)));
	QObject::connect(m_doubleSpinBox_trefoilKnotPathWeight, SIGNAL(valueChanged(double)), this, SLOT(TrefoildKnotPathWeightChanged(double)));
	QObject::connect(m_doubleSpinBox_angleIncrement, SIGNAL(valueChanged(double)), this, SLOT(AlignmentWeightChanged(double)));
}

void SettingsTab::LoadDefaultSceneParameters(const TestFrameWork::ScenePtr scene)
{
	m_spinBox_flockSize->blockSignals(true);
	m_doubleSpinBox_separationDistance->blockSignals(true);
	m_doubleSpinBox_groupDistance->blockSignals(true);
	m_doubleSpinBox_separationWeight->blockSignals(true);
	m_doubleSpinBox_cohesionWeight->blockSignals(true);
	m_doubleSpinBox_alignmentWeight->blockSignals(true);
	m_doubleSpinBox_maxSpeed->blockSignals(true);
	m_doubleSpinBox_trefoilKnotPathWeight->blockSignals(true);
	m_doubleSpinBox_angleIncrement->blockSignals(true);
	m_spinBox_tasksCount->blockSignals(true);

	const TestScenePtr testScene(boost::shared_polymorphic_downcast<TestScene>(scene));

	size_t tasksCount = testScene->GetTasksCount();
	int tt = static_cast<int>(tasksCount);
	m_spinBox_tasksCount->setValue(tt);

	const Flock& flock = testScene->GetFlock();

	m_doubleSpinBox_angleIncrement->setValue(static_cast<float>(flock.GetAngleIncrement()));
	m_doubleSpinBox_separationWeight->setValue(static_cast<float>(flock.GetSeparationWeight()));
	m_doubleSpinBox_cohesionWeight->setValue(static_cast<float>(flock.GetCohesionWeight()));
	m_doubleSpinBox_alignmentWeight->setValue(static_cast<float>(flock.GetAlignmentWeight()));
	m_doubleSpinBox_trefoilKnotPathWeight->setValue(static_cast<float>(flock.GetTrefoilKnotPathWeight()));

	m_spinBox_flockSize->setValue(static_cast<int>(flock.GetBoidsCount()));
	m_spinBox_flockSize->setMinimum(1);
	m_spinBox_flockSize->setMaximum(static_cast<int>(flock.GetMaxSize()));

	m_doubleSpinBox_maxSpeed->setValue(static_cast<float>(flock.GetMaxSpeed().m_x));

	m_doubleSpinBox_separationDistance->setValue(static_cast<float>(flock.GetSeparationDistance()));

	m_doubleSpinBox_groupDistance->setValue(static_cast<float>(flock.GetGroupDistance()));

	m_spinBox_flockSize->blockSignals(false);
	m_doubleSpinBox_separationDistance->blockSignals(false);
	m_doubleSpinBox_groupDistance->blockSignals(false);
	m_doubleSpinBox_separationWeight->blockSignals(false);
	m_doubleSpinBox_cohesionWeight->blockSignals(false);
	m_doubleSpinBox_alignmentWeight->blockSignals(false);
	m_doubleSpinBox_maxSpeed->blockSignals(false);
	m_doubleSpinBox_trefoilKnotPathWeight->blockSignals(false);
	m_doubleSpinBox_angleIncrement->blockSignals(false);
	m_spinBox_tasksCount->blockSignals(false);
}

void SettingsTab::TasksCountChanged(int i)
{
	m_eventQueue.Push(ValueChangedEventPtr(new ValueChangedEvent(i, TasksCount)));
}

void SettingsTab::SizeChange(int val)
{
	m_eventQueue.Push(ValueChangedEventPtr(new ValueChangedEvent(val, FlockSize)));
}

void SettingsTab::AngleIncrementChanged(double val)
{
	m_eventQueue.Push(ValueChangedEventPtr(new ValueChangedEvent(val, AngleIncrement)));
}

void SettingsTab::SeparationWeightChanged(double val)
{
	m_eventQueue.Push(ValueChangedEventPtr(new ValueChangedEvent(val, SeparationWeight)));
}

void SettingsTab::CohesionWeightChanged(double val)
{
	m_eventQueue.Push(ValueChangedEventPtr(new ValueChangedEvent(val, CohesionWeight)));
}

void SettingsTab::AlignmentWeightChanged(double val)
{
	m_eventQueue.Push(ValueChangedEventPtr(new ValueChangedEvent(val, AlignmentWeight)));
}

void SettingsTab::TrefoildKnotPathWeightChanged(double val)
{
	m_eventQueue.Push(ValueChangedEventPtr(new ValueChangedEvent(val, TrefoilKnotPathWeight)));
}

void SettingsTab::MaxSpeedChanged(double val)
{
	m_eventQueue.Push(ValueChangedEventPtr(new ValueChangedEvent(val, MaxSpeed)));
}

void SettingsTab::SeparationDistanceChanged(double val)
{
	m_eventQueue.Push(ValueChangedEventPtr(new ValueChangedEvent(val, SeparationDistance)));
}

void SettingsTab::GroupDistanceChanged(double val)
{
	m_eventQueue.Push(ValueChangedEventPtr(new ValueChangedEvent(val, GroupDistance)));
}