/**
 * @brief Update the display of building space for all researched facilities
 * @sa B_BaseInit_f
 */
static void B_BuildingSpace_f (void)
{
	int i;
	base_t *base = B_GetCurrentSelectedBase();

	if (!base)
		return;

	// Clear existing entries from the UI panel
	cgi->UI_ExecuteConfunc("clear_bld_space");
	for (i = 0; i < ccs.numBuildingTemplates; i++) {
		const building_t* b = &ccs.buildingTemplates[i];
		const baseCapacities_t capType = B_GetCapacityFromBuildingType(b->buildingType);
		capacities_t cap;

		/* skip mandatory buildings (like Entrance) which are built automatically */
		if (b->mandatory)
			continue;
		/* only show already researched buildings */
		if (!RS_IsResearched_ptr(b->tech))
			continue;

		if (capType != MAX_CAP)
			cap = *CAP_Get(base, capType);
		else
			OBJZERO(cap);

		assert(b->tpl);
		const int count = B_GetNumberOfBuildingsInBaseByTemplate(base, b->tpl);

		cgi->UI_ExecuteConfunc("show_bld_space \"%s\" \"%s\" %i %i %i %i", _(b->name), b->id, cap.cur, cap.max, count, b->tpl->maxCount);
	}
}
/**
 * @brief Base Summary menu init function.
 * @note Should be called whenever the Base Summary menu gets active.
 */
static void BaseSummary_Init (const base_t *base)
{
	static char textStatsBuffer[1024];
	static char textInfoBuffer[256];
	const aliensCont_t *containment = base->alienscont;
	int i;

	baseCapacities_t cap;
	const production_queue_t *queue;
	const technology_t *tech;
	int tmp;

	/* wipe away old buffers */
	textStatsBuffer[0] = textInfoBuffer[0] = 0;

	Q_strcat(textInfoBuffer, _("^BAircraft\n"), sizeof(textInfoBuffer));
	for (i = 0; i <= MAX_HUMAN_AIRCRAFT_TYPE; i++) {
		const aircraftType_t airType = (aircraftType_t)i;
		const int count = AIR_CountTypeInBase(base, airType);
		if (count == 0)
			continue;

		Q_strcat(textInfoBuffer, va("\t%s:\t\t\t\t%i\n", AIR_GetAircraftString(airType),
			count), sizeof(textInfoBuffer));
	}

	Q_strcat(textInfoBuffer, "\n", sizeof(textInfoBuffer));

	Q_strcat(textInfoBuffer, _("^BEmployees\n"), sizeof(textInfoBuffer));
	for (i = 0; i < MAX_EMPL; i++) {
		const employeeType_t emplType = (employeeType_t)i;
		tmp = E_CountHired(base, emplType);

		if (tmp == 0)
			continue;

		Q_strcat(textInfoBuffer, va("\t%s:\t\t\t\t%i\n", E_GetEmployeeString(emplType, tmp), tmp), sizeof(textInfoBuffer));
	}

	Q_strcat(textInfoBuffer, "\n", sizeof(textInfoBuffer));

	Q_strcat(textInfoBuffer, _("^BAliens\n"), sizeof(textInfoBuffer));
	for (i = 0; i < ccs.numAliensTD; i++) {
		if (!containment[i].amountAlive && !containment[i].amountDead)
			continue;
		Q_strcat(textInfoBuffer, va("\t%s:\t\t\t\t%i/%i\n",
			_(containment[i].teamDef->name), containment[i].amountAlive,
			containment[i].amountDead), sizeof(textInfoBuffer));
	}

	/* link into the menu */
	cgi->UI_RegisterText(TEXT_STANDARD, textInfoBuffer);

	Q_strcat(textStatsBuffer, _("^BBuildings\t\t\t\t\t\tCapacity\t\t\t\tAmount\n"), sizeof(textStatsBuffer));
	for (i = 0; i < ccs.numBuildingTemplates; i++) {
		const building_t* b = &ccs.buildingTemplates[i];

		/* only show already researched buildings */
		if (!RS_IsResearched_ptr(b->tech))
			continue;

		cap = B_GetCapacityFromBuildingType(b->buildingType);
		if (cap == MAX_CAP)
			continue;

		if (!B_GetNumberOfBuildingsInBaseByBuildingType(base, b->buildingType))
			continue;

		/* Check if building is functional (see comments in B_UpdateBaseCapacities) */
		if (B_GetBuildingStatus(base, b->buildingType)) {
			Q_strcat(textStatsBuffer, va("%s:\t\t\t\t\t\t%i/%i", _(b->name),
				CAP_GetCurrent(base, cap), CAP_GetMax(base, cap)), sizeof(textStatsBuffer));
		} else {
			if (b->buildingStatus == B_STATUS_UNDER_CONSTRUCTION) {
				const float remaining = B_GetConstructionTimeRemain(b);
				const float timeLeft = std::max(0.0f, remaining);
				Q_strcat(textStatsBuffer, va("%s:\t\t\t\t\t\t%3.1f %s", _(b->name), timeLeft, ngettext("day", "days", timeLeft)), sizeof(textStatsBuffer));
			} else {
				Q_strcat(textStatsBuffer, va("%s:\t\t\t\t\t\t%i/%i", _(b->name), CAP_GetCurrent(base, cap), 0), sizeof(textStatsBuffer));
			}
		}
		Q_strcat(textStatsBuffer, va("\t\t\t\t%i\n", B_GetNumberOfBuildingsInBaseByBuildingType(base, b->buildingType)), sizeof(textStatsBuffer));
	}

	Q_strcat(textStatsBuffer, "\n", sizeof(textStatsBuffer));

	Q_strcat(textStatsBuffer, _("^BProduction\t\t\t\t\t\tQuantity\t\t\t\tPercent\n"), sizeof(textStatsBuffer));
	queue = PR_GetProductionForBase(base);
	if (queue->numItems > 0) {
		for (i = 0; i < queue->numItems; i++) {
			const production_t *production = &queue->items[i];
			const char *name = PR_GetName(&production->data);
			/** @todo use the same method as we do in PR_ProductionInfo */
			Q_strcat(textStatsBuffer, va(_("%s\t\t\t\t\t\t%d\t\t\t\t%.2f%%\n"), name,
				production->amount, PR_GetProgress(production) * 100), sizeof(textStatsBuffer));
		}
	} else {
		Q_strcat(textStatsBuffer, _("Nothing\n"), sizeof(textStatsBuffer));
	}

	Q_strcat(textStatsBuffer, "\n", sizeof(textStatsBuffer));

	Q_strcat(textStatsBuffer, _("^BResearch\t\t\t\t\t\tScientists\t\t\t\tPercent\n"), sizeof(textStatsBuffer));
	tmp = 0;
	for (i = 0; i < ccs.numTechnologies; i++) {
		tech = RS_GetTechByIDX(i);
		if (tech->base == base && (tech->statusResearch == RS_RUNNING || tech->statusResearch == RS_PAUSED)) {
			Q_strcat(textStatsBuffer, va(_("%s\t\t\t\t\t\t%d\t\t\t\t%1.2f%%\n"), _(tech->name),
				tech->scientists, (1 - tech->time / tech->overallTime) * 100), sizeof(textStatsBuffer));
			tmp++;
		}
	}
	if (!tmp)
		Q_strcat(textStatsBuffer, _("Nothing\n"), sizeof(textStatsBuffer));

	/* link into the menu */
	cgi->UI_RegisterText(TEXT_STATS_BASESUMMARY, textStatsBuffer);
}
/**
 * @brief Mark a building for destruction - you only have to confirm it now
 * @param[in] building Pointer to the base to destroy
 */
static void B_MarkBuildingDestroy (building_t* building)
{
	baseCapacities_t cap;
	base_t *base = building->base;

	/* you can't destroy buildings if base is under attack */
	if (B_IsUnderAttack(base)) {
		CP_Popup(_("Notice"), _("Base is under attack, you can't destroy buildings!"));
		return;
	}

	cap = B_GetCapacityFromBuildingType(building->buildingType);
	/* store the pointer to the building you wanna destroy */
	base->buildingCurrent = building;

	/** @todo: make base destroyable by destroying entrance */
	if (building->buildingType == B_ENTRANCE) {
		CP_Popup(_("Destroy Entrance"), _("You can't destroy the entrance of the base!"));
		return;
	}

	if (!B_IsBuildingDestroyable(building)) {
			CP_Popup(_("Notice"), _("You can't destroy this building! It is the only connection to other buildings!"));
			return;
	}

	if (building->buildingStatus == B_STATUS_WORKING) {
		const bool hasMoreBases = B_GetCount() > 1;
		switch (building->buildingType) {
		case B_HANGAR:
		case B_SMALL_HANGAR:
			if (CAP_GetFreeCapacity(base, cap) <= 0) {
				cgi->UI_PopupButton(_("Destroy Hangar"), _("If you destroy this hangar, you will also destroy the aircraft inside.\nAre you sure you want to destroy this building?"),
					"ui_pop;ui_push aircraft;aircraft_select;", _("Go to hangar"), _("Go to hangar without destroying building"),
					va("building_destroy %i %i confirmed; ui_pop;", base->idx, building->idx), _("Destroy"), _("Destroy the building"),
					hasMoreBases ? "ui_pop;ui_push transfer;" : NULL, hasMoreBases ? _("Transfer") : NULL,
					_("Go to transfer menu without destroying the building"));
				return;
			}
			break;
		case B_QUARTERS:
			if (CAP_GetFreeCapacity(base, cap) < building->capacity) {
				cgi->UI_PopupButton(_("Destroy Quarter"), _("If you destroy this Quarters, every employee inside will be killed.\nAre you sure you want to destroy this building?"),
					"ui_pop;ui_push employees;employee_list 0;", _("Dismiss"), _("Go to hiring menu without destroying building"),
					va("building_destroy %i %i confirmed; ui_pop;", base->idx, building->idx), _("Destroy"), _("Destroy the building"),
					hasMoreBases ? "ui_pop;ui_push transfer;" : NULL, hasMoreBases ? _("Transfer") : NULL,
					_("Go to transfer menu without destroying the building"));
				return;
			}
			break;
		case B_STORAGE:
			if (CAP_GetFreeCapacity(base, cap) < building->capacity) {
				cgi->UI_PopupButton(_("Destroy Storage"), _("If you destroy this Storage, every items inside will be destroyed.\nAre you sure you want to destroy this building?"),
					"ui_pop;ui_push market;buy_type *mn_itemtype", _("Go to storage"), _("Go to buy/sell menu without destroying building"),
					va("building_destroy %i %i confirmed; ui_pop;", base->idx, building->idx), _("Destroy"), _("Destroy the building"),
					hasMoreBases ? "ui_pop;ui_push transfer;" : NULL, hasMoreBases ? _("Transfer") : NULL,
					_("Go to transfer menu without destroying the building"));
				return;
			}
			break;
		default:
			break;
		}
	}

	cgi->UI_PopupButton(_("Destroy building"), _("Are you sure you want to destroy this building?"),
		NULL, NULL, NULL,
		va("building_destroy %i %i confirmed; ui_pop;", base->idx, building->idx), _("Destroy"), _("Destroy the building"),
		NULL, NULL, NULL);
}
/**
 * @brief Initialises base.
 * @note This command is executed in the init node of the base menu.
 * It is called everytime the base menu pops up and sets the cvars.
 * @todo integrate building status tooltips from B_CheckBuildingStatusForMenu_f into this one
 */
static void B_BaseInit_f (void)
{
	int i;
	base_t *base = B_GetCurrentSelectedBase();

	if (!base)
		return;

	/* make sure the credits cvar is up-to-date */
	CP_UpdateCredits(ccs.credits);

	cgi->Cvar_SetValue("mn_base_num_aircraft", AIR_BaseCountAircraft(base));

	/* activate or deactivate the aircraft button */
	if (AIR_AircraftAllowed(base)) {
		if (AIR_BaseHasAircraft(base))
			cgi->UI_ExecuteConfunc("update_basebutton aircraft false \"%s\"", _("Aircraft management and crew equipment"));
		else
			cgi->UI_ExecuteConfunc("update_basebutton aircraft true \"%s\"", _("Buy or produce at least one aircraft first."));
	} else {
		cgi->UI_ExecuteConfunc("update_basebutton aircraft true \"%s\"", _("No Hangar functional in base."));
	}

	if (BS_BuySellAllowed(base))
		cgi->UI_ExecuteConfunc("update_basebutton buysell false \"%s\"", _("Buy/Sell equipment, aircraft and UGV"));
	else
		cgi->UI_ExecuteConfunc("update_basebutton buysell true \"%s\"", va(_("No %s functional in base."), _("Storage")));

	if (B_GetCount() > 1)
		cgi->UI_ExecuteConfunc("update_basebutton transfer false \"%s\"", _("Transfer equipment, vehicles, aliens and employees to other bases"));
	else
		cgi->UI_ExecuteConfunc("update_basebutton transfer true \"%s\"", _("Build at least a second base to transfer equipment or personnel"));

	if (RS_ResearchAllowed(base))
		cgi->UI_ExecuteConfunc("update_basebutton research false \"%s\"", _("Research new technology"));
	else
		cgi->UI_ExecuteConfunc("update_basebutton research true \"%s\"", va(_("No %s functional in base."), _("Laboratory")));

	if (PR_ProductionAllowed(base))
		cgi->UI_ExecuteConfunc("update_basebutton production false \"%s\"", _("Produce equipment, aircraft and UGV"));
	else
		cgi->UI_ExecuteConfunc("update_basebutton production true \"%s\"", va(_("No %s functional in base."), _("Workshop")));

	if (E_HireAllowed(base))
		cgi->UI_ExecuteConfunc("update_basebutton hire false \"%s\"", _("Hire or dismiss employees"));
	else
		cgi->UI_ExecuteConfunc("update_basebutton hire true \"%s\"", va(_("No %s functional in base."), _("Living Quarters")));

	if (AC_ContainmentAllowed(base))
		cgi->UI_ExecuteConfunc("update_basebutton containment false \"%s\"", _("Manage captured aliens"));
	else
		cgi->UI_ExecuteConfunc("update_basebutton containment true \"%s\"", va(_("No %s functional in base."), _("Containment")));

	if (HOS_HospitalAllowed(base))
		cgi->UI_ExecuteConfunc("update_basebutton hospital false \"%s\"", _("Treat wounded soldiers and perform implant surgery"));
	else
		cgi->UI_ExecuteConfunc("update_basebutton hospital true \"%s\"", va(_("No %s functional in base."), _("Hospital")));

	/*
	 * Gather data on current/max space for living quarters, storage, lab and workshop
	 * clear_bld_space ensures 0/0 data for facilities which may not exist in base
	 */
	cgi->UI_ExecuteConfunc("clear_bld_space");
	for (i = 0; i < ccs.numBuildingTemplates; i++) {
		const building_t* b = &ccs.buildingTemplates[i];
		const baseCapacities_t capType = B_GetCapacityFromBuildingType(b->buildingType);
		capacities_t cap;

		if (capType == MAX_CAP)
			continue;
		/* Check if building matches one of our four types */
		if (b->buildingType != B_QUARTERS && b->buildingType != B_STORAGE && b->buildingType != B_WORKSHOP && b->buildingType != B_LAB && b->buildingType != B_ANTIMATTER)
			continue;
		/* only show already researched buildings */
		if (!RS_IsResearched_ptr(b->tech))
			continue;
		cap = *CAP_Get(base, capType);

		assert(b->tpl);
		const int count = B_GetNumberOfBuildingsInBaseByTemplate(base, b->tpl);
		if (count < 1)
			continue;

		cgi->UI_ExecuteConfunc("show_bld_space \"%s\" \"%s\" %i %i %i %i", _(b->name), b->id, cap.cur, cap.max, count, b->tpl->maxCount);
	}

	/*
	 * Get the number of different employees in the base
	 * @todo: Get the number of injured soldiers if hospital exists
	 */
	cgi->UI_ExecuteConfunc("current_employees %i %i %i %i", E_CountHired(base, EMPL_SOLDIER), E_CountHired(base, EMPL_PILOT), E_CountHired(base, EMPL_SCIENTIST), E_CountHired(base, EMPL_WORKER));

	/*
	 * List the first five aircraft in the base if they exist
	 */
	cgi->UI_ExecuteConfunc("clear_aircraft");
	if (AIR_AircraftAllowed(base)) {
		if (AIR_BaseHasAircraft(base)) {
			i = 0;
			AIR_ForeachFromBase(aircraft, base) {
				if (i > 5)
					break;
				/*
				 * UI node should use global IDX to identify aircraft but it uses order of aircraft in base (i)
				 * See @todo in cp_aircraft_callbacks.c in AIR_AircraftSelect()
				 */
				cgi->UI_ExecuteConfunc("show_aircraft %i \"%s\" \"%s\" \"%s\" %i", i, aircraft->name, aircraft->id, AIR_AircraftStatusToName(aircraft), AIR_IsAircraftInBase(aircraft));
				i++;
			}
		}
	}

	/* Get the research item closest to completion in the base if it exists */
	cgi->UI_ExecuteConfunc("clear_research");
	if (RS_ResearchAllowed(base)) {
		const technology_t *closestTech = NULL;
		double finished = -1;
		for (i = 0; i < ccs.numTechnologies; i++) {
			const technology_t *tech = RS_GetTechByIDX(i);
			if (!tech)
				continue;
			if (tech->base != base)
				continue;
			if (tech->statusResearch == RS_RUNNING) {
				const double percent = (1 - tech->time / tech->overallTime) * 100;
				if (percent > finished) {
					finished = percent;
					closestTech = tech;
				}
			}
		}
		if (closestTech != NULL)
			cgi->UI_ExecuteConfunc("show_research \"%s\" %i %3.0f", closestTech->name, closestTech->scientists, finished);
	}

	/* Get the production item closest to completion in the base if it exists */
	cgi->UI_ExecuteConfunc("clear_production");
	if (PR_ProductionAllowed(base)) {
		const production_queue_t *queue = PR_GetProductionForBase(base);
		if (queue->numItems > 0) {
			const production_t *production = &queue->items[0];
			cgi->UI_ExecuteConfunc("show_production \"%s\" %3.0f", PR_GetName(&production->data), PR_GetProgress(production) * 100);
		}
	}
}
/**
 * @brief Initialises base.
 * @note This command is executed in the init node of the base menu.
 * It is called everytime the base menu pops up and sets the cvars.
 * @todo integrate building status tooltips from B_CheckBuildingStatusForMenu_f into this one
 */
static void B_BaseInit_f (void)
{
	base_t* base = B_GetCurrentSelectedBase();

	if (!base)
		return;

	/* make sure the credits cvar is up-to-date */
	CP_UpdateCredits(ccs.credits);

	/* activate or deactivate the aircraft button */
	if (AIR_AircraftAllowed(base)) {
		if (AIR_BaseHasAircraft(base))
			cgi->UI_ExecuteConfunc("update_basebutton aircraft false \"%s\"", _("Aircraft management and crew equipment"));
		else
			cgi->UI_ExecuteConfunc("update_basebutton aircraft true \"%s\"", _("Buy or produce at least one aircraft first."));
	} else {
		cgi->UI_ExecuteConfunc("update_basebutton aircraft true \"%s\"", _("No Hangar functional in base."));
	}

	if (BS_BuySellAllowed(base))
		cgi->UI_ExecuteConfunc("update_basebutton buysell false \"%s\"", _("Buy/Sell equipment, aircraft and UGV"));
	else
		cgi->UI_ExecuteConfunc("update_basebutton buysell true \"%s\"", va(_("No %s functional in base."), _("Storage")));

	if (B_GetCount() > 1)
		cgi->UI_ExecuteConfunc("update_basebutton transfer false \"%s\"", _("Transfer equipment, vehicles, aliens and employees to other bases"));
	else
		cgi->UI_ExecuteConfunc("update_basebutton transfer true \"%s\"", _("Build at least a second base to transfer equipment or personnel"));

	if (RS_ResearchAllowed(base))
		cgi->UI_ExecuteConfunc("update_basebutton research false \"%s\"", _("Research new technology"));
	else
		cgi->UI_ExecuteConfunc("update_basebutton research true \"%s\"", va(_("No %s functional in base."), _("Laboratory")));

	if (PR_ProductionAllowed(base))
		cgi->UI_ExecuteConfunc("update_basebutton production false \"%s\"", _("Produce equipment, aircraft and UGV"));
	else
		cgi->UI_ExecuteConfunc("update_basebutton production true \"%s\"", va(_("No %s functional in base."), _("Workshop")));

	if (E_HireAllowed(base))
		cgi->UI_ExecuteConfunc("update_basebutton hire false \"%s\"", _("Hire or dismiss employees"));
	else
		cgi->UI_ExecuteConfunc("update_basebutton hire true \"%s\"", va(_("No %s functional in base."), _("Living Quarters")));

	if (AC_ContainmentAllowed(base))
		cgi->UI_ExecuteConfunc("update_basebutton containment false \"%s\"", _("Manage captured aliens"));
	else
		cgi->UI_ExecuteConfunc("update_basebutton containment true \"%s\"", va(_("No %s functional in base."), _("Containment")));

	if (HOS_HospitalAllowed(base))
		cgi->UI_ExecuteConfunc("update_basebutton hospital false \"%s\"", _("Treat wounded soldiers and perform implant surgery"));
	else
		cgi->UI_ExecuteConfunc("update_basebutton hospital true \"%s\"", va(_("No %s functional in base."), _("Hospital")));

	/*
	 * Gather data on current/max space for living quarters, storage, lab and workshop
	 * clear_bld_space ensures 0/0 data for facilities which may not exist in base
	 */
	cgi->UI_ExecuteConfunc("clear_bld_space");
	for (int i = 0; i < ccs.numBuildingTemplates; i++) {
		const building_t* b = &ccs.buildingTemplates[i];

		/* Check if building matches one of our four types */
		if (b->buildingType != B_QUARTERS && b->buildingType != B_STORAGE && b->buildingType != B_WORKSHOP && b->buildingType != B_LAB && b->buildingType != B_ANTIMATTER)
			continue;

		/* only show already researched buildings */
		if (!RS_IsResearched_ptr(b->tech))
			continue;

		const baseCapacities_t capType = B_GetCapacityFromBuildingType(b->buildingType);
		if (capType == MAX_CAP)
			continue;

		const int count = B_GetNumberOfBuildingsInBaseByTemplate(base, b->tpl);
		if (count < 1)
			continue;

		const capacities_t& cap = *CAP_Get(base, capType);
		cgi->UI_ExecuteConfunc("show_bld_space \"%s\" \"%s\" %i %i %i %i", _(b->name), b->id, cap.cur, cap.max, count, b->tpl->maxCount);
	}

	/*
	 * Get the number of different employees in the base
	 * @todo: Get the number of injured soldiers if hospital exists
	 */
	cgi->UI_ExecuteConfunc("current_employees %i %i %i %i", E_CountHired(base, EMPL_SOLDIER), E_CountHired(base, EMPL_PILOT), E_CountHired(base, EMPL_SCIENTIST), E_CountHired(base, EMPL_WORKER));

	/*
	 * List the first five aircraft in the base if they exist
	 */
	cgi->UI_ExecuteConfunc("clear_aircraft");
	if (AIR_AircraftAllowed(base)) {
		AIR_ForeachFromBase(aircraft, base) {
			cgi->UI_ExecuteConfunc("show_aircraft %i \"%s\" \"%s\" \"%s\" %i", aircraft->idx, aircraft->name, aircraft->id, AIR_AircraftStatusToName(aircraft), AIR_IsAircraftInBase(aircraft));
		}
	}