import * as metaData from '../metaData';
const groupBy = (array, key) => {
    return array.reduce((rv, x) => {
        (rv[x[key]] = rv[x[key]] || []).push(x);
        return rv;
    }, {});
};
function getIPPGroups(imageIds) {
    const ippMetadata = imageIds.map((imageId) => {
        const { imagePositionPatient } = metaData.get('imagePlaneModule', imageId) || {};
        return { imageId, imagePositionPatient };
    });
    if (!ippMetadata.every((item) => item.imagePositionPatient)) {
        return null;
    }
    const positionGroups = groupBy(ippMetadata, 'imagePositionPatient');
    const positions = Object.keys(positionGroups);
    const frame_count = positionGroups[positions[0]].length;
    if (frame_count === 1) {
        return null;
    }
    const frame_count_equal = positions.every((k) => positionGroups[k].length === frame_count);
    if (!frame_count_equal) {
        return null;
    }
    return positionGroups;
}
function test4DTag(IPPGroups, value_getter) {
    const frame_groups = {};
    let first_frame_value_set = [];
    const positions = Object.keys(IPPGroups);
    for (let i = 0; i < positions.length; i++) {
        const frame_value_set = new Set();
        const frames = IPPGroups[positions[i]];
        for (let j = 0; j < frames.length; j++) {
            const frame_value = value_getter(frames[j].imageId) || 0;
            frame_groups[frame_value] = frame_groups[frame_value] || [];
            frame_groups[frame_value].push({ imageId: frames[j].imageId });
            frame_value_set.add(frame_value);
            if (frame_value_set.size - 1 < j) {
                return undefined;
            }
        }
        if (i == 0) {
            first_frame_value_set = Array.from(frame_value_set);
        }
        else if (!setEquals(first_frame_value_set, frame_value_set)) {
            return undefined;
        }
    }
    return frame_groups;
}
function getTagValue(imageId, tag) {
    const value = metaData.get(tag, imageId);
    try {
        return parseFloat(value);
    }
    catch {
        return undefined;
    }
}
function getPhilipsPrivateBValue(imageId) {
    const value = metaData.get('20011003', imageId);
    try {
        const { InlineBinary } = value;
        if (InlineBinary) {
            const value_bytes = atob(InlineBinary);
            const ary_buf = new ArrayBuffer(value_bytes.length);
            const dv = new DataView(ary_buf);
            for (let i = 0; i < value_bytes.length; i++) {
                dv.setUint8(i, value_bytes.charCodeAt(i));
            }
            return new Float32Array(ary_buf)[0];
        }
        return parseFloat(value);
    }
    catch {
        return undefined;
    }
}
function getSiemensPrivateBValue(imageId) {
    let value = metaData.get('0019100c', imageId) || metaData.get('0019100C', imageId);
    try {
        const { InlineBinary } = value;
        if (InlineBinary) {
            value = atob(InlineBinary);
        }
        return parseFloat(value);
    }
    catch {
        return undefined;
    }
}
function getGEPrivateBValue(imageId) {
    let value = metaData.get('00431039', imageId);
    try {
        const { InlineBinary } = value;
        if (InlineBinary) {
            value = atob(InlineBinary).split('//');
        }
        return parseFloat(value[0]) % 100000;
    }
    catch {
        return undefined;
    }
}
function setEquals(set_a, set_b) {
    if (set_a.length != set_b.size) {
        return false;
    }
    for (let i = 0; i < set_a.length; i++) {
        if (!set_b.has(set_a[i])) {
            return false;
        }
    }
    return true;
}
function getPetFrameReferenceTime(imageId) {
    const moduleInfo = metaData.get('petImageModule', imageId);
    return moduleInfo ? moduleInfo['frameReferenceTime'] : 0;
}
function splitImageIdsBy4DTags(imageIds) {
    const positionGroups = getIPPGroups(imageIds);
    if (!positionGroups) {
        return { imageIdGroups: [imageIds], splittingTag: null };
    }
    const tags = [
        'TemporalPositionIdentifier',
        'DiffusionBValue',
        'TriggerTime',
        'EchoTime',
        'EchoNumber',
        'PhilipsPrivateBValue',
        'SiemensPrivateBValue',
        'GEPrivateBValue',
        'PetFrameReferenceTime',
    ];
    const fncList2 = [
        (imageId) => getTagValue(imageId, tags[0]),
        (imageId) => getTagValue(imageId, tags[1]),
        (imageId) => getTagValue(imageId, tags[2]),
        (imageId) => getTagValue(imageId, tags[3]),
        (imageId) => getTagValue(imageId, tags[4]),
        getPhilipsPrivateBValue,
        getSiemensPrivateBValue,
        getGEPrivateBValue,
        getPetFrameReferenceTime,
    ];
    for (let i = 0; i < fncList2.length; i++) {
        const frame_groups = test4DTag(positionGroups, fncList2[i]);
        if (frame_groups) {
            const sortedKeys = Object.keys(frame_groups)
                .map(Number.parseFloat)
                .sort((a, b) => a - b);
            const imageIdGroups = sortedKeys.map((key) => frame_groups[key].map((item) => item.imageId));
            return { imageIdGroups, splittingTag: tags[i] };
        }
    }
    return { imageIdGroups: [imageIds], splittingTag: null };
}
export default splitImageIdsBy4DTags;
