import { distanceBetweenTwoPoints2D } from '../utils/distanceBetweenTwoPoints2D';
import { addTo } from '../addTo';
import { getGroup } from '../getGroup';
import { getPrefab } from '../getPrefab';
import { pop3 } from '../utils/pop3';
import { rsd } from '../utils/randomSeed';
import { Packer } from './Packer';
import Space from './Space';
import { progressBetween } from '../utils/progressBetween';
/**
 * The getScape function is a helper that is used to distribute objects in a specific area.
 * It takes an optional IScapeOptions object as a parameter that specifies various settings for the scape such as
 * spaceSize, spaceSizeDiff, gapFreq, gapSize, gapSizeDiff, boundaryMin, boundaryMax, areaSize, size, itemScale,
 * itemScaleDiff, prefabId, material, tiltiness, randomRotation, seed, and onEach.
 * The function returns a wrapper containing the objects distributed according to the specified settings.
 * The function uses a Packer class to distribute the objects and applies rotation, scale, and material properties to them.
 * More info in [README](README.md)
 * @example
 * ```
  addTo(root, getScape({ ...SCAPE_PRESETS.mediumDist, ...{ prefabId: 'rock_01_t4' } }));
 * ```
 */
export const getScape = (opt) => {
    const val = {
        spaceSize: 10,
        spaceSizeDiff: 10,
        gapFreq: 0.2,
        gapSize: 1.5,
        gapSizeDiff: 2.5,
        boundaryMin: 0.1,
        boundaryMax: 1,
        areaSize: 200,
        size: 150,
        itemScale: pop3(1),
        itemScaleDiff: pop3(1),
        prefabId: ['rock_01_t1'],
        material: undefined,
        tiltiness: 0.01,
        randomRotation: true,
        onEach: undefined,
        p: [0, 0, 0],
        r: [0, 0, 0],
        s: [1, 1, 1],
        ...opt,
    };
    if (!Array.isArray(val.prefabId))
        val.prefabId = [val.prefabId];
    if (val.material && !Array.isArray(val.material))
        val.material = [val.material];
    const addSpace = (data = { width: 10, depth: 10 }, layer) => {
        const space = new Space(data, layer);
        const isAdded = layer.packer.pack(space.rect);
        if (isAdded) {
            return { space, added: true };
        }
        else {
            return { space, added: false };
        }
    };
    let getRandomData = (layerInfo) => {
        let isGap = rsd(val.seed).getValue() > layerInfo.props.gapFreq ? false : true;
        let boundaryMin = layerInfo.props.boundaryMin;
        let boundaryMax = layerInfo.props.boundaryMax;
        let itemSize;
        if (isGap) {
            itemSize = rsd(val.seed).range(layerInfo.props.gapSize, layerInfo.props.gapSize + layerInfo.props.gapSizeDiff);
        }
        else {
            itemSize = rsd(val.seed).range(layerInfo.props.spaceSize, layerInfo.props.spaceSize + layerInfo.props.spaceSizeDiff);
        }
        return { isGap, boundaryMin, boundaryMax, width: itemSize, depth: itemSize };
    };
    val.size = val.areaSize;
    const wrapper = getGroup(val);
    const packer = new Packer(val.size, val.size);
    let layer = { props: val, packer, filled: false };
    let spaceInfo = { added: true, space: null };
    const fn = (space) => {
        const p = [space.x(), 0, space.z()];
        // Tiltiness
        const tiltK = 80;
        const tiltValX = rsd(val.seed).range(val.tiltiness * tiltK, val.tiltiness * -tiltK);
        const tiltValZ = rsd(val.seed).range(val.tiltiness * tiltK, val.tiltiness * -tiltK);
        const r = [tiltValX, val.randomRotation ? rsd(val.seed).range(0, 360) : 0, tiltValZ];
        const prefabAr = (val.prefabId.length ? val.prefabId : [val.prefabId]);
        const materialAr = (val.material && (val.material?.length ? val.material : [val.material]));
        const itemScaleDiffRandomVal = rsd(val.seed).getValue();
        const scaleVal = [
            progressBetween(val.itemScale[0], val.itemScaleDiff[0], itemScaleDiffRandomVal),
            progressBetween(val.itemScale[1], val.itemScaleDiff[1], itemScaleDiffRandomVal),
            progressBetween(val.itemScale[2], val.itemScaleDiff[2], itemScaleDiffRandomVal),
        ];
        const props = {
            id: rsd(val.seed).randomFromArray(prefabAr),
            p,
            r,
            s: scaleVal,
        };
        if (val.material) {
            props.material = rsd(val.seed).randomFromArray(materialAr);
        }
        if (val.onEach) {
            const onEachRes = val.onEach(props);
            if (onEachRes) {
                addTo(wrapper, onEachRes);
            }
        }
        else {
            addTo(wrapper, getPrefab(props));
        }
    };
    while (spaceInfo.added) {
        let randomData = getRandomData(layer);
        spaceInfo = addSpace(randomData, layer);
        if (spaceInfo.space) {
            let distanceToCenter = distanceBetweenTwoPoints2D(spaceInfo.space.x(), spaceInfo.space.z());
            distanceToCenter = (distanceToCenter * 2) / layer.props.size;
            spaceInfo.space.distanceToCenter = distanceToCenter;
            if (distanceToCenter < randomData.boundaryMax && distanceToCenter >= randomData.boundaryMin) {
                if (spaceInfo.added && !randomData.isGap) {
                    fn(spaceInfo.space);
                }
            }
        }
    }
    return wrapper;
};
//# sourceMappingURL=getScape.js.map