import { classes } from 'common/react';
import { uniqBy } from 'common/collections';
import { useBackend, useSharedState } from '../backend';
import { formatSiUnit, formatMoney } from '../format';
import { Flex, Section, Tabs, Box, Button, Fragment, ProgressBar, NumberInput, Icon, Input, Tooltip } from '../components';
import { Window } from '../layouts';
import { createSearch, toTitleCase } from 'common/string';
import { toFixed } from 'common/math';
const MATERIAL_KEYS = {
'steel': 'sheet-metal_3',
'glass': 'sheet-glass_3',
'silver': 'sheet-silver_3',
'graphite': 'sheet-puck_3',
'plasteel': 'sheet-plasteel_3',
'durasteel': 'sheet-durasteel_3',
'verdantium': 'sheet-wavy_3',
'morphium': 'sheet-wavy_3',
'mhydrogen': 'sheet-mythril_3',
'gold': 'sheet-gold_3',
'diamond': 'sheet-diamond',
'supermatter': 'sheet-super_3',
'osmium': 'sheet-silver_3',
'phoron': 'sheet-phoron_3',
'uranium': 'sheet-uranium_3',
'titanium': 'sheet-titanium_3',
'lead': 'sheet-adamantine_3',
'platinum': 'sheet-adamantine_3',
'plastic': 'sheet-plastic_3',
};
const COLOR_NONE = 0;
const COLOR_AVERAGE = 1;
const COLOR_BAD = 2;
const COLOR_KEYS = {
[COLOR_NONE]: false,
[COLOR_AVERAGE]: 'average',
[COLOR_BAD]: 'bad',
};
const materialArrayToObj = (materials) => {
let materialObj = {};
materials.forEach((m) => {
materialObj[m.name] = m.amount;
});
return materialObj;
};
const partBuildColor = (cost, tally, material) => {
if (cost > material) {
return { color: COLOR_BAD, deficit: cost - material };
}
if (tally > material) {
return { color: COLOR_AVERAGE, deficit: cost };
}
if (cost + tally > material) {
return { color: COLOR_AVERAGE, deficit: cost + tally - material };
}
return { color: COLOR_NONE, deficit: 0 };
};
const partCondFormat = (materials, tally, part) => {
let format = { 'textColor': COLOR_NONE };
Object.keys(part.cost).forEach((mat) => {
format[mat] = partBuildColor(part.cost[mat], tally[mat], materials[mat]);
if (format[mat].color > format['textColor']) {
format['textColor'] = format[mat].color;
}
});
return format;
};
const queueCondFormat = (materials, queue) => {
let materialTally = {};
let matFormat = {};
let missingMatTally = {};
let textColors = {};
queue.forEach((part, i) => {
textColors[i] = COLOR_NONE;
Object.keys(part.cost).forEach((mat) => {
materialTally[mat] = materialTally[mat] || 0;
missingMatTally[mat] = missingMatTally[mat] || 0;
matFormat[mat] = partBuildColor(part.cost[mat], materialTally[mat], materials[mat]);
if (matFormat[mat].color !== COLOR_NONE) {
if (textColors[i] < matFormat[mat].color) {
textColors[i] = matFormat[mat].color;
}
} else {
materialTally[mat] += part.cost[mat];
}
missingMatTally[mat] += matFormat[mat].deficit;
});
});
return { materialTally, missingMatTally, textColors, matFormat };
};
const searchFilter = (search, allparts) => {
let searchResults = [];
if (!search.length) {
return;
}
const resultFilter = createSearch(search, (part) => (part.name || '') + (part.desc || '') + (part.searchMeta || ''));
Object.keys(allparts).forEach((category) => {
allparts[category].filter(resultFilter).forEach((e) => {
searchResults.push(e);
});
});
searchResults = uniqBy((part) => part.name)(searchResults);
return searchResults;
};
export const ExosuitFabricator = (props, context) => {
const { act, data } = useBackend(context);
const queue = data.queue || [];
const materialAsObj = materialArrayToObj(data.materials || []);
const { materialTally, missingMatTally, textColors } = queueCondFormat(materialAsObj, queue);
const [displayMatCost, setDisplayMatCost] = useSharedState(context, 'display_mats', false);
const [displayAllMat, setDisplayAllMat] = useSharedState(context, 'display_all_mats', false);
return (
setDisplayMatCost(!displayMatCost)} checked={displayMatCost}>
Display Material Costs
setDisplayAllMat(!displayAllMat)} checked={displayAllMat}>
Display All Materials
{(data.species_types && (
Species:
)) ||
null}
{(data.manufacturers && (
Manufacturer:
)) ||
null}
);
};
const EjectMaterial = (props, context) => {
const { act } = useBackend(context);
const { material } = props;
const { name, removable, sheets } = material;
const [removeMaterials, setRemoveMaterials] = useSharedState(context, 'remove_mats_' + name, 1);
if (removeMaterials > 1 && sheets < removeMaterials) {
setRemoveMaterials(sheets || 1);
}
return (
{
const newVal = parseInt(val, 10);
if (Number.isInteger(newVal)) {
setRemoveMaterials(newVal);
}
}}
/>
);
};
export const Materials = (props, context) => {
const { data } = useBackend(context);
const { displayAllMat, disableEject = false } = props;
const materials = data.materials || [];
let display_materials = materials.filter((mat) => displayAllMat || mat.amount > 0);
if (display_materials.length === 0) {
return (
No Materials Loaded.
);
}
return (
{display_materials.map(
(material) =>
(
{!disableEject && (
)}
) || null
)}
);
};
const MaterialAmount = (props, context) => {
const { name, amount, formatsi, formatmoney, color, style } = props;
let amountDisplay = '0';
if (amount < 1 && amount > 0) {
amountDisplay = toFixed(amount, 2);
} else if (formatsi) {
amountDisplay = formatSiUnit(amount, 0);
} else if (formatmoney) {
amountDisplay = formatMoney(amount);
} else {
amountDisplay = amount;
}
return (
{amountDisplay}
);
};
const PartSets = (props, context) => {
const { data } = useBackend(context);
const partSets = data.partSets || [];
const buildableParts = data.buildableParts || {};
const [selectedPartTab, setSelectedPartTab] = useSharedState(
context,
'part_tab',
partSets.length ? buildableParts[0] : ''
);
return (
{partSets.map(
(set) =>
!!buildableParts[set] && (
setSelectedPartTab(set)}>
{set}
)
)}
);
};
const PartLists = (props, context) => {
const { data } = useBackend(context);
const getFirstValidPartSet = (sets) => {
for (let set of sets) {
if (buildableParts[set]) {
return set;
}
}
return null;
};
const partSets = data.partSets || [];
const buildableParts = data.buildableParts || [];
const { queueMaterials, materials } = props;
const [selectedPartTab, setSelectedPartTab] = useSharedState(context, 'part_tab', getFirstValidPartSet(partSets));
const [searchText, setSearchText] = useSharedState(context, 'search_text', '');
if (!selectedPartTab || !buildableParts[selectedPartTab]) {
const validSet = getFirstValidPartSet(partSets);
if (validSet) {
setSelectedPartTab(validSet);
} else {
return;
}
}
let partsList;
// Build list of sub-categories if not using a search filter.
if (!searchText) {
partsList = { 'Parts': [] };
buildableParts[selectedPartTab].forEach((part) => {
part['format'] = partCondFormat(materials, queueMaterials, part);
if (!part.subCategory) {
partsList['Parts'].push(part);
return;
}
if (!(part.subCategory in partsList)) {
partsList[part.subCategory] = [];
}
partsList[part.subCategory].push(part);
});
} else {
partsList = [];
searchFilter(searchText, buildableParts).forEach((part) => {
part['format'] = partCondFormat(materials, queueMaterials, part);
partsList.push(part);
});
}
return (
{(!!searchText && (
)) ||
Object.keys(partsList).map((category) => (
))}
);
};
const PartCategory = (props, context) => {
const { act, data } = useBackend(context);
const { buildingPart } = data;
const { parts, name, forceShow, placeholder } = props;
const [displayMatCost] = useSharedState(context, 'display_mats', false);
return (
(!!parts.length || forceShow) && (
act('add_queue_set', {
part_list: parts.map((part) => part.id),
})
}
/>
}>
{!parts.length && placeholder}
{parts.map((part) => (
{part.name}
{displayMatCost && (
{Object.keys(part.cost).map((material) => (
))}
)}
))}
)
);
};
const Queue = (props, context) => {
const { act, data } = useBackend(context);
const { isProcessingQueue } = data;
const queue = data.queue || [];
const { queueMaterials, missingMaterials, textColors } = props;
return (
act('clear_queue')}
/>
{(!!isProcessingQueue && (
{!!queue.length && (
)}
);
};
const QueueMaterials = (props, context) => {
const { queueMaterials, missingMaterials } = props;
return (
{Object.keys(queueMaterials).map((material) => (
{!!missingMaterials[material] && (
{formatMoney(missingMaterials[material])}
)}
))}
);
};
const QueueList = (props, context) => {
const { act, data } = useBackend(context);
const { textColors } = props;
const queue = data.queue || [];
if (!queue.length) {
return No parts in queue.;
}
return queue.map((part, index) => (
act('del_queue_part', { index: index + 1 })}
/>
{part.name}
));
};
const BeingBuilt = (props, context) => {
const { data } = useBackend(context);
const { buildingPart, storedPart } = data;
if (storedPart) {
const { name } = storedPart;
return (
{name}
{'Fabricator outlet obstructed...'}
);
}
if (buildingPart) {
const { name, duration, printTime } = buildingPart;
const timeLeft = Math.ceil(duration / 10);
return (
{name}
{(timeLeft >= 0 && timeLeft + 's') || 'Dispensing...'}
);
}
};