"use strict";
Object.defineProperty(exports, "__esModule", {
    value: true
});
Object.defineProperty(exports, "BGCodeParser", {
    enumerable: true,
    get: function() {
        return BGCodeParser;
    }
});
const _nodepath = /*#__PURE__*/ _interop_require_default(require("node:path"));
const _promises = /*#__PURE__*/ _interop_require_wildcard(require("node:fs/promises"));
const _bgcodeutils = require("../bgcode/bgcode.utils");
const _bgcodetypes = require("../bgcode/bgcode.types");
const _bgcodethumbnailparser = require("../bgcode/bgcode-thumbnail.parser");
function _interop_require_default(obj) {
    return obj && obj.__esModule ? obj : {
        default: obj
    };
}
function _getRequireWildcardCache(nodeInterop) {
    if (typeof WeakMap !== "function") return null;
    var cacheBabelInterop = new WeakMap();
    var cacheNodeInterop = new WeakMap();
    return (_getRequireWildcardCache = function(nodeInterop) {
        return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
    })(nodeInterop);
}
function _interop_require_wildcard(obj, nodeInterop) {
    if (!nodeInterop && obj && obj.__esModule) {
        return obj;
    }
    if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
        return {
            default: obj
        };
    }
    var cache = _getRequireWildcardCache(nodeInterop);
    if (cache && cache.has(obj)) {
        return cache.get(obj);
    }
    var newObj = {
        __proto__: null
    };
    var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
    for(var key in obj){
        if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
            var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
            if (desc && (desc.get || desc.set)) {
                Object.defineProperty(newObj, key, desc);
            } else {
                newObj[key] = obj[key];
            }
        }
    }
    newObj.default = obj;
    if (cache) {
        cache.set(obj, newObj);
    }
    return newObj;
}
class BGCodeParser {
    async parse(filePath) {
        const stats = await _promises.default.stat(filePath);
        const fileName = _nodepath.default.basename(filePath);
        const fileHandle = await (0, _promises.open)(filePath, "r");
        try {
            const { version, checksumType } = await (0, _bgcodeutils.parseFileHeader)(fileHandle);
            if (version !== 1) {
                throw new Error(`Unsupported BGCode version: ${version}`);
            }
            const blockHeaders = await (0, _bgcodeutils.parseBlockHeaders)(fileHandle, stats.size, checksumType, true);
            const metadata = await (0, _bgcodeutils.extractMetadataFromBlocks)(fileHandle, blockHeaders);
            const thumbnails = await this.extractThumbnailsFromBlocks(fileHandle, blockHeaders);
            const isMmu = this.isMmuData(metadata.nozzle_diameter) || this.isMmuData(metadata.temperature) || this.isMmuData(metadata.filament_used_mm) || this.isMmuData(metadata.bed_temperature) || this.isMmuData(metadata.filament_type, ';');
            const normalized = {
                fileName,
                fileFormat: "bgcode",
                fileSize: stats.size,
                producer: metadata.producer,
                producedOn: metadata.produced_on,
                checksumType: checksumType === 1 ? "CRC32" : "None",
                isMmu: isMmu || undefined,
                gcodePrintTimeSeconds: this.parseTime(metadata.estimated_printing_time_normal_mode || metadata.print_time),
                gcodePrintTimeSecondsSilent: this.parseTime(metadata.estimated_printing_time_silent_mode),
                nozzleDiameterMm: isMmu ? this.parseNumberArray(metadata.nozzle_diameter) : this.parseFirstValue(metadata.nozzle_diameter),
                filamentDiameterMm: isMmu ? this.parseNumberArray(metadata.filament_diameter) : this.parseFirstValue(metadata.filament_diameter) || 1.75,
                filamentDensityGramsCm3: isMmu ? this.parseNumberArray(metadata.filament_density) : this.parseFirstValue(metadata.filament_density),
                filamentUsedMm: isMmu ? this.parseNumberArray(metadata.filament_used_mm) : this.parseFirstValue(metadata.filament_used_mm),
                filamentUsedCm3: isMmu ? this.parseNumberArray(metadata.filament_used_cm3) : this.parseFirstValue(metadata.filament_used_cm3),
                filamentUsedGrams: isMmu ? this.parseNumberArray(metadata.filament_used_g) : this.parseFirstValue(metadata.filament_used_g),
                totalFilamentUsedGrams: isMmu ? this.sumNumberArray(this.parseNumberArray(metadata.filament_used_g)) : this.parseFirstValue(metadata.filament_used_g),
                layerHeight: this.parseFloat(metadata.layer_height),
                firstLayerHeight: this.parseFloat(metadata.first_layer_height || metadata.initial_layer_height),
                bedTemperature: isMmu ? this.parseNumberArray(metadata.bed_temperature) : this.parseFirstValue(metadata.bed_temperature),
                nozzleTemperature: isMmu ? this.parseNumberArray(metadata.temperature) : this.parseFirstValue(metadata.temperature),
                fillDensity: metadata.fill_density || null,
                filamentType: isMmu ? this.parseStringArray(metadata.filament_type, ';') : this.parseFirstCsvValue(metadata.filament_type),
                printerModel: metadata.printer_model || null,
                slicerVersion: metadata.producer || null,
                maxLayerZ: this.parseFloat(metadata.max_layer_z),
                totalLayers: this.parseInt(metadata.total_layers || metadata.layer_count),
                thumbnails: thumbnails.length > 0 ? thumbnails.map((t)=>({
                        width: t.width,
                        height: t.height,
                        format: t.format,
                        dataLength: t.data?.length || 0
                    })) : undefined,
                blocks: blockHeaders.map((b)=>({
                        type: _bgcodetypes.BgCodeBlockTypeName[b.type] || `Unknown(${b.type})`,
                        compressedSize: b.compressedSize,
                        uncompressedSize: b.uncompressedSize,
                        compression: _bgcodetypes.BgCodeCompressionName[b.compression] || `Unknown(${b.compression})`
                    }))
            };
            return {
                raw: {
                    _thumbnails: thumbnails,
                    blocks: blockHeaders.map((b)=>({
                            type: _bgcodetypes.BgCodeBlockTypeName[b.type] || `Unknown(${b.type})`,
                            compressedSize: b.compressedSize,
                            uncompressedSize: b.uncompressedSize,
                            compression: _bgcodetypes.BgCodeCompressionName[b.compression] || `Unknown(${b.compression})`
                        }))
                },
                normalized
            };
        } finally{
            await fileHandle.close();
        }
    }
    async extractThumbnailsFromBlocks(fileHandle, blockHeaders) {
        const thumbnails = [];
        const thumbnailBlocks = blockHeaders.filter((b)=>b.type === _bgcodetypes.BgCodeBlockTypes.Thumbnail);
        for (const header of thumbnailBlocks){
            const parameters = header.parameters;
            const blockData = await (0, _bgcodeutils.getBlockData)(fileHandle, header);
            const imageData = (0, _bgcodeutils.decompressBlock)(header.compression, blockData);
            const processed = (0, _bgcodethumbnailparser.processThumbnail)(imageData, parameters);
            thumbnails.push({
                width: parameters.width,
                height: parameters.height,
                format: processed.extension,
                data: processed.data.toString('base64')
            });
        }
        return thumbnails;
    }
    parseNumber(value, parser) {
        if (!value) return null;
        const num = parser(value);
        return Number.isNaN(num) ? null : num;
    }
    parseFloat(value) {
        return this.parseNumber(value, Number.parseFloat);
    }
    parseInt(value) {
        return this.parseNumber(value, (val)=>Number.parseInt(val, 10));
    }
    parseTime(value) {
        if (!value) return null;
        let totalSeconds = 0;
        const hours = new RegExp(/(\d+)h/).exec(value);
        const minutes = new RegExp(/(\d+)m/).exec(value);
        const seconds = new RegExp(/(\d+)s/).exec(value);
        if (hours) totalSeconds += Number.parseInt(hours[1]) * 3600;
        if (minutes) totalSeconds += Number.parseInt(minutes[1]) * 60;
        if (seconds) totalSeconds += Number.parseInt(seconds[1]);
        if (hours || minutes || seconds) return totalSeconds;
        const num = Number.parseFloat(value);
        return Number.isNaN(num) ? null : num;
    }
    parseFirstValue(value) {
        if (!value) return null;
        const firstValue = value.split(',')[0].trim();
        const num = Number.parseFloat(firstValue);
        return Number.isNaN(num) ? null : num;
    }
    parseFirstCsvValue(value) {
        if (!value) return null;
        return value.trim();
    }
    parseNumberArray(value) {
        if (!value) return null;
        const values = value.split(',').map((v)=>Number.parseFloat(v.trim())).filter((n)=>!Number.isNaN(n));
        return values.length > 0 ? values : null;
    }
    parseStringArray(value, separator = ';') {
        if (!value) return null;
        const values = value.split(separator).map((v)=>v.trim()).filter((v)=>v.length > 0);
        return values.length > 0 ? values : null;
    }
    isMmuData(value, separator = ',') {
        if (!value) return false;
        const parts = value.split(separator).map((v)=>v.trim()).filter((v)=>v.length > 0);
        return parts.length > 1;
    }
    sumNumberArray(values) {
        if (!values || values.length === 0) return null;
        return values.reduce((sum, val)=>sum + val, 0);
    }
}

//# sourceMappingURL=bgcode.parser.js.map