App.UI.Budget.Cost = function() {
	let el = document.createElement('p');
	let table = document.createElement("table");
	table.classList.add("budget");
	let node;
	let subNode;
	let cell;
	let array;
	let coloredRow = true;

	// Set up object to track calculated displays
	const income = "lastWeeksCashIncome";
	const expenses = "lastWeeksCashExpenses";
	const profits = "lastWeeksCashProfits";
	const F = V.lastWeeksGatheredTotals;

	// HEADER
	let header = table.createTHead();
	let row = header.insertRow(0);
	let th = document.createElement("th");
	let pent = document.createElement("h1");
	pent.textContent = "Budget Overview";
	th.appendChild(pent);
	row.appendChild(th);

	array = [
		"Income",
		"Expense",
		"Totals"
	];
	for (let th of array) {
		let cell = document.createElement("th");
		cell.textContent = th;
		row.appendChild(cell);
	}

	let body = document.createElement('tbody');
	table.appendChild(body);
	row = body.insertRow();

	// HEADER: FACILITIES
	createSectionHeader("Facilities");

	// PENTHOUSE
	generateRowGroup("Penthouse", "PENTHOUSE");
	generateRowCategory("Rest", "slaveAssignmentRest");
	generateRowCategory("RestVign", "slaveAssignmentRestVign");
	generateRowCategory("Fucktoy", "slaveAssignmentFucktoy");
	generateRowCategory("Classes", "slaveAssignmentClasses");
	generateRowCategory("House", "slaveAssignmentHouse");
	generateRowCategory("HouseVign", "slaveAssignmentHouseVign");
	generateRowCategory("Whore", "slaveAssignmentWhore");
	generateRowCategory("WhoreVign", "slaveAssignmentWhoreVign");
	generateRowCategory("Public", "slaveAssignmentPublic");
	generateRowCategory("PublicVign", "slaveAssignmentPublicVign");
	generateRowCategory("Subordinate", "slaveAssignmentSubordinate");
	generateRowCategory("Milked", "slaveAssignmentMilked");
	generateRowCategory("MilkedVign", "slaveAssignmentMilkedVign");
	generateRowCategory("ExtraMilk", "slaveAssignmentExtraMilk");
	generateRowCategory("ExtraMilkVign", "slaveAssignmentExtraMilkVign");
	generateRowCategory("Gloryhole", "slaveAssignmentGloryhole");
	generateRowCategory("Confinement", "slaveAssignmentConfinement");
	// Other
	generateRowCategory("Chosing Own Assignment", "slaveAssignmentChoice");

	// LEADERSHIP ROLES

	// HEAD GIRL
	// find passage name for HGSuite
	generateRowGroup(V.HGSuiteNameCaps, "HEADGIRLSUITE");
	generateRowCategory("Head Girl", "slaveAssignmentHeadgirl");
	generateRowCategory("Head Girl Fucktoys", "slaveAssignmentHeadgirlsuite");

	// RECRUITER
	generateRowGroup("Recruiter", "RECRUITER");
	generateRowCategory("Recruiter", "slaveAssignmentRecruiter");

	// BODYGUARD
	// find passage name for Armory
	generateRowGroup("Armory", "DOJO");
	generateRowCategory("Bodyguard", "slaveAssignmentBodyguard");

	// CONCUBINE
	generateRowGroup("Master Suite", "MASTERSUITE");
	generateRowCategory("Master Suite Maintenance", "masterSuite");
	generateRowCategory("Master Suite Concubine", "slaveAssignmentConcubine");
	generateRowCategory("Master Suite Fucktoys", "slaveAssignmentMastersuite");

	// AGENT
	generateRowGroup("Agent", "AGENT");
	generateRowCategory("Agent", "slaveAssignmentAgent");
	generateRowCategory("Agent's Partner", "slaveAssignmentAgentPartner");

	// ARCADE
	generateRowGroup(V.arcadeNameCaps, "ARCADE");
	generateRowCategory("Arcade Maintenance", "arcade");
	generateRowCategory("Arcade Fuckdolls", "slaveAssignmentArcade");

	// BROTHEL
	generateRowGroup(V.brothelNameCaps, "BROTHEL");
	generateRowCategory("Brothel Maintenance", "brothel");
	generateRowCategory("Brothel Madam", "slaveAssignmentMadam");
	generateRowCategory("Brothel MadamVign", "slaveAssignmentMadamVign");
	generateRowCategory("Brothel Whore", "slaveAssignmentBrothel");
	generateRowCategory("Brothel WhoreVign", "slaveAssignmentBrothelVign");
	generateRowCategory("Brothel Ads", "brothelAds");

	// CELLBLOCK
	generateRowGroup(V.cellblockNameCaps, "CELLBLOCK");
	generateRowCategory("Cellblock Maintenance", "cellblock");
	generateRowCategory("Cellblock Warden", "slaveAssignmentWarden");
	generateRowCategory("Cellblock Slaves", "slaveAssignmentCellblock");

	// CLUB
	generateRowGroup(V.clubNameCaps, "CLUB");
	generateRowCategory("Club Maintenance", "club");
	generateRowCategory("Club DJ", "slaveAssignmentDj");
	generateRowCategory("Club DJVign", "slaveAssignmentDjVign");
	generateRowCategory("Club Public", "slaveAssignmentClub");
	generateRowCategory("Club PublicVign", "slaveAssignmentClubVign");
	generateRowCategory("Club Ads", "clubAds");

	// CLINIC
	generateRowGroup(V.clinicNameCaps, "CLINIC");
	generateRowCategory("Clinic Maintenance", "clinic");
	generateRowCategory("Clinic Nurse", "slaveAssignmentNurse");
	generateRowCategory("Clinic Slaves", "slaveAssignmentClinic");

	// DAIRY
	generateRowGroup(V.dairyNameCaps, "DAIRY");
	generateRowCategory("Dairy Maintenance", "dairy");
	generateRowCategory("Dairy Milkmaid", "slaveAssignmentMilkmaid");
	generateRowCategory("Dairy Cows", "slaveAssignmentDairy");
	generateRowCategory("Dairy Cows", "slaveAssignmentDairyVign");

	// FARMYARD
	generateRowGroup(V.farmyardNameCaps, "FARMYARD");
	generateRowCategory("Farmyard Maintenance", "farmyard");
	generateRowCategory("Farmyard Farmer", "slaveAssignmentFarmer");
	generateRowCategory("Farmyard Farmhands", "slaveAssignmentFarmyard");
	generateRowCategory("Farmyard FarmhandsVign", "slaveAssignmentFarmyardVign");

	// INCUBATOR
	generateRowGroup(V.incubatorNameCaps, "INCUBATOR");
	generateRowCategory("Incubator Maintenance", "incubator");
	generateRowCategory("Incubator Babies", "incubatorSlaves");

	// NURSERY
	generateRowGroup(V.nurseryNameCaps, "NURSERY");
	generateRowCategory("Nursery Maintenance", "nursery");
	generateRowCategory("Nursery Matron", "slaveAssignmentMatron");
	generateRowCategory("Nursery Nannies", "slaveAssignmentNursery");
	generateRowCategory("Nursery NanniesVign", "slaveAssignmentNurseryVign");

	// PIT
	generateRowGroup(V.pitNameCaps, "PIT");
	generateRowCategory("Pit Maintenance", "pit");

	// PROSTHETIC LAB
	generateRowGroup("Prosthetic Lab", "PROSTHETICLAB");
	generateRowCategory("Prosthetic Lab Maintenance", "lab");
	generateRowCategory("Prostethic Lab Research", "labResearch");
	generateRowCategory("Prostethic Lab Scientists", "labScientists");
	generateRowCategory("Prostethic Lab Menials", "labMenials");

	// SCHOOLROOM
	generateRowGroup(V.schoolroomNameCaps, "SCHOOLROOM");
	generateRowCategory("Schoolroom Maintenance", "school");
	generateRowCategory("Schoolroom Teacher", "slaveAssignmentTeacher");
	generateRowCategory("Schoolroom Students", "slaveAssignmentSchool");

	// SERVANTS' QUARTERS
	generateRowGroup(V.servantsQuartersNameCaps, "SERVANTSQUARTERS");
	generateRowCategory("Servants' Quarters Maintenance", "servantsQuarters");
	generateRowCategory("Servants' Quarters Steward", "slaveAssignmentSteward");
	generateRowCategory("Servants' Quarters Servants", "slaveAssignmentQuarter");
	generateRowCategory("Servants' Quarters ServantsVign", "slaveAssignmentQuarterVign");

	// SPA
	generateRowGroup(V.spaNameCaps, "SPA");
	generateRowCategory("Spa Maintenance", "spa");
	generateRowCategory("Spa Attendant", "slaveAssignmentAttendant");
	generateRowCategory("Spa Slaves", "slaveAssignmentSpa");

	// HEADER: ARCOLOGY
	createSectionHeader("Arcology");

	// SLAVES
	generateRowGroup("Miscellaneous Slave Income and Expenses", "SLAVES");
	generateRowCategory("Slave Porn", "porn");
	generateRowCategory("Slave Modifcations", "slaveMod");
	generateRowCategory("Slave Surgery", "slaveSurgery");
	generateRowCategory("Slave Birhting", "birth");

	// MENIAL LABOR
	generateRowGroup("Menial Labor", "LABOR");
	generateRowCategory("Menials: Slaves", "menialTrades");
	generateRowCategory("Menials: Fuckdolls", "fuckdolls");
	generateRowCategory("Menials: Bioreactors", "menialBioreactors");

	// FLIPPING
	generateRowGroup("Flipping", "FLIPPING");
	generateRowCategory("Slave Transfer", "slaveTransfer");
	generateRowCategory("Menials", "menialTransfer");
	generateRowCategory("Fuckdolls", "fuckdollsTransfer");
	generateRowCategory("Bioreactors", "menialBioreactorsTransfer");
	generateRowCategory("Assistant: Menials", "menialTransferA");
	generateRowCategory("Assistant: Fuckdolls", "fuckdollsTransferA");
	generateRowCategory("Assistant: Bioreactors", "menialBioreactorsTransferA");
	generateRowCategory("Menial Retirement", "menialRetirement");
	generateRowCategory("Scientist Transfer", "labScientistsTransfer");
	generateRowCategory("Slave Babies", "babyTransfer");

	// FINANCIALS
	generateRowGroup("Financials", "FINANCIALS");
	generateRowCategory("Weather", "weather");
	generateRowCategory("Rents", "rents");
	generateRowCategory("Fines", "fines");
	generateRowCategory("Events", "event");
	generateRowCategory("Capital Expenses", "capEx");
	generateRowCategory("Future Society Shaping", "futureSocieties");
	generateRowCategory("School Subsidy", "schoolBacking");
	generateRowCategory("Arcology conflict", "war");
	generateRowCategory("Cheating", "cheating");

	// POLICIES
	generateRowGroup("Policies", "POLICIES");
	generateRowCategory("Policies", "policies");
	generateRowCategory("Subsidies and Barriers", "subsidiesAndBarriers");

	// EDICTS
	generateRowGroup("Edicts", "EDICTS");
	generateRowCategory("Edicts", "edicts");

	// PERSONAL FINANCE
	generateRowGroup("Personal Finance", "PERSONALFINANCE");
	generateRowCategory("Personal Business", "personalBusiness");
	generateRowCategory("Personal Living Expenses", "personalLivingExpenses");
	generateRowCategory("Your skills", "PCSkills");
	generateRowCategory("Your training expenses", "PCtraining");
	generateRowCategory("Your medical expenses", "PCmedical");
	generateRowCategory("Citizen Orphanage", "citizenOrphanage");
	generateRowCategory("Private Orphanage", "privateOrphanage");
	generateRowCategory("Stock dividents", "stocks");
	generateRowCategory("Stock trading", "stocksTraded");

	// SECURITY
	generateRowGroup("Security", "SECURITY");
	generateRowCategory("Mercenaries", "mercenaries");
	generateRowCategory("Security Expansion", "securityExpansion");
	generateRowCategory("Special Forces", "specialForces");
	generateRowCategory("Peacekeepers", "peacekeepers");

	// BUDGET REPORT
	createSectionHeader("Budget Report");

	row = table.insertRow();
	cell = row.insertCell();
	cell.append("Tracked totals");

	cell = row.insertCell();
	V.lastWeeksCashIncome.Total = hashSum(V.lastWeeksCashIncome);
	cell.append(cashFormatColorDOM(Math.trunc(V.lastWeeksCashIncome.Total)));

	cell = row.insertCell();
	V.lastWeeksCashExpenses.Total = hashSum(V.lastWeeksCashExpenses);
	cell.append(cashFormatColorDOM(Math.trunc(V.lastWeeksCashExpenses.Total)));

	cell = row.insertCell();

	V.lastWeeksCashProfits.Total = (V.lastWeeksCashIncome.Total + V.lastWeeksCashExpenses.Total);
	// each "profit" item is calculated on this sheet, and there's two ways to generate a profit total: the difference of the income and expense totals, and adding all the profit items. If they aren't the same, I probably forgot to properly add an item's profit calculation to this sheet.
	node = new DocumentFragment();
	let total = hashSum(V.lastWeeksCashProfits) - V.lastWeeksCashProfits.Total;
	if (V.lastWeeksCashProfits.Total !== total) { // Profits includes the total number of profits, so we have to subtract it back out
		node.append(cashFormatColorDOM(Math.trunc(total)));
		subNode = document.createElement('span');
		subNode.className = "red";
		subNode.textContent = "Fix profit calc";
		node.append(subNode);
	}
	node.append(cashFormatColorDOM(Math.trunc(V.lastWeeksCashProfits.Total)));
	cell.append(node);
	flipColors(row);

	row = table.insertRow();
	cell = row.insertCell();
	cell.append(`Expenses budget for week ${V.week + 1}`);
	cell = row.insertCell();
	cell = row.insertCell();
	cell.append(cashFormatColorDOM(-V.costs));
	flipColors(row);

	row = table.insertRow();
	cell = row.insertCell();
	cell.append(`Last week actuals`);
	cell = row.insertCell();
	cell = row.insertCell();
	cell = row.insertCell();
	cell.append(cashFormatColorDOM(V.cash - V.cashLastWeek));
	flipColors(row);

	row = table.insertRow();
	if ((V.cash - V.cashLastWeek) === V.lastWeeksCashProfits.Total) {
		cell = row.insertCell();
		node = document.createElement('span');
		node.className = "green";
		node.textContent = `The books are balanced, ${properTitle()}!`;
		cell.append(node);
	} else {
		cell = row.insertCell();
		cell.append("Transaction tracking off by:");
		cell = row.insertCell();
		cell = row.insertCell();
		cell = row.insertCell();
		cell.append(cashFormatColorDOM((V.cash - V.cashLastWeek) - V.lastWeeksCashProfits.Total));
	}
	flipColors(row);

	el.appendChild(table);
	return jQuery('#costTable').empty().append(el);

	function createSectionHeader(text) {
		coloredRow = true; // make sure the following section begins with color.
		row = table.insertRow();
		cell = row.insertCell();
		let headline = document.createElement('h2');
		headline.textContent = text;
		cell.append(headline);
	}

	function generateRowCategory(node, category) {
		if (category === "") {
			row = table.insertRow();
			row.append(document.createElement('br'));
			row.insertCell();
			row.insertCell();
			row.insertCell();
			flipColors(row);
			return;
		}

		if (V[income][category] || V[expenses][category] || V.showAllEntries.costsBudget) {
			row = table.insertRow();
			let cell = row.insertCell();
			cell.append(node);
			cell = row.insertCell();
			cell.append(cashFormatColorDOM(V[income][category]));
			cell = row.insertCell();
			cell.append(cashFormatColorDOM(-Math.abs(V[expenses][category])));
			flipColors(row);
			cell = row.insertCell();
			cell.append(cashFormatColorDOM(V[profits][category]));
		}
	}

	function generateRowGroup(title, group) {
		if (F[group].income || F[group].expenses || V.showAllEntries.costsBudget) {
			row = table.insertRow();
			cell = row.insertCell();
			let headline = document.createElement('h3');
			headline.textContent = title;
			cell.append(headline);
			cell = row.insertCell();
			cell.append(cashFormatColorDOM(F[group].income, null, true));
			cell = row.insertCell();
			cell.append(cashFormatColorDOM(F[group].expenses, null, true));
			cell = row.insertCell();
			cell.append(cashFormatColorDOM(F[group].profits, null, true));
		}
	}

	function cashFormatColorDOM(s, invert = false, temp) {
		if (invert) {
			s = -1 * s;
		}
		let el = document.createElement('span');
		el.textContent = cashFormat(s);
		if (temp === true) {
			// Gray display for totals when expanded
			el.className = "gray";
		} else {
			// Display red if the value is negative, unless invert is true
			if (s < 0) {
				el.className = "red";
				// Yellow for positive
			} else if (s > 0) {
				el.className = "yellowgreen";
				// White for exactly zero
			}
		}
		return el;
	}

	function flipColors(row) {
		if (coloredRow === true) {
			row.classList.add("colored");
		}
		coloredRow = !coloredRow;
	}
};

src/uncategorized/costsBudget.js