#include "androidsWidget.h"
#include <random>
#include <cmath>
#include "softProj\settings.h"

void AndroidsWidget::initDevice(AndroidsSectionWidget * widget, ESectionType sectionType, const std::wstring & name, const std::string & iconPath) {
	widget->setSectionIcon(iconPath);
	widget->setSectionName(name);
	widget->setBackgroundsHolder(backgroundsHolder_);

	devices_.insert(std::pair<ESectionType, AndroidsSectionWidget *>(sectionType, widget));
}

void AndroidsWidget::lockForUpdate(bool lock) {
	isLockedForUpdate_ = lock;

	if (lock) {
		ui_.androidsSection->setAsChanged();
		ui_.unmountButton->setEnabled(false);
	}
	else {
		ui_.androidsSection->setAsNormal();
		ui_.unmountButton->setEnabled(true);
	}
}

void AndroidsWidget::setCommonAndroidsState(androids_status & state) {
	rememberUpdateTime();

	backgroundsHolder_->setLimits(state.androidsMinPriority, state.androidsMaxPriority);

	ui_.totalPartitionSlider->setValues(state.clientAndroidsStateSliderBackground, state.clientAndroidsStateSliderMax - state.clientAndroidsStateSliderBackground);

	ui_.totalPartitionCopySlider->setValues(state.clientWorkingAndroidsSliderBackground, state.clientAndroidsStateSliderMax - state.clientWorkingAndroidsSliderBackground);
	ui_.ablePartitionSlider->setValues(state.clientWorkingAndroidsSliderValue, state.clientAndroidsStateSliderMax - state.clientWorkingAndroidsSliderValue);

	ui_.ablePartitionCopySlider->setValues(state.clientRepConSliderBackground, max(0, state.clientWorkingAndroidsSliderValue - state.clientRepConSliderBackground));
	ui_.workingPartitionSlider->setValues(state.clientRepConSliderValue, state.clientRepConSliderMax - state.clientRepConSliderValue);	
}

void AndroidsWidget::getCommonAndroidsState(androids_request_status & state) {
	state.workingAndroidsSlider = ui_.ablePartitionSlider->getValue();
	state.repConSlider = ui_.workingPartitionSlider->getValue();
}

void AndroidsWidget::setState(ship_androids_status & state) {	
	state_ = ANDROIDS_STATE_SHIP;

	if (!isLockedForUpdate_) {
		shipState_ = state;

		setCommonAndroidsState(state);
		
		ui_.shipMasking->setState(state.cloaking, state);
		ui_.shipShields->setState(state.deflectorShields, state);
		ui_.shipEnergeticAccumulator->setState(state.energeticSystem, state);
		ui_.shipMainframe->setState(state.mainframeSystem, state);
		ui_.shipAndroids->setState(state.mechanics, state);
		ui_.shipQuarrying->setState(state.miningDevices, state);
		ui_.shipEquipment->setState(state.otherEquipment, state);
		ui_.shipProbes->setState(state.probeDevices, state);
		ui_.shipSensors->setState(state.sensors, state);	
		ui_.shipTransport->setState(state.transportBeam, state);
		ui_.shipWarehouses->setState(state.warehouse, state);
		ui_.shipWeapons->setState(state.weapons, state);
		ui_.shipStructuralIngegrity->setState(state.structuralIntegrity, state);
		ui_.shipImpulsDrive->setState(state.impulsDrive, state);
		ui_.shipSubspaceDrive->setState(state.subspaceDrive, state);

		ui_.shipRepairingValue->setText(Settings::instance().formatNumber(state.actualRepairingAndroids));
		ui_.shipConstructingValue->setText(Settings::instance().formatNumber(state.actualConstructingAndroids));
		ui_.shipWorkingValue->setText(Settings::instance().formatNumber(state.actualWorkingAndroids));

		ui_.sectionsWidget->setCurrentWidget(ui_.shipSectionsPage);

		lockForUpdate(false);
	}
}

void AndroidsWidget::setState(base_androids_status & state) {
	state_ = ANDROIDS_STATE_BASE;

	if (!isLockedForUpdate_) {		
		baseState_ = state;

		setCommonAndroidsState(state);
		ui_.baseMasking->setState(state.cloaking, state);
		ui_.baseShields->setState(state.deflectorShields, state);
		ui_.baseEnergeticAccumulator->setState(state.energeticSystem, state);
		ui_.baseMainframe->setState(state.mainframeSystem, state);
		ui_.baseAndroids->setState(state.mechanics, state);
		ui_.baseQuarrying->setState(state.miningDevices, state);
		ui_.baseEquipment->setState(state.otherEquipment, state);
		ui_.baseProbes->setState(state.probeDevices, state);
		ui_.baseSensors->setState(state.sensors, state);	
		ui_.baseTransport->setState(state.transportBeam, state);
		ui_.baseWarehouses->setState(state.warehouse, state);
		ui_.baseWeapons->setState(state.weapons, state);
		ui_.baseStructuralIngegrity->setState(state.structuralIntegrity, state);

		ui_.baseFactories->setState(state.factories, state);
		ui_.baseHangars->setState(state.hangars, state);

		ui_.baseRepairingValue->setText(Settings::instance().formatNumber(state.actualRepairingAndroids));
		ui_.baseConstructingValue->setText(Settings::instance().formatNumber(state.actualConstructingAndroids));
		ui_.baseWorkingValue->setText(Settings::instance().formatNumber(state.actualWorkingAndroids));

		ui_.sectionsWidget->setCurrentWidget(ui_.baseSectionsPage);

		lockForUpdate(false);
	}
}

void AndroidsWidget::settingsChangedSlot() {
	lockForUpdate(true);
}

void AndroidsWidget::submitSlot(bool checked) {
	lockForUpdate(false);	

	if (state_ == ANDROIDS_STATE_SHIP) {
		ship_androids_request_status state;

		getCommonAndroidsState(state);

		state.cloaking = ui_.shipMasking->getState();
		state.deflectorShields = ui_.shipShields->getState();
		state.energeticSystem = ui_.shipEnergeticAccumulator->getState();
		state.mainframeSystem = ui_.shipMainframe->getState();
		state.mechanics = ui_.shipAndroids->getState();
		state.miningDevices = ui_.shipQuarrying->getState();
		state.otherEquipment = ui_.shipEquipment->getState();
		state.probeDevices = ui_.shipProbes->getState();
		state.sensors = ui_.shipSensors->getState();	
		state.transportBeam = ui_.shipTransport->getState();
		state.warehouse = ui_.shipWarehouses->getState();
		state.weapons = ui_.shipWeapons->getState();
		state.structuralIntegrity = ui_.shipStructuralIngegrity->getState();

		state.impulsDrive = ui_.shipImpulsDrive->getState();
		state.subspaceDrive = ui_.shipSubspaceDrive->getState();

		emit androidsShipSubmitSignal(state);
	}
	else if (state_ == ANDROIDS_STATE_BASE) {
		base_androids_request_status state;

		getCommonAndroidsState(state);

		state.cloaking = ui_.baseMasking->getState();
		state.deflectorShields = ui_.baseShields->getState();
		state.energeticSystem = ui_.baseEnergeticAccumulator->getState();
		state.mainframeSystem = ui_.baseMainframe->getState();
		state.mechanics = ui_.baseAndroids->getState();
		state.miningDevices = ui_.baseQuarrying->getState();
		state.otherEquipment = ui_.baseEquipment->getState();
		state.probeDevices = ui_.baseProbes->getState();
		state.sensors = ui_.baseSensors->getState();	
		state.transportBeam = ui_.baseTransport->getState();
		state.warehouse = ui_.baseWarehouses->getState();
		state.weapons = ui_.baseWeapons->getState();
		state.structuralIntegrity = ui_.baseStructuralIngegrity->getState();

		state.factories = ui_.baseFactories->getState();
		state.hangars = ui_.baseHangars->getState();

		emit androidsBaseSubmitSignal(state);
	}
}

void AndroidsWidget::cancelSlot(bool checked) {
	lockForUpdate(false);

	if (state_ == ANDROIDS_STATE_SHIP) {
		emit androidsShipResetSignal();
	}
	else if (state_ == ANDROIDS_STATE_BASE) {
		emit androidsBaseResetSignal();
	}
}

AndroidsWidget::AndroidsWidget(QWidget * parent) : NotifyWidget(parent) {
	ui_.setupUi(this);	

	QTime midnight(0, 0, 0);
	qsrand(midnight.secsTo(QTime::currentTime()));	

	backgroundsHolder_ = new DeviceBackgroundsHolder();

	state_ = ANDROIDS_STATE_NONE;

	ui_.totalPartitionSlider->setLeftText(L"Nepoškození androidi");
	ui_.totalPartitionSlider->setRightText(L"Poškození androidi");

	ui_.ablePartitionSlider->setLeftText(L"Pracující androidi");
	ui_.ablePartitionSlider->setRightText(L"Nepracující androidi");

	ui_.workingPartitionSlider->setLeftText(L"Androidi na opravu");
	ui_.workingPartitionSlider->setRightText(L"Androidi na konstrukci");

	ui_.totalPartitionCopySlider->setShowText(false);
	ui_.ablePartitionCopySlider->setShowText(false);

	ui_.totalPartitionSlider->setValues(500, 500);
	ui_.totalPartitionCopySlider->setValues(500, 500);
	ui_.ablePartitionSlider->setValues(300, 200);
	ui_.ablePartitionCopySlider->setValues(300, 200);
	ui_.workingPartitionSlider->setValues(150, 150);

	ui_.androidsSection->setName(L"Androidi");

	bool ok = true;
	
	ok = ok && QObject::connect(ui_.androidsSection->submitButton, SIGNAL(clicked(bool)), this, SLOT(submitSlot(bool)));
	ok = ok && QObject::connect(ui_.androidsSection->cancelButton, SIGNAL(clicked(bool)), this, SLOT(cancelSlot(bool)));

	ok = ok && connect(ui_.ablePartitionSlider, SIGNAL(valueChangedSignal(unsigned long long)), this, SLOT(androidsAbleSliderChangedSlot(unsigned long long)));

	ok = ok && connect(ui_.ablePartitionSlider, SIGNAL(valueChangedSignal(unsigned long long)), this, SLOT(settingsChangedSlot()));
	ok = ok && connect(ui_.workingPartitionSlider, SIGNAL(valueChangedSignal(unsigned long long)), this, SLOT(settingsChangedSlot()));

	/* Ship */

	initDevice(ui_.shipStructuralIngegrity, ANDROIDS_SECTION_STRUCTURAL_INTEGRITY, L"Strukturální integrita", ":/pictures/images/others/shuttle-icon.png");
	initDevice(ui_.shipEnergeticAccumulator, ANDROIDS_SECTION_ENERGETIC_ACCUMULATOR, L"Energetický akumulátor", ":/pictures/images/others/energyCircuit.png");
	initDevice(ui_.shipShields, ANDROIDS_SECTION_SHIELDS, L"Štíty", ":/pictures/images/details/stity.png");
	initDevice(ui_.shipWeapons, ANDROIDS_SECTION_WEAPONS, L"Zbraňě",  ":/pictures/images/details/zbrane.png");

	initDevice(ui_.shipTransport, ANDROIDS_SECTION_TRANSPORT, L"Transportní\npaprsek",  ":/pictures/images/details/transport.png");
	initDevice(ui_.shipQuarrying, ANDROIDS_SECTION_QUARRYING, L"Těžební zařízení",  ":/pictures/images/details/mining.png");
	initDevice(ui_.shipProbes, ANDROIDS_SECTION_PROBES, L"Sondy",  ":/pictures/images/details/pruzkum.png");
	initDevice(ui_.shipSensors, ANDROIDS_SECTION_SENSORS, L"Senzory",  ":/pictures/images/details/senzory.png");

	initDevice(ui_.shipMasking, ANDROIDS_SECTION_MASKING, L"Maskování",  ":/pictures/images/details/maskovani.png");
	initDevice(ui_.shipAndroids, ANDROIDS_SECTION_ANDROIDS, L"Androidi",  ":/pictures/images/details/androidi.png");
	initDevice(ui_.shipWarehouses, ANDROIDS_SECTION_WAREHOUSES, L"Sklady",  ":/pictures/images/details/sklady.png");
	initDevice(ui_.shipMainframe, ANDROIDS_SECTION_MAINFRAME, L"Mainframe",  ":/pictures/images/details/pocitac.png");

	initDevice(ui_.shipEquipment, ANDROIDS_SECTION_EQUIPMENT, L"Vybavení",  ":/pictures/images/details/vybaveni.png");
	initDevice(ui_.shipImpulsDrive, ANDROIDS_SECTION_IMPULS_DRIVE, L"Impuzlní pohon",  ":/pictures/images/details/zakladniPohon.png");
	initDevice(ui_.shipSubspaceDrive, ANDROIDS_SECTION_SUBSPACE_DRIVE, L"Podprostorový pohon",  ":/pictures/images/details/podprostorovyPohon.png");

	ok = ok && connect(ui_.shipAndroids, SIGNAL(settingsChangedSignal()), this, SLOT(settingsChangedSlot()));
	ok = ok && connect(ui_.shipEnergeticAccumulator, SIGNAL(settingsChangedSignal()), this, SLOT(settingsChangedSlot()));
	ok = ok && connect(ui_.shipEquipment, SIGNAL(settingsChangedSignal()), this, SLOT(settingsChangedSlot()));
	ok = ok && connect(ui_.shipImpulsDrive, SIGNAL(settingsChangedSignal()), this, SLOT(settingsChangedSlot()));
	ok = ok && connect(ui_.shipMainframe, SIGNAL(settingsChangedSignal()), this, SLOT(settingsChangedSlot()));
	ok = ok && connect(ui_.shipMasking, SIGNAL(settingsChangedSignal()), this, SLOT(settingsChangedSlot()));
	ok = ok && connect(ui_.shipProbes, SIGNAL(settingsChangedSignal()), this, SLOT(settingsChangedSlot()));
	ok = ok && connect(ui_.shipQuarrying, SIGNAL(settingsChangedSignal()), this, SLOT(settingsChangedSlot()));
	ok = ok && connect(ui_.shipSensors, SIGNAL(settingsChangedSignal()), this, SLOT(settingsChangedSlot()));
	ok = ok && connect(ui_.shipShields, SIGNAL(settingsChangedSignal()), this, SLOT(settingsChangedSlot()));
	ok = ok && connect(ui_.shipStructuralIngegrity, SIGNAL(settingsChangedSignal()), this, SLOT(settingsChangedSlot()));
	ok = ok && connect(ui_.shipSubspaceDrive, SIGNAL(settingsChangedSignal()), this, SLOT(settingsChangedSlot()));
	ok = ok && connect(ui_.shipTransport, SIGNAL(settingsChangedSignal()), this, SLOT(settingsChangedSlot()));
	ok = ok && connect(ui_.shipWarehouses, SIGNAL(settingsChangedSignal()), this, SLOT(settingsChangedSlot()));
	ok = ok && connect(ui_.shipWeapons, SIGNAL(settingsChangedSignal()), this, SLOT(settingsChangedSlot()));

	ok = ok && connect(ui_.unmountButton, SIGNAL(clicked(bool)), this, SLOT(unmountButtonClickedSlot(bool)));

	/* Base */

	initDevice(ui_.baseStructuralIngegrity, ANDROIDS_SECTION_STRUCTURAL_INTEGRITY, L"Strukturální integrita", ":/pictures/images/others/shuttle-icon.png");
	initDevice(ui_.baseEnergeticAccumulator, ANDROIDS_SECTION_ENERGETIC_ACCUMULATOR, L"Energetický akumulátor", ":/pictures/images/others/energyCircuit.png");
	initDevice(ui_.baseShields, ANDROIDS_SECTION_SHIELDS, L"Štíty", ":/pictures/images/details/stity.png");
	initDevice(ui_.baseWeapons, ANDROIDS_SECTION_WEAPONS, L"Zbraňě",  ":/pictures/images/details/zbrane.png");
				   
	initDevice(ui_.baseTransport, ANDROIDS_SECTION_TRANSPORT, L"Transportní\npaprsek",  ":/pictures/images/details/transport.png");
	initDevice(ui_.baseQuarrying, ANDROIDS_SECTION_QUARRYING, L"Těžební zařízení",  ":/pictures/images/details/mining.png");
	initDevice(ui_.baseProbes, ANDROIDS_SECTION_PROBES, L"Sondy",  ":/pictures/images/details/pruzkum.png");
	initDevice(ui_.baseSensors, ANDROIDS_SECTION_SENSORS, L"Senzory",  ":/pictures/images/details/senzory.png");
				   
	initDevice(ui_.baseMasking, ANDROIDS_SECTION_MASKING, L"Maskování",  ":/pictures/images/details/maskovani.png");
	initDevice(ui_.baseAndroids, ANDROIDS_SECTION_ANDROIDS, L"Androidi",  ":/pictures/images/details/androidi.png");
	initDevice(ui_.baseWarehouses, ANDROIDS_SECTION_WAREHOUSES, L"Sklady",  ":/pictures/images/details/sklady.png");
	initDevice(ui_.baseMainframe, ANDROIDS_SECTION_MAINFRAME, L"Mainframe",  ":/pictures/images/details/pocitac.png");
				 
	initDevice(ui_.baseEquipment, ANDROIDS_SECTION_EQUIPMENT, L"Vybavení", ":/pictures/images/details/vybaveni.png");
	initDevice(ui_.baseHangars, ANDROIDS_SECTION_HANGARS, L"Hangáry", ":/pictures/images/others/hangary.png");
	initDevice(ui_.baseFactories, ANDROIDS_SECTION_FACTORIES, L"Továrny",":/pictures/images/details/tovarny.png");	

	ok = ok && connect(ui_.baseAndroids, SIGNAL(settingsChangedSignal()), this, SLOT(settingsChangedSlot()));
	ok = ok && connect(ui_.baseEnergeticAccumulator, SIGNAL(settingsChangedSignal()), this, SLOT(settingsChangedSlot()));
	ok = ok && connect(ui_.baseEquipment, SIGNAL(settingsChangedSignal()), this, SLOT(settingsChangedSlot()));
	ok = ok && connect(ui_.baseFactories, SIGNAL(settingsChangedSignal()), this, SLOT(settingsChangedSlot()));
	ok = ok && connect(ui_.baseHangars, SIGNAL(settingsChangedSignal()), this, SLOT(settingsChangedSlot()));	
	ok = ok && connect(ui_.baseMainframe, SIGNAL(settingsChangedSignal()), this, SLOT(settingsChangedSlot()));
	ok = ok && connect(ui_.baseMasking, SIGNAL(settingsChangedSignal()), this, SLOT(settingsChangedSlot()));
	ok = ok && connect(ui_.baseProbes, SIGNAL(settingsChangedSignal()), this, SLOT(settingsChangedSlot()));
	ok = ok && connect(ui_.baseQuarrying, SIGNAL(settingsChangedSignal()), this, SLOT(settingsChangedSlot()));
	ok = ok && connect(ui_.baseSensors, SIGNAL(settingsChangedSignal()), this, SLOT(settingsChangedSlot()));
	ok = ok && connect(ui_.baseShields, SIGNAL(settingsChangedSignal()), this, SLOT(settingsChangedSlot()));
	ok = ok && connect(ui_.baseStructuralIngegrity, SIGNAL(settingsChangedSignal()), this, SLOT(settingsChangedSlot()));	
	ok = ok && connect(ui_.baseTransport, SIGNAL(settingsChangedSignal()), this, SLOT(settingsChangedSlot()));
	ok = ok && connect(ui_.baseWarehouses, SIGNAL(settingsChangedSignal()), this, SLOT(settingsChangedSlot()));
	ok = ok && connect(ui_.baseWeapons, SIGNAL(settingsChangedSignal()), this, SLOT(settingsChangedSlot()));

	assert(ok && "Signals not connected");

	lockForUpdate(false);
}

void AndroidsWidget::androidsAbleSliderChangedSlot(unsigned long long value) {
	unsigned long long oldTotal = ui_.workingPartitionSlider->getMaximum();
	unsigned long long oldRepairing = ui_.workingPartitionSlider->getValue();
	unsigned long long oldConstructing = oldTotal - oldRepairing;

	long long addition = value - oldTotal;
	
	// If addition is odd, oneRest will be one, so when we subtract it from
	// addition, addition will be even. Otherwise, if addition is event, then 
	// oneRest is zero and addition will still be even
	long long oneRest = addition % 2;
	addition = addition - oneRest;

	unsigned long long newRepairing = oldRepairing + addition / 2;	

	// If addition was odd, we randomly add either repairing or constructing. 
	// If we add repairing, it is done, otherwise we do not add constructing 
	// directly, because it will be added anyway since it is the rest to total
	// and we did not add to repairing
	if (oneRest != 0) {
		if (qrand() % 2 == 0) {
			newRepairing += oneRest;
		}
	}

	unsigned long long newConstructing = value - newRepairing;
	
	unsigned long long notDamaged = ui_.totalPartitionSlider->getValue();
	ui_.workingPartitionSlider->setValues(newRepairing, newConstructing);	
	ui_.ablePartitionCopySlider->setValues(notDamaged, max(0, ui_.ablePartitionSlider->getValue() - notDamaged));
}

void AndroidsWidget::unmountButtonClickedSlot(bool checked) {
	 if (state_ == ANDROIDS_STATE_SHIP) {
		 emit unmountSignal(PROTOCOL_HANGARS_PATTERN_ID_ANDROIDS, shipState_.clientAndroidsStateSliderBackground, shipState_.clientAndroidsStateSliderMax - shipState_.clientAndroidsStateSliderBackground);
	 }
	 else if (state_ == ANDROIDS_STATE_BASE) {
		 emit unmountSignal(PROTOCOL_HANGARS_PATTERN_ID_ANDROIDS, baseState_.clientAndroidsStateSliderBackground, baseState_.clientAndroidsStateSliderMax - baseState_.clientAndroidsStateSliderBackground);
	 }
}

AndroidsWidget::~AndroidsWidget() {
	for (std::map<ESectionType, AndroidsSectionWidget *>::iterator it = devices_.begin(); it != devices_.end(); ++it) {
		delete it->second;
	}

	delete backgroundsHolder_;
}

