import {
	ProcessType,
	TableType,
} from "qrc:/js/lib/generated/enum";
import {
	isAutomaticMechanicalDeburringMaterial,
	isAutomaticMechanicalDeburringParameters,
	isBendDeduction,
	isBendLineConstraint,
	isBendRateParameters,
	isBendTime,
	isBendTimeParameters,
	isDieGroupPriority,
	isDimensionConstraints,
	isSheetMaterial,
	isSheetMaterialScrapValue,
	isLaserSheetCuttingGas,
	isLaserSheetCuttingMaxThickness,
	isLaserSheetCuttingMinArea,
	isLaserSheetCuttingPierceTime,
	isLaserSheetCuttingRate,
	isLaserSheetCuttingSpeed,
	isLowerDie,
	isLowerDieGroup,
	isLowerDieUnit,
	isSheetMaterialDensity,
	isPackaging,
	isProcess,
	isProcessHandlingTime,
	isProcessIdlePeriod,
	isProcessRate,
	isProcessSetupTimeFallback,
	isProcessUnitTimeFallback,
	isScrewThread,
	isSetting,
	isSheet,
	isSheetBendingMaterial,
	isSheetBendingMaterialMapping,
	isSheetCuttingMaterial,
	isSheetCuttingMaterialMapping,
	isSheetModulus,
	isSheetPrice,
	isSheetPriority,
	isSheetStock,
	isStringIndexedInterface,
	isSurcharge,
	isTableType,
	isTappingTimeParameters,
	isTransportationCosts,
	isTube,
	isTubeMaterial,
	isTubeMaterialDensity,
	isTubeProfile,
	isUpperDie,
	isUpperDieGroup,
	isUpperDieUnit,
	isTubeCuttingSpeed,
	isTubeCuttingPierceTime,
	isTubeCuttingProcess,
	isTubeCuttingProcessMapping,
	isTubePrice,
	isTubeStock,
	isTubeMaterialScrapValue,
} from "qrc:/js/lib/generated/typeguard";
import {
	createCheckBoxRow,
	createDropDownRow,
	createLabelRow,
	createLineEditRow,
	createSpinBoxRow,
} from "qrc:/js/lib/gui_form_widget";
import {
	showFormWidget,
} from "qrc:/js/lib/gui_utils";
import {
	getTable,
	TableTypeMap,
} from "qrc:/js/lib/table_utils";
import {
	getKeysOfObject,
	isArray,
	isBoolean,
	isNumber,
	isString,
	parseJson,
} from "qrc:/js/lib/utils";

/**
 * Can be considered an AnyTable with unparsed and potentially incomplete content
 */
export interface PotentialAnyTable {
	type: TableType;
	content: StringIndexedInterface[];
}

export function isPotentialAnyTable(input: unknown): input is PotentialAnyTable {
	return isStringIndexedInterface(input) && isTableType(input["type"]) && isArray(input["content"], isStringIndexedInterface);
}

type TypeGuard<Row> = {
	(arg: unknown): arg is Row;
}

type Parsers<Row> = {
	[key in keyof Row]: (arg: unknown) => Row[key]|undefined;
};

type ConfigGenerators<Row> = {
	[key in keyof Row]: (key: string, value: unknown) => FormRowConfig;
};

type ResultExtractors<Row> = {
	[key in keyof Row]: (value: unknown) => Row[key];
};

type AllAliases<Row> = {
	[key in keyof Row]: string[];
};

type Aliases<Row> = Partial<AllAliases<Row>>;

interface ImportUtils<Row> {
	isRow: TypeGuard<Row>;
	parsers: Parsers<Row>;
	configGenerators: ConfigGenerators<Row>;
	resultExtractors: ResultExtractors<Row>;
	aliases?: Aliases<Row>;
}

function parseString(arg: unknown): string|undefined {
	return isString(arg) ? arg : undefined;
}

function parseDouble(arg: unknown): number|undefined {
	if (isNumber(arg)) {
		return arg;
	}
	if (!isString(arg)) {
		return undefined;
	}
	// replace all , to . to make sure the decimal point is a .
	const str = arg.replace(/,/gi, ".");
	const float = Number.parseFloat(str);
	return Number.isNaN(float) ? undefined : float;
}

function parseInt(arg: unknown): number|undefined {
	return (isNumber(arg) && Number.isInteger(arg)) ? arg : isString(arg) ? (Number.isNaN(Number.parseInt(arg)) ? undefined : Number.parseInt(arg)) : undefined;
}

function parseBoolean(arg: unknown): boolean|undefined {
	return isBoolean(arg) ? arg : isString(arg) ? parseJson(arg, isBoolean) : undefined;
}

function isProcessType(arg: unknown): arg is ProcessType {
	return isString(arg) && Array.from(ProcessType)
		.some(pt => pt === arg);
}

function parseProcessType(arg: unknown): ProcessType|undefined {
	return isProcessType(arg) ? arg : undefined;
}

function createStringWidgetConfig(key: string, value: unknown): FormRowConfig {
	if (value === undefined) {
		return createLineEditRow(
			key,
			key,
			"",
		);
	} else if (typeof value === "string") {
		return createLabelRow(
			key,
			key,
			value,
		);
	} else {
		return wsi4.throwError("Expecting undefined or string");
	}
}

function createDoubleWidgetConfig(key: string, value: unknown): FormRowConfig {
	if (value === undefined) {
		return createSpinBoxRow({
			key: key,
			name: key,
			initialValue: 0,
			min: Number.MIN_VALUE,
			max: Number.MAX_VALUE,
			decimals: 3,
		});
	} else if (typeof value === "number") {
		return createLabelRow(
			key,
			key,
			value.toFixed(3),
		);
	} else {
		return wsi4.throwError("Expecting undefined or number");
	}
}

function createIntWidgetConfig(key: string, value: unknown): FormRowConfig {
	if (value === undefined) {
		return createSpinBoxRow({
			key: key,
			name: key,
			initialValue: 0,
			min: Number.MIN_SAFE_INTEGER,
			max: Number.MAX_SAFE_INTEGER,
			decimals: 0,
		});
	} else if (typeof value === "number") {
		return createLabelRow(
			key,
			key,
			value.toFixed(0),
		);
	} else {
		return wsi4.throwError("Expecting undefined or number");
	}
}

function createBooleanWidgetConfig(key: string, value: unknown): FormRowConfig {
	if (value === undefined) {
		return createCheckBoxRow(
			key,
			key,
			true,
		);
	} else if (typeof value === "boolean") {
		return createLabelRow(
			key,
			key,
			JSON.stringify(value),
		);
	} else {
		return wsi4.throwError("Expecting undefined or boolean");
	}
}

function createTableWidgetConfig<Index extends keyof TableTypeMap>(
	key: string,
	value: unknown,
	tableType: Index,
	rowToId: (row: Readonly<TableTypeMap[Index]>) => string,
	rowToText: (row: Readonly<TableTypeMap[Index]>) => string,
): FormRowConfig {
	if (value === undefined) {
		return createDropDownRow({
			key: key,
			name: key,
			values: getTable(tableType),
			toId: rowToId,
			toName: rowToText,
			computeInitialValueIndex: () => 0,
		});
	} else if (isString(value)) {
		return createLabelRow(
			key,
			key,
			value,
		);
	} else {
		return wsi4.throwError("Expecting undefiend or StringIndexedInterface");
	}
}

function createDropDownWidget(key: string, values: string[], value: unknown): FormRowConfig {
	if (value === undefined) {
		return createDropDownRow({
			key: key,
			name: key,
			values: values,
			toId: (arg: string) => arg,
			toName: (arg: string) => arg,
			computeInitialValueIndex: () => 0,
		});
	} else if (typeof value === "string") {
		return createLabelRow(
			key,
			key,
			value,
		);
	} else {
		return wsi4.throwError("Expecting undefined or string");
	}
}

function createProcessTypeWidgetConfig(key: string, value: unknown): FormRowConfig {
	return createDropDownWidget(key, Array.from(ProcessType), value);
}

function createSheetMaterialTableWidgetConfig(key: string, value: unknown) {
	return createTableWidgetConfig(key, value, TableType.sheetMaterial, row => row.identifier, row => row.name);
}

function createSheetCuttingMatrialTableWidgetConfig(key: string, value: unknown) {
	return createTableWidgetConfig(key, value, TableType.sheetCuttingMaterial, row => row.identifier, row => row.name);
}

function createLaserSheetCuttingGasTableWidgetConfig(key: string, value: unknown) {
	return createTableWidgetConfig(key, value, TableType.laserSheetCuttingGas, row => row.identifier, row => row.name);
}

function createSheetBendingMaterialTableWidget(key: string, value: unknown) {
	return createTableWidgetConfig(key, value, TableType.sheetBendingMaterial, row => row.identifier, row => row.name);
}

function createAutomaticMechanicalDeburringMaterialTableWidgetConfig(key: string, value: unknown) {
	return createTableWidgetConfig(
		key, value, TableType.automaticMechanicalDeburringMaterial, row => row.automaticMechanicalDeburringMaterialId, row => row.automaticMechanicalDeburringMaterialId);
}

function createPackagingTableWidgetConfig(key: string, value: unknown) {
	return createTableWidgetConfig(key, value, TableType.packaging, row => row.identifier, row => row.name);
}

function createProcessTableWidgetConfig(key: string, value: unknown) {
	return createTableWidgetConfig(key, value, TableType.process, row => row.identifier, row => row.name);
}

function createScrewThreadTableWidgetConfig(key: string, value: unknown) {
	return createTableWidgetConfig(key, value, TableType.screwThread, row => row.identifier, row => row.name);
}

function createSheetTableWidgetConfig(key: string, value: unknown) {
	return createTableWidgetConfig(key, value, TableType.sheet, row => row.identifier, row => row.name);
}

function createUpperDieGroupTableWidgetConfig(key: string, value: unknown) {
	return createTableWidgetConfig(key, value, TableType.upperDieGroup, row => row.identifier, row => row.name);
}

function createUpperDieTableWidgetConfig(key: string, value: unknown) {
	return createTableWidgetConfig(key, value, TableType.upperDie, row => row.identifier, row => row.name);
}

function createLowerDieTableWidgetConfig(key: string, value: unknown) {
	return createTableWidgetConfig(key, value, TableType.lowerDie, row => row.identifier, row => row.name);
}

function createLowerDieGroupTableWidgetConfig(key: string, value: unknown) {
	return createTableWidgetConfig(key, value, TableType.lowerDieGroup, row => row.identifier, row => row.name);
}

function createTubeMaterialTableWidgetConfig(key: string, value: unknown) {
	return createTableWidgetConfig(key, value, TableType.tubeMaterial, row => row.identifier, row => row.name);
}

function createTubeProfileTableWidgetConfig(key: string, value: unknown) {
	return createTableWidgetConfig(key, value, TableType.tubeProfile, row => row.identifier, row => row.name);
}

function createTubeSpecificationTableWidgetConfig(key: string, value: unknown) {
	return createTableWidgetConfig(key, value, TableType.tubeSpecification, row => row.identifier, row => row.name);
}

function createTubeCuttingProcessTableWidgetConfig(key: string, value: unknown) {
	return createTableWidgetConfig(key, value, TableType.tubeCuttingProcess, row => row.identifier, row => row.name);
}

function createTubeTableWidgetConfig(key: string, value: unknown) {
	return createTableWidgetConfig(key, value, TableType.tube, row => row.identifier, row => row.name);
}

function stringExtractor(input: unknown): string {
	return isString(input) ? input : wsi4.throwError("Type invalid");
}

function numberExtractor(input: unknown): number {
	return isNumber(input) ? input : wsi4.throwError("Type invalid");
}

function booleanExtractor(input: unknown): boolean {
	return isBoolean(input) ? input : wsi4.throwError("Type invalid");
}

function processTypeExtractor(input: unknown): ProcessType {
	return isProcessType(input) ? input : wsi4.throwError("Type invalid");
}

function readProprty<Row>(input: StringIndexedInterface, key: keyof Row, aliases?: Aliases<Row>): unknown {
	const keys = [ key as string ];
	if (aliases !== undefined && key in aliases) {
		keys.push(...(aliases[key] as string[]));
	}
	for (const key of keys) {
		if (key in input) {
			return input[key];
		}
	}
	return undefined;
}

function parseInput<Row>(input: StringIndexedInterface, parsers: Parsers<Row>, aliases?: Aliases<Row>): Partial<Row> {
	return getKeysOfObject(parsers)
		.reduce((incompleteRow: Partial<Row>, key) => {
			incompleteRow[key] = parsers[key](readProprty(input, key, aliases));
			return incompleteRow;
		}, {});
}

function completeRowInteractively<Row>(incompleteRow: Partial<Row>, importUtils: ImportUtils<Row>): Row|undefined {
	const dialogResult = showFormWidget(getKeysOfObject(importUtils.configGenerators)
		.map(key => importUtils.configGenerators[key](key as string, incompleteRow[key])));
	if (dialogResult !== undefined) {
		getKeysOfObject(importUtils.configGenerators)
			.forEach(key => {
				const value = dialogResult.values[key as string];
				if (incompleteRow[key] === undefined && value !== undefined) {
					incompleteRow[key] = importUtils.resultExtractors[key](value);
				}
			});
	}

	if (importUtils.isRow(incompleteRow)) {
		return incompleteRow;
	} else {
		return undefined;
	}
}

function convertToTable<Row>(input: Array<StringIndexedInterface>, importUtils: ImportUtils<Row>, interactive: boolean): Array<Row>|undefined {
	return input.reduce((acc: Array<Row>|undefined, input) => {
		if (acc === undefined) {
			return acc;
		}
		if (importUtils.isRow(input)) {
			acc.push(input);
			return acc;
		}

		const parsedRow = parseInput(input, importUtils.parsers, importUtils.aliases);
		if (importUtils.isRow(parsedRow)) {
			acc.push(parsedRow);
			return acc;
		}

		if (!interactive) {
			return undefined;
		}

		const completedRow = completeRowInteractively(parsedRow, importUtils);
		if (completedRow === undefined) {
			// user canceled
			return undefined;
		} else {
			acc.push(completedRow);
			return acc;
		}
	}, []);
}

const sheetMaterialImportUtils: ImportUtils<SheetMaterial> = {
	isRow: isSheetMaterial,
	parsers: {
		identifier: parseString,
		name: parseString,
		description: parseString,
	},
	configGenerators: {
		identifier: createStringWidgetConfig,
		name: createStringWidgetConfig,
		description: createStringWidgetConfig,
	},
	resultExtractors: {
		identifier: stringExtractor,
		name: stringExtractor,
		description: stringExtractor,
	},
};

const sheetMaterialDensityImportUtils: ImportUtils<SheetMaterialDensity> = {
	isRow: isSheetMaterialDensity,
	aliases: {
		sheetMaterialId: [ "globalMaterialId" ],
	},
	parsers: {
		sheetMaterialId: parseString,
		density: parseDouble,
	},
	configGenerators: {
		sheetMaterialId: createSheetMaterialTableWidgetConfig,
		density: createDoubleWidgetConfig,
	},
	resultExtractors: {
		sheetMaterialId: stringExtractor,
		density: numberExtractor,
	},
};

const sheetCuttingMaterialMappingUtils: ImportUtils<SheetCuttingMaterialMapping> = {
	isRow: isSheetCuttingMaterialMapping,
	aliases: {
		sheetMaterialId: [ "globalMaterialId" ],
		sheetCuttingMaterialId: [ "laserSheetCuttingMaterialId" ],
	},
	parsers: {
		sheetMaterialId: parseString,
		sheetCuttingMaterialId: parseString,
	},
	configGenerators: {
		sheetMaterialId: createSheetMaterialTableWidgetConfig,
		sheetCuttingMaterialId: createStringWidgetConfig,
	},
	resultExtractors: {
		sheetMaterialId: stringExtractor,
		sheetCuttingMaterialId: stringExtractor,
	},
};

const sheetBendingMaterialMappingUtils: ImportUtils<SheetBendingMaterialMapping> = {
	isRow: isSheetBendingMaterialMapping,
	aliases: {
		sheetMaterialId: [ "globalMaterialId" ],
		sheetBendingMaterialId: [ "bendMaterialId" ],
	},
	parsers: {
		sheetMaterialId: parseString,
		sheetBendingMaterialId: parseString,
	},
	configGenerators: {
		sheetMaterialId: createSheetMaterialTableWidgetConfig,
		sheetBendingMaterialId: createStringWidgetConfig,
	},
	resultExtractors: {
		sheetMaterialId: stringExtractor,
		sheetBendingMaterialId: stringExtractor,
	},
};

const bendTimeImportUtils: ImportUtils<BendTime> = {
	isRow: isBendTime,
	parsers: {
		mass: parseDouble,
		setupTime: parseDouble,
		setupTimePerBend: parseDouble,
		unitTime: parseDouble,
		unitTimePerBend: parseDouble,
	},
	configGenerators: {
		mass: createDoubleWidgetConfig,
		setupTime: createDoubleWidgetConfig,
		setupTimePerBend: createDoubleWidgetConfig,
		unitTime: createDoubleWidgetConfig,
		unitTimePerBend: createDoubleWidgetConfig,
	},
	resultExtractors: {
		mass: numberExtractor,
		setupTime: numberExtractor,
		setupTimePerBend: numberExtractor,
		unitTime: numberExtractor,
		unitTimePerBend: numberExtractor,
	},
};

const bendTimeParametersImportUtils: ImportUtils<BendTimeParameters> = {
	isRow: isBendTimeParameters,
	aliases: {
		sheetBendingMaterialId: [ "bendMaterialId" ],
	},
	parsers: {
		sheetBendingMaterialId: parseString,
		thickness: parseDouble,
		bendLineNetLength: parseDouble,
		setupTimeFactor: parseDouble,
		setupTimeDelta: parseDouble,
		setupTimePerBendFactor: parseDouble,
		setupTimePerBendDelta: parseDouble,
		unitTimeFactor: parseDouble,
		unitTimeDelta: parseDouble,
		unitTimePerBendFactor: parseDouble,
		unitTimePerBendDelta: parseDouble,
	},
	configGenerators: {
		sheetBendingMaterialId: createSheetBendingMaterialTableWidget,
		thickness: createDoubleWidgetConfig,
		bendLineNetLength: createDoubleWidgetConfig,
		setupTimeFactor: createDoubleWidgetConfig,
		setupTimeDelta: createDoubleWidgetConfig,
		setupTimePerBendFactor: createDoubleWidgetConfig,
		setupTimePerBendDelta: createDoubleWidgetConfig,
		unitTimeFactor: createDoubleWidgetConfig,
		unitTimeDelta: createDoubleWidgetConfig,
		unitTimePerBendFactor: createDoubleWidgetConfig,
		unitTimePerBendDelta: createDoubleWidgetConfig,
	},
	resultExtractors: {
		sheetBendingMaterialId: stringExtractor,
		thickness: numberExtractor,
		bendLineNetLength: numberExtractor,
		setupTimeFactor: numberExtractor,
		setupTimeDelta: numberExtractor,
		setupTimePerBendFactor: numberExtractor,
		setupTimePerBendDelta: numberExtractor,
		unitTimeFactor: numberExtractor,
		unitTimeDelta: numberExtractor,
		unitTimePerBendFactor: numberExtractor,
		unitTimePerBendDelta: numberExtractor,
	},
};

const bendRateParametersImportUtils: ImportUtils<BendRateParameters> = {
	isRow: isBendRateParameters,
	aliases: {
		sheetBendingMaterialId: [ "bendMaterialId" ],
	},
	parsers: {
		sheetBendingMaterialId: parseString,
		thickness: parseDouble,
		bendLineNetLength: parseDouble,
		hourlyRateFactor: parseDouble,
		hourlyRateDelta: parseDouble,
	},
	configGenerators: {
		sheetBendingMaterialId: createSheetBendingMaterialTableWidget,
		thickness: createDoubleWidgetConfig,
		bendLineNetLength: createDoubleWidgetConfig,
		hourlyRateFactor: createDoubleWidgetConfig,
		hourlyRateDelta: createDoubleWidgetConfig,
	},
	resultExtractors: {
		sheetBendingMaterialId: stringExtractor,
		thickness: numberExtractor,
		bendLineNetLength: numberExtractor,
		hourlyRateFactor: numberExtractor,
		hourlyRateDelta: numberExtractor,
	},
};

const bendLineConstraintImportUtils: ImportUtils<BendLineConstraint> = {
	isRow: isBendLineConstraint,
	aliases: {
		sheetBendingMaterialId: [ "bendMaterialId" ],
	},
	parsers: {
		sheetBendingMaterialId: parseString,
		thickness: parseDouble,
		maxNetLength: parseDouble,
	},
	configGenerators: {
		sheetBendingMaterialId: createSheetBendingMaterialTableWidget,
		thickness: createDoubleWidgetConfig,
		maxNetLength: createDoubleWidgetConfig,
	},
	resultExtractors: {
		sheetBendingMaterialId: stringExtractor,
		thickness: numberExtractor,
		maxNetLength: numberExtractor,
	},
};

const laserSheetCuttingGasImportUtils: ImportUtils<LaserSheetCuttingGas> = {
	isRow: isLaserSheetCuttingGas,
	parsers: {
		identifier: parseString,
		name: parseString,
	},
	configGenerators: {
		identifier: createStringWidgetConfig,
		name: createStringWidgetConfig,
	},
	resultExtractors: {
		identifier: stringExtractor,
		name: stringExtractor,
	},
};

const laserSheetCuttingSpeedImportUtils: ImportUtils<LaserSheetCuttingSpeed> = {
	isRow: isLaserSheetCuttingSpeed,
	aliases: {
		sheetCuttingMaterialId: [ "laserSheetCuttingMaterialId" ],
	},
	parsers: {
		sheetCuttingMaterialId: parseString,
		laserSheetCuttingGasId: parseString,
		thickness: parseDouble,
		speed: parseDouble,
	},
	configGenerators: {
		sheetCuttingMaterialId: createSheetCuttingMatrialTableWidgetConfig,
		laserSheetCuttingGasId: createLaserSheetCuttingGasTableWidgetConfig,
		thickness: createDoubleWidgetConfig,
		speed: createDoubleWidgetConfig,
	},
	resultExtractors: {
		sheetCuttingMaterialId: stringExtractor,
		laserSheetCuttingGasId: stringExtractor,
		thickness: numberExtractor,
		speed: numberExtractor,
	},
};

const laserSheetCuttingPierceTimeImportUtils: ImportUtils<LaserSheetCuttingPierceTime> = {
	isRow: isLaserSheetCuttingPierceTime,
	aliases: {
		sheetCuttingMaterialId: [ "laserSheetCuttingMaterialId" ],
	},
	parsers: {
		sheetCuttingMaterialId: parseString,
		laserSheetCuttingGasId: parseString,
		thickness: parseDouble,
		time: parseDouble,
	},
	configGenerators: {
		sheetCuttingMaterialId: createSheetCuttingMatrialTableWidgetConfig,
		laserSheetCuttingGasId: createLaserSheetCuttingGasTableWidgetConfig,
		thickness: createDoubleWidgetConfig,
		time: createDoubleWidgetConfig,
	},
	resultExtractors: {
		sheetCuttingMaterialId: stringExtractor,
		laserSheetCuttingGasId: stringExtractor,
		thickness: numberExtractor,
		time: numberExtractor,
	},
};

const laserSheetCuttingRateImportUtils: ImportUtils<LaserSheetCuttingRate> = {
	isRow: isLaserSheetCuttingRate,
	aliases: {
		sheetCuttingMaterialId: [ "laserSheetCuttingMaterialId" ],
	},
	parsers: {
		sheetCuttingMaterialId: parseString,
		laserSheetCuttingGasId: parseString,
		rate: parseDouble,
	},
	configGenerators: {
		sheetCuttingMaterialId: createSheetCuttingMatrialTableWidgetConfig,
		laserSheetCuttingGasId: createLaserSheetCuttingGasTableWidgetConfig,
		rate: createDoubleWidgetConfig,
	},
	resultExtractors: {
		sheetCuttingMaterialId: stringExtractor,
		laserSheetCuttingGasId: stringExtractor,
		rate: numberExtractor,
	},
};

const laserSheetCuttingMinAreaImportUtils: ImportUtils<LaserSheetCuttingMinArea> = {
	isRow: isLaserSheetCuttingMinArea,
	aliases: {
		sheetCuttingMaterialId: [ "laserSheetCuttingMaterialId" ],
	},
	parsers: {
		sheetCuttingMaterialId: parseString,
		laserSheetCuttingGasId: parseString,
		thickness: parseDouble,
		area: parseDouble,
	},
	configGenerators: {
		sheetCuttingMaterialId: createSheetCuttingMatrialTableWidgetConfig,
		laserSheetCuttingGasId: createLaserSheetCuttingGasTableWidgetConfig,
		thickness: createDoubleWidgetConfig,
		area: createDoubleWidgetConfig,
	},
	resultExtractors: {
		sheetCuttingMaterialId: stringExtractor,
		laserSheetCuttingGasId: stringExtractor,
		thickness: numberExtractor,
		area: numberExtractor,
	},
};

const laserSheetCuttingMaxThicknessImportUtils: ImportUtils<LaserSheetCuttingMaxThickness> = {
	isRow: isLaserSheetCuttingMaxThickness,
	aliases: {
		sheetCuttingMaterialId: [ "laserSheetCuttingMaterialId" ],
	},
	parsers: {
		sheetCuttingMaterialId: parseString,
		laserSheetCuttingGasId: parseString,
		maxThickness: parseDouble,
		minThickness: parseDouble,
	},
	configGenerators: {
		sheetCuttingMaterialId: createSheetCuttingMatrialTableWidgetConfig,
		laserSheetCuttingGasId: createLaserSheetCuttingGasTableWidgetConfig,
		maxThickness: createDoubleWidgetConfig,
		minThickness: createDoubleWidgetConfig,
	},
	resultExtractors: {
		sheetCuttingMaterialId: stringExtractor,
		laserSheetCuttingGasId: stringExtractor,
		maxThickness: numberExtractor,
		minThickness: numberExtractor,
	},
};

const packagingImportUtils: ImportUtils<Packaging> = {
	isRow: isPackaging,
	parsers: {
		identifier: parseString,
		name: parseString,
		dimX: parseDouble,
		dimY: parseDouble,
		dimZ: parseDouble,
		maxWeight: parseDouble,
		price: parseDouble,
		tr: parseDouble,
		tep: parseDouble,
		tea: parseDouble,
		packagingWeight: parseDouble,
	},
	configGenerators: {
		identifier: createStringWidgetConfig,
		name: createStringWidgetConfig,
		dimX: createDoubleWidgetConfig,
		dimY: createDoubleWidgetConfig,
		dimZ: createDoubleWidgetConfig,
		maxWeight: createDoubleWidgetConfig,
		price: createDoubleWidgetConfig,
		tr: createDoubleWidgetConfig,
		tep: createDoubleWidgetConfig,
		tea: createDoubleWidgetConfig,
		packagingWeight: createDoubleWidgetConfig,
	},
	resultExtractors: {
		identifier: stringExtractor,
		name: stringExtractor,
		dimX: numberExtractor,
		dimY: numberExtractor,
		dimZ: numberExtractor,
		maxWeight: numberExtractor,
		price: numberExtractor,
		tr: numberExtractor,
		tep: numberExtractor,
		tea: numberExtractor,
		packagingWeight: numberExtractor,
	},
};

const transportationCostsImportUtils: ImportUtils<TransportationCosts> = {
	isRow: isTransportationCosts,
	parsers: {
		identifier: parseString,
		name: parseString,
		packagingId: parseString,
		fixedCosts: parseDouble,
		minCosts: parseDouble,
		kmKgFactor: parseDouble,
		kmFactor: parseDouble,
	},
	configGenerators: {
		identifier: createStringWidgetConfig,
		name: createStringWidgetConfig,
		packagingId: createPackagingTableWidgetConfig,
		fixedCosts: createDoubleWidgetConfig,
		minCosts: createDoubleWidgetConfig,
		kmKgFactor: createDoubleWidgetConfig,
		kmFactor: createDoubleWidgetConfig,
	},
	resultExtractors: {
		identifier: stringExtractor,
		name: stringExtractor,
		packagingId: stringExtractor,
		fixedCosts: numberExtractor,
		minCosts: numberExtractor,
		kmKgFactor: numberExtractor,
		kmFactor: numberExtractor,
	},
};

const surchargeImportUtils: ImportUtils<Surcharge> = {
	isRow: isSurcharge,
	parsers: {
		name: parseString,
		type: parseString,
		value: parseDouble,
		description: parseString,
	},
	configGenerators: {
		name: createStringWidgetConfig,
		type: createStringWidgetConfig,
		value: createDoubleWidgetConfig,
		description: createStringWidgetConfig,
	},
	resultExtractors: {
		name: stringExtractor,
		type: stringExtractor,
		value: numberExtractor,
		description: stringExtractor,
	},
};

const processImportUtils: ImportUtils<Process> = {
	isRow: isProcess,
	parsers: {
		identifier: parseString,
		parentIdentifier: parseString,
		type: parseProcessType,
		name: parseString,
		costCenter: parseString,
		active: parseBoolean,
		childrenActive: parseBoolean,
		description: parseString,
	},
	configGenerators: {
		identifier: createStringWidgetConfig,
		parentIdentifier: createStringWidgetConfig,
		type: createProcessTypeWidgetConfig,
		name: createStringWidgetConfig,
		costCenter: createStringWidgetConfig,
		active: createBooleanWidgetConfig,
		childrenActive: createBooleanWidgetConfig,
		description: createStringWidgetConfig,
	},
	resultExtractors: {
		identifier: stringExtractor,
		parentIdentifier: stringExtractor,
		type: processTypeExtractor,
		name: stringExtractor,
		costCenter: stringExtractor,
		active: booleanExtractor,
		childrenActive: booleanExtractor,
		description: stringExtractor,
	},
};

const processRateImportUtils: ImportUtils<ProcessRate> = {
	isRow: isProcessRate,
	parsers: {
		processId: parseString,
		rate: parseDouble,
	},
	configGenerators: {
		processId: createProcessTableWidgetConfig,
		rate: createDoubleWidgetConfig,
	},
	resultExtractors: {
		processId: stringExtractor,
		rate: numberExtractor,
	},
};

const processSetupTimeFallbackImportUtils: ImportUtils<ProcessSetupTimeFallback> = {
	isRow: isProcessSetupTimeFallback,
	parsers: {
		processId: parseString,
		time: parseDouble,
	},
	configGenerators: {
		processId: createProcessTableWidgetConfig,
		time: createDoubleWidgetConfig,
	},
	resultExtractors: {
		processId: stringExtractor,
		time: numberExtractor,
	},
};

const processUnitTimeFallbackImportUtils: ImportUtils<ProcessUnitTimeFallback> = {
	isRow: isProcessUnitTimeFallback,
	parsers: {
		processId: parseString,
		time: parseDouble,
	},
	configGenerators: {
		processId: createProcessTableWidgetConfig,
		time: createDoubleWidgetConfig,
	},
	resultExtractors: {
		processId: stringExtractor,
		time: numberExtractor,
	},
};

const sheetImportUtils: ImportUtils<Sheet> = {
	isRow: isSheet,
	aliases: {
		sheetMaterialId: [ "globalMaterialId" ],
	},
	parsers: {
		identifier: parseString,
		name: parseString,
		sheetMaterialId: parseString,
		dimX: parseDouble,
		dimY: parseDouble,
		thickness: parseDouble,
		description: parseString,
	},
	configGenerators: {
		identifier: createStringWidgetConfig,
		name: createStringWidgetConfig,
		sheetMaterialId: createSheetMaterialTableWidgetConfig,
		dimX: createDoubleWidgetConfig,
		dimY: createDoubleWidgetConfig,
		thickness: createDoubleWidgetConfig,
		description: createStringWidgetConfig,
	},
	resultExtractors: {
		identifier: stringExtractor,
		name: stringExtractor,
		sheetMaterialId: stringExtractor,
		dimX: numberExtractor,
		dimY: numberExtractor,
		thickness: numberExtractor,
		description: stringExtractor,
	},
};

const sheetModulusImportUtils: ImportUtils<SheetModulus> = {
	isRow: isSheetModulus,
	parsers: {
		sheetId: parseString,
		xModulus: parseDouble,
		yModulus: parseDouble,
		applyToAll: parseBoolean,
	},
	configGenerators: {
		sheetId: createSheetTableWidgetConfig,
		xModulus: createDoubleWidgetConfig,
		yModulus: createDoubleWidgetConfig,
		applyToAll: createBooleanWidgetConfig,
	},
	resultExtractors: {
		sheetId: stringExtractor,
		xModulus: numberExtractor,
		yModulus: numberExtractor,
		applyToAll: booleanExtractor,
	},
};

const sheetPriceImportUtils: ImportUtils<SheetPrice> = {
	isRow: isSheetPrice,
	parsers: {
		sheetId: parseString,
		pricePerSheet: parseDouble,
	},
	configGenerators: {
		sheetId: createSheetTableWidgetConfig,
		pricePerSheet: createDoubleWidgetConfig,
	},
	resultExtractors: {
		sheetId: stringExtractor,
		pricePerSheet: numberExtractor,
	},
};

const upperDieGroupImportUtils: ImportUtils<UpperDieGroup> = {
	isRow: isUpperDieGroup,
	parsers: {
		identifier: parseString,
		name: parseString,
		exportIdentifier: parseString,
		radius: parseDouble,
	},
	configGenerators: {
		identifier: createStringWidgetConfig,
		name: createStringWidgetConfig,
		exportIdentifier: createStringWidgetConfig,
		radius: createDoubleWidgetConfig,
	},
	resultExtractors: {
		identifier: stringExtractor,
		name: stringExtractor,
		exportIdentifier: stringExtractor,
		radius: numberExtractor,
	},
};

const lowerDieGroupImportUtils: ImportUtils<LowerDieGroup> = {
	isRow: isLowerDieGroup,
	parsers: {
		identifier: parseString,
		name: parseString,
		exportIdentifier: parseString,
		openingWidth: parseDouble,
	},
	configGenerators: {
		identifier: createStringWidgetConfig,
		name: createStringWidgetConfig,
		exportIdentifier: createStringWidgetConfig,
		openingWidth: createDoubleWidgetConfig,
	},
	resultExtractors: {
		identifier: stringExtractor,
		name: stringExtractor,
		exportIdentifier: stringExtractor,
		openingWidth: numberExtractor,
	},
};

const bendDeductionImportUtils: ImportUtils<BendDeduction> = {
	isRow: isBendDeduction,
	aliases: {
		sheetBendingMaterialId: [ "bendMaterialId" ],
	},
	parsers: {
		sheetBendingMaterialId: parseString,
		upperDieGroupId: parseString,
		lowerDieGroupId: parseString,
		thickness: parseDouble,
		bendAngle: parseDouble,
		innerRadius: parseDouble,
		sharpDeduction: parseDouble,
	},
	configGenerators: {
		sheetBendingMaterialId: createSheetBendingMaterialTableWidget,
		upperDieGroupId: createUpperDieGroupTableWidgetConfig,
		lowerDieGroupId: createLowerDieGroupTableWidgetConfig,
		thickness: createDoubleWidgetConfig,
		bendAngle: createDoubleWidgetConfig,
		innerRadius: createDoubleWidgetConfig,
		sharpDeduction: createDoubleWidgetConfig,
	},
	resultExtractors: {
		sheetBendingMaterialId: stringExtractor,
		upperDieGroupId: stringExtractor,
		lowerDieGroupId: stringExtractor,
		thickness: numberExtractor,
		bendAngle: numberExtractor,
		innerRadius: numberExtractor,
		sharpDeduction: numberExtractor,
	},
};

const settingImportUtils: ImportUtils<Setting> = {
	isRow: isSetting,
	parsers: {
		key: parseString,
		value: parseString,
	},
	configGenerators: {
		key: createStringWidgetConfig,
		value: createStringWidgetConfig,
	},
	resultExtractors: {
		key: stringExtractor,
		value: stringExtractor,
	},
};

const automaticMechanicalDeburringMaterialImportUtils: ImportUtils<AutomaticMechanicalDeburringMaterial> = {
	isRow: isAutomaticMechanicalDeburringMaterial,
	aliases: {
		sheetMaterialId: [ "globalMaterialId" ],
	},
	parsers: {
		sheetMaterialId: parseString,
		automaticMechanicalDeburringMaterialId: parseString,
	},
	configGenerators: {
		sheetMaterialId: createSheetMaterialTableWidgetConfig,
		automaticMechanicalDeburringMaterialId: createStringWidgetConfig,
	},
	resultExtractors: {
		sheetMaterialId: stringExtractor,
		automaticMechanicalDeburringMaterialId: stringExtractor,
	},
};

const automaticMechanicalDeburringParametersImportUtils: ImportUtils<AutomaticMechanicalDeburringParameters> = {
	isRow: isAutomaticMechanicalDeburringParameters,
	parsers: {
		automaticMechanicalDeburringMaterialId: parseString,
		maxDimY: parseDouble,
		unitTimeBase: parseDouble,
		speed: parseDouble,
	},
	configGenerators: {
		automaticMechanicalDeburringMaterialId: createAutomaticMechanicalDeburringMaterialTableWidgetConfig,
		maxDimY: createDoubleWidgetConfig,
		unitTimeBase: createDoubleWidgetConfig,
		speed: createDoubleWidgetConfig,
	},
	resultExtractors: {
		automaticMechanicalDeburringMaterialId: stringExtractor,
		maxDimY: numberExtractor,
		unitTimeBase: numberExtractor,
		speed: numberExtractor,
	},
};

const dimensionConstraintsImportUtils: ImportUtils<DimensionConstraints> = {
	isRow: isDimensionConstraints,
	parsers: {
		processId: parseString,
		minX: parseDouble,
		minY: parseDouble,
		minZ: parseDouble,
		maxX: parseDouble,
		maxY: parseDouble,
		maxZ: parseDouble,
	},
	configGenerators: {
		processId: createProcessTableWidgetConfig,
		minX: createDoubleWidgetConfig,
		minY: createDoubleWidgetConfig,
		minZ: createDoubleWidgetConfig,
		maxX: createDoubleWidgetConfig,
		maxY: createDoubleWidgetConfig,
		maxZ: createDoubleWidgetConfig,
	},
	resultExtractors: {
		processId: stringExtractor,
		minX: numberExtractor,
		minY: numberExtractor,
		minZ: numberExtractor,
		maxX: numberExtractor,
		maxY: numberExtractor,
		maxZ: numberExtractor,
	},
};

const screwThreadImportUtils: ImportUtils<ScrewThread> = {
	isRow: isScrewThread,
	parsers: {
		identifier: parseString,
		name: parseString,
		coreHoleDiameter: parseDouble,
		minDepth: parseDouble,
		symmetricTolerance: parseDouble,
	},
	configGenerators: {
		identifier: createStringWidgetConfig,
		name: createStringWidgetConfig,
		coreHoleDiameter: createDoubleWidgetConfig,
		minDepth: createDoubleWidgetConfig,
		symmetricTolerance: createDoubleWidgetConfig,
	},
	resultExtractors: {
		identifier: stringExtractor,
		name: stringExtractor,
		coreHoleDiameter: numberExtractor,
		minDepth: numberExtractor,
		symmetricTolerance: numberExtractor,
	},
};

const tappingTimeParametersImportUtils: ImportUtils<TappingTimeParameters> = {
	isRow: isTappingTimeParameters,
	parsers: {
		processId: parseString,
		screwThreadId: parseString,
		unitTimePerMm: parseDouble,
	},
	configGenerators: {
		processId: createProcessTableWidgetConfig,
		screwThreadId: createScrewThreadTableWidgetConfig,
		unitTimePerMm: createDoubleWidgetConfig,
	},
	resultExtractors: {
		processId: stringExtractor,
		screwThreadId: stringExtractor,
		unitTimePerMm: numberExtractor,
	},
};

const tubeMaterialImportUtils: ImportUtils<TubeMaterial> = {
	isRow: isTubeMaterial,
	parsers: {
		identifier: parseString,
		name: parseString,
		description: parseString,
	},
	configGenerators: {
		identifier: createStringWidgetConfig,
		name: createStringWidgetConfig,
		description: createStringWidgetConfig,
	},
	resultExtractors: {
		identifier: stringExtractor,
		name: stringExtractor,
		description: stringExtractor,
	},
};

const tubeMaterialDensityImportUtils: ImportUtils<TubeMaterialDensity> = {
	isRow: isTubeMaterialDensity,
	parsers: {
		tubeMaterialId: parseString,
		density: parseDouble,
	},
	configGenerators: {
		tubeMaterialId: createTubeMaterialTableWidgetConfig,
		density: createDoubleWidgetConfig,
	},
	resultExtractors: {
		tubeMaterialId: stringExtractor,
		density: numberExtractor,
	},
};

const tubeProfileImportUtils: ImportUtils<TubeProfile> = {
	isRow: isTubeProfile,
	parsers: {
		identifier: parseString,
		name: parseString,
		description: parseString,
		geometryJson: parseString,
	},
	configGenerators: {
		identifier: createStringWidgetConfig,
		name: createStringWidgetConfig,
		description: createStringWidgetConfig,
		geometryJson: createStringWidgetConfig,
	},
	resultExtractors: {
		identifier: stringExtractor,
		name: stringExtractor,
		description: stringExtractor,
		geometryJson: stringExtractor,
	},
};

const tubeSpecificationImportUtils: ImportUtils<TubeSpecification> = {
	isRow: isTubeMaterial,
	parsers: {
		identifier: parseString,
		name: parseString,
		description: parseString,
	},
	configGenerators: {
		identifier: createStringWidgetConfig,
		name: createStringWidgetConfig,
		description: createStringWidgetConfig,
	},
	resultExtractors: {
		identifier: stringExtractor,
		name: stringExtractor,
		description: stringExtractor,
	},
};

const tubeImportUtils: ImportUtils<Tube> = {
	isRow: isTube,
	parsers: {
		identifier: parseString,
		name: parseString,
		tubeMaterialId: parseString,
		tubeProfileId: parseString,
		tubeSpecificationId: parseString,
		dimX: parseDouble,
	},
	configGenerators: {
		identifier: createStringWidgetConfig,
		name: createStringWidgetConfig,
		tubeMaterialId: createTubeMaterialTableWidgetConfig,
		tubeProfileId: createTubeProfileTableWidgetConfig,
		tubeSpecificationId: createTubeSpecificationTableWidgetConfig,
		dimX: createDoubleWidgetConfig,
	},
	resultExtractors: {
		identifier: stringExtractor,
		name: stringExtractor,
		tubeMaterialId: stringExtractor,
		tubeProfileId: stringExtractor,
		tubeSpecificationId: stringExtractor,
		dimX: numberExtractor,
	},
};

const upperDieImportUtils: ImportUtils<UpperDie> = {
	isRow: isUpperDie,
	parsers: {
		identifier: parseString,
		name: parseString,
		upperDieGroupId: parseString,
		description: parseString,
	},
	configGenerators: {
		identifier: createStringWidgetConfig,
		name: createStringWidgetConfig,
		upperDieGroupId: createUpperDieGroupTableWidgetConfig,
		description: createStringWidgetConfig,
	},
	resultExtractors: {
		identifier: stringExtractor,
		name: stringExtractor,
		upperDieGroupId: stringExtractor,
		description: stringExtractor,
	},
};

const lowerDieImportUtils: ImportUtils<LowerDie> = {
	isRow: isLowerDie,
	parsers: {
		identifier: parseString,
		name: parseString,
		lowerDieGroupId: parseString,
		description: parseString,
	},
	configGenerators: {
		identifier: createStringWidgetConfig,
		name: createStringWidgetConfig,
		lowerDieGroupId: createLowerDieGroupTableWidgetConfig,
		description: createStringWidgetConfig,
	},
	resultExtractors: {
		identifier: stringExtractor,
		name: stringExtractor,
		lowerDieGroupId: stringExtractor,
		description: stringExtractor,
	},
};

const upperDieUnitImportUtils: ImportUtils<UpperDieUnit> = {
	isRow: isUpperDieUnit,
	parsers: {
		upperDieId: parseString,
		dimX: parseDouble,
		multiplicity: parseInt,
	},
	configGenerators: {
		upperDieId: createUpperDieTableWidgetConfig,
		dimX: createDoubleWidgetConfig,
		multiplicity: createIntWidgetConfig,
	},
	resultExtractors: {
		upperDieId: stringExtractor,
		dimX: numberExtractor,
		multiplicity: numberExtractor,
	},
};

const lowerDieUnitImportUtils: ImportUtils<LowerDieUnit> = {
	isRow: isLowerDieUnit,
	parsers: {
		lowerDieId: parseString,
		dimX: parseDouble,
		multiplicity: parseInt,
	},
	configGenerators: {
		lowerDieId: createLowerDieTableWidgetConfig,
		dimX: createDoubleWidgetConfig,
		multiplicity: createIntWidgetConfig,
	},
	resultExtractors: {
		lowerDieId: stringExtractor,
		dimX: numberExtractor,
		multiplicity: numberExtractor,
	},
};

const processHandlingTimeImportUtils: ImportUtils<ProcessHandlingTime> = {
	isRow: isProcessHandlingTime,
	parsers: {
		processId: parseString,
		mass: parseDouble,
		setupTimeDelta: parseDouble,
		unitTimeDelta: parseDouble,
	},
	configGenerators: {
		processId: createProcessTableWidgetConfig,
		mass: createDoubleWidgetConfig,
		setupTimeDelta: createDoubleWidgetConfig,
		unitTimeDelta: createDoubleWidgetConfig,
	},
	resultExtractors: {
		processId: stringExtractor,
		mass: numberExtractor,
		setupTimeDelta: numberExtractor,
		unitTimeDelta: numberExtractor,
	},
};

const sheetStockImportUtils: ImportUtils<SheetStock> = {
	isRow: isSheetStock,
	parsers: {
		sheetId: parseString,
		count: parseInt,
	},
	configGenerators: {
		sheetId: createSheetTableWidgetConfig,
		count: createIntWidgetConfig,
	},
	resultExtractors: {
		sheetId: stringExtractor,
		count: numberExtractor,
	},
};

const processIdlePeriodUtils: ImportUtils<ProcessIdlePeriod> = {
	isRow: isProcessIdlePeriod,
	parsers: {
		processId: parseString,
		time: parseDouble,
	},
	configGenerators: {
		processId: createProcessTableWidgetConfig,
		time: createDoubleWidgetConfig,
	},
	resultExtractors: {
		processId: stringExtractor,
		time: numberExtractor,
	},
};

const sheetMaterialScrapValueUtils: ImportUtils<SheetMaterialScrapValue> = {
	isRow: isSheetMaterialScrapValue,
	parsers: {
		sheetMaterialId: parseString,
		scrapValue: parseDouble,
	},
	configGenerators: {
		sheetMaterialId: createSheetMaterialTableWidgetConfig,
		scrapValue: createIntWidgetConfig,
	},
	resultExtractors: {
		sheetMaterialId: stringExtractor,
		scrapValue: numberExtractor,
	},
};

const sheetPriorityUtils: ImportUtils<SheetPriority> = {
	isRow: isSheetPriority,
	parsers: {
		sheetId: parseString,
		priority: parseInt,
	},
	configGenerators: {
		sheetId: createSheetTableWidgetConfig,
		priority: createIntWidgetConfig,
	},
	resultExtractors: {
		sheetId: stringExtractor,
		priority: numberExtractor,
	},
};

const dieGroupPriorityUtils: ImportUtils<DieGroupPriority> = {
	isRow: isDieGroupPriority,
	aliases: {
		sheetBendingMaterialId: [ "bendMaterialId" ],
	},
	parsers: {
		upperDieGroupId: parseString,
		lowerDieGroupId: parseString,
		sheetBendingMaterialId: parseString,
		sheetThickness: parseDouble,
		priority: parseInt,
	},
	configGenerators: {
		upperDieGroupId: createUpperDieGroupTableWidgetConfig,
		lowerDieGroupId: createLowerDieGroupTableWidgetConfig,
		sheetBendingMaterialId: createSheetCuttingMatrialTableWidgetConfig,
		sheetThickness: createDoubleWidgetConfig,
		priority: createIntWidgetConfig,
	},
	resultExtractors: {
		upperDieGroupId: stringExtractor,
		lowerDieGroupId: stringExtractor,
		sheetBendingMaterialId: stringExtractor,
		sheetThickness: numberExtractor,
		priority: numberExtractor,
	},
};

const sheetCuttingMaterialUtils: ImportUtils<SheetCuttingMaterial> = {
	isRow: isSheetCuttingMaterial,
	parsers: {
		identifier: parseString,
		name: parseString,
	},
	configGenerators: {
		identifier: createStringWidgetConfig,
		name: createStringWidgetConfig,
	},
	resultExtractors: {
		identifier: stringExtractor,
		name: stringExtractor,
	},
};

const sheetBendingMaterialUtils: ImportUtils<SheetBendingMaterial> = {
	isRow: isSheetBendingMaterial,
	parsers: {
		identifier: parseString,
		name: parseString,
	},
	configGenerators: {
		identifier: createStringWidgetConfig,
		name: createStringWidgetConfig,
	},
	resultExtractors: {
		identifier: stringExtractor,
		name: stringExtractor,
	},
};

const tubeCuttingProcessUtils: ImportUtils<TubeCuttingProcess> = {
	isRow: isTubeCuttingProcess,
	parsers: {
		identifier: parseString,
		name: parseString,
	},
	configGenerators: {
		identifier: createStringWidgetConfig,
		name: createStringWidgetConfig,
	},
	resultExtractors: {
		identifier: stringExtractor,
		name: stringExtractor,
	},
};

const tubeCuttingProcessMappingUtils: ImportUtils<TubeCuttingProcessMapping> = {
	isRow: isTubeCuttingProcessMapping,
	parsers: {
		processId: parseString,
		tubeMaterialId: parseString,
		tubeCuttingProcessId: parseString,
	},
	configGenerators: {
		processId: createProcessTableWidgetConfig,
		tubeMaterialId: createTubeMaterialTableWidgetConfig,
		tubeCuttingProcessId: createTubeCuttingProcessTableWidgetConfig,
	},
	resultExtractors: {
		processId: stringExtractor,
		tubeMaterialId: stringExtractor,
		tubeCuttingProcessId: stringExtractor,
	},
};

const tubeCuttingSpeedUtils: ImportUtils<TubeCuttingSpeed> = {
	isRow: isTubeCuttingSpeed,
	parsers: {
		tubeCuttingProcessId: parseString,
		thickness: parseDouble,
		speed: parseDouble,
	},
	configGenerators: {
		tubeCuttingProcessId: createProcessTableWidgetConfig,
		thickness: createDoubleWidgetConfig,
		speed: createDoubleWidgetConfig,
	},
	resultExtractors: {
		tubeCuttingProcessId: stringExtractor,
		thickness: numberExtractor,
		speed: numberExtractor,
	},
};

const tubeCuttingPierceTimeUtils: ImportUtils<TubeCuttingPierceTime> = {
	isRow: isTubeCuttingPierceTime,
	parsers: {
		tubeCuttingProcessId: parseString,
		thickness: parseDouble,
		time: parseDouble,
	},
	configGenerators: {
		tubeCuttingProcessId: createProcessTableWidgetConfig,
		thickness: createDoubleWidgetConfig,
		time: createDoubleWidgetConfig,
	},
	resultExtractors: {
		tubeCuttingProcessId: stringExtractor,
		thickness: numberExtractor,
		time: numberExtractor,
	},
};

const tubePriceUtils: ImportUtils<TubePrice> = {
	isRow: isTubePrice,
	parsers: {
		tubeId: parseString,
		pricePerTube: parseDouble,
	},
	configGenerators: {
		tubeId: createTubeTableWidgetConfig,
		pricePerTube: createDoubleWidgetConfig,
	},
	resultExtractors: {
		tubeId: stringExtractor,
		pricePerTube: numberExtractor,
	},
};

const tubeStockUtils: ImportUtils<TubeStock> = {
	isRow: isTubeStock,
	parsers: {
		tubeId: parseString,
		count: parseInt,
	},
	configGenerators: {
		tubeId: createTubeTableWidgetConfig,
		count: createIntWidgetConfig,
	},
	resultExtractors: {
		tubeId: stringExtractor,
		count: numberExtractor,
	},
};

const tubeMaterialScrapValue: ImportUtils<TubeMaterialScrapValue> = {
	isRow: isTubeMaterialScrapValue,
	parsers: {
		tubeMaterialId: parseString,
		scrapValue: parseDouble,
	},
	configGenerators: {
		tubeMaterialId: createTubeTableWidgetConfig,
		scrapValue: createDoubleWidgetConfig,
	},
	resultExtractors: {
		tubeMaterialId: stringExtractor,
		scrapValue: numberExtractor,
	},
};

/**
 * Create AnyTable from potentially invalid / incomplete input
 *
 * If input cannot be deduced the user will be asked to complete the input.
 *
 * @param input The input
 * @returns undefined if table cannot be completed and user canceles; completed AnyTable else
 */
export function convertToAnyTable(input: PotentialAnyTable, interactive = false): AnyTable|undefined {
	const content = (() => {
		switch (input.type) {
			case TableType.sheetMaterial: return convertToTable(input.content, sheetMaterialImportUtils, interactive);
			case TableType.sheetMaterialDensity: return convertToTable(input.content, sheetMaterialDensityImportUtils, interactive);
			case TableType.sheetCuttingMaterialMapping: return convertToTable(input.content, sheetCuttingMaterialMappingUtils, interactive);
			case TableType.sheetBendingMaterialMapping: return convertToTable(input.content, sheetBendingMaterialMappingUtils, interactive);
			case TableType.bendTime: return convertToTable(input.content, bendTimeImportUtils, interactive);
			case TableType.bendTimeParameters: return convertToTable(input.content, bendTimeParametersImportUtils, interactive);
			case TableType.bendRateParameters: return convertToTable(input.content, bendRateParametersImportUtils, interactive);
			case TableType.bendLineConstraint: return convertToTable(input.content, bendLineConstraintImportUtils, interactive);
			case TableType.laserSheetCuttingGas: return convertToTable(input.content, laserSheetCuttingGasImportUtils, interactive);
			case TableType.laserSheetCuttingSpeed: return convertToTable(input.content, laserSheetCuttingSpeedImportUtils, interactive);
			case TableType.laserSheetCuttingPierceTime: return convertToTable(input.content, laserSheetCuttingPierceTimeImportUtils, interactive);
			case TableType.laserSheetCuttingRate: return convertToTable(input.content, laserSheetCuttingRateImportUtils, interactive);
			case TableType.laserSheetCuttingMinArea: return convertToTable(input.content, laserSheetCuttingMinAreaImportUtils, interactive);
			case TableType.laserSheetCuttingMaxThickness: return convertToTable(input.content, laserSheetCuttingMaxThicknessImportUtils, interactive);
			case TableType.packaging: return convertToTable(input.content, packagingImportUtils, interactive);
			case TableType.transportationCosts: return convertToTable(input.content, transportationCostsImportUtils, interactive);
			case TableType.surcharge: return convertToTable(input.content, surchargeImportUtils, interactive);
			case TableType.process: return convertToTable(input.content, processImportUtils, interactive);
			case TableType.processRate: return convertToTable(input.content, processRateImportUtils, interactive);
			case TableType.processSetupTimeFallback: return convertToTable(input.content, processSetupTimeFallbackImportUtils, interactive);
			case TableType.processUnitTimeFallback: return convertToTable(input.content, processUnitTimeFallbackImportUtils, interactive);
			case TableType.sheet: return convertToTable(input.content, sheetImportUtils, interactive);
			case TableType.sheetModulus: return convertToTable(input.content, sheetModulusImportUtils, interactive);
			case TableType.sheetPrice: return convertToTable(input.content, sheetPriceImportUtils, interactive);
			case TableType.upperDieGroup: return convertToTable(input.content, upperDieGroupImportUtils, interactive);
			case TableType.lowerDieGroup: return convertToTable(input.content, lowerDieGroupImportUtils, interactive);
			case TableType.bendDeduction: return convertToTable(input.content, bendDeductionImportUtils, interactive);
			case TableType.setting: return convertToTable(input.content, settingImportUtils, interactive);
			case TableType.automaticMechanicalDeburringMaterial: return convertToTable(input.content, automaticMechanicalDeburringMaterialImportUtils, interactive);
			case TableType.automaticMechanicalDeburringParameters: return convertToTable(input.content, automaticMechanicalDeburringParametersImportUtils, interactive);
			case TableType.dimensionConstraints: return convertToTable(input.content, dimensionConstraintsImportUtils, interactive);
			case TableType.screwThread: return convertToTable(input.content, screwThreadImportUtils, interactive);
			case TableType.tappingTimeParameters: return convertToTable(input.content, tappingTimeParametersImportUtils, interactive);
			case TableType.tubeMaterial: return convertToTable(input.content, tubeMaterialImportUtils, interactive);
			case TableType.tubeMaterialDensity: return convertToTable(input.content, tubeMaterialDensityImportUtils, interactive);
			case TableType.tubeProfile: return convertToTable(input.content, tubeProfileImportUtils, interactive);
			case TableType.tubeSpecification: return convertToTable(input.content, tubeSpecificationImportUtils, interactive);
			case TableType.tube: return convertToTable(input.content, tubeImportUtils, interactive);
			case TableType.upperDie: return convertToTable(input.content, upperDieImportUtils, interactive);
			case TableType.lowerDie: return convertToTable(input.content, lowerDieImportUtils, interactive);
			case TableType.upperDieUnit: return convertToTable(input.content, upperDieUnitImportUtils, interactive);
			case TableType.lowerDieUnit: return convertToTable(input.content, lowerDieUnitImportUtils, interactive);
			case TableType.processHandlingTime: return convertToTable(input.content, processHandlingTimeImportUtils, interactive);
			case TableType.sheetStock: return convertToTable(input.content, sheetStockImportUtils, interactive);
			case TableType.processIdlePeriod: return convertToTable(input.content, processIdlePeriodUtils, interactive);
			case TableType.sheetMaterialScrapValue: return convertToTable(input.content, sheetMaterialScrapValueUtils, interactive);
			case TableType.sheetPriority: return convertToTable(input.content, sheetPriorityUtils, interactive);
			case TableType.dieGroupPriority: return convertToTable(input.content, dieGroupPriorityUtils, interactive);
			case TableType.sheetCuttingMaterial: return convertToTable(input.content, sheetCuttingMaterialUtils, interactive);
			case TableType.sheetBendingMaterial: return convertToTable(input.content, sheetBendingMaterialUtils, interactive);
			case TableType.tubeCuttingProcess: return convertToTable(input.content, tubeCuttingProcessUtils, interactive);
			case TableType.tubeCuttingProcessMapping: return convertToTable(input.content, tubeCuttingProcessMappingUtils, interactive);
			case TableType.tubeCuttingSpeed: return convertToTable(input.content, tubeCuttingSpeedUtils, interactive);
			case TableType.tubeCuttingPierceTime: return convertToTable(input.content, tubeCuttingPierceTimeUtils, interactive);
			case TableType.tubePrice: return convertToTable(input.content, tubePriceUtils, interactive);
			case TableType.tubeStock: return convertToTable(input.content, tubeStockUtils, interactive);
			case TableType.tubeMaterialScrapValue: return convertToTable(input.content, tubeMaterialScrapValue, interactive);
		}
	})();
	if (content === undefined) {
		return undefined;
	} else {
		return {
			type: input.type,
			content: content,
		};
	}
}
