Source: modules/action/Symbology.js

/**
 * @module action/Symbology.js
 * @name SymbologyAction
 * @copyright 2023 3Liz
 * @author DHONT René-Luc
 * @license MPL-2.0
 */

import { HttpError } from '../Errors.js';
import { HttpRequestMethods } from '../Utils.js';
import WMS from './../WMS.js';
import {LayerTreeLayerState, LayerTreeGroupState} from './../state/LayerTree.js'

/**
 * Update the symbology of the tree layers
 * @param {LayerTreeLayerState[]} treeLayers - The tree layer group in which tree layers will be updated
 * @param {string}                [method]   - HTTP Request method, use enum HttpRequestMethods
 * @returns {Promise} Promise object represents the tree layers updated
 */
export async function updateLayerTreeLayersSymbology(treeLayers, method=HttpRequestMethods.GET) {
    if (!Array.isArray(treeLayers)) {
        throw new TypeError('`updateLayerTreeLayersSymbology` method required an array as parameter!');
    }

    const wms = new WMS();

    // If the tree layers is empty
    // nothing to do
    if (treeLayers.length == 0) {
        return treeLayers;
    }

    if (method.toUpperCase() == HttpRequestMethods.GET) {
        for (const treeLayer of treeLayers) {
            const wmsParams = {
                LAYER: treeLayer.wmsName,
                STYLES: treeLayer.wmsSelectedStyleName,
            };

            await wms.getLegendGraphic(wmsParams).then((response) => {
                for (const node of response.nodes) {
                    // If the layer has no symbology, there is no type property
                    if (node.hasOwnProperty('type')) {
                        treeLayer.symbology = node;
                    }
                }
            }).catch((error) => {
                console.error(error);
            });
        }
        return treeLayers;
    }

    const wmsNames = treeLayers.map(layer => layer.wmsName);
    const wmsStyles = treeLayers.map(layer => layer.wmsSelectedStyleName);
    let treeLayersByName = {};
    for (const treeLayer of treeLayers) {
        treeLayersByName[treeLayer.wmsName] = treeLayer;
    }

    const wmsParams = {
        LAYER: wmsNames,
        STYLES: wmsStyles,
    };

    await wms.getLegendGraphic(wmsParams).then((response) => {
        for (const node of response.nodes) {
            // If the layer has no symbology, there is no type property
            if (node.hasOwnProperty('type')) {
                treeLayersByName[node.name].symbology = node;
            }
        }
        return treeLayers;
    }).catch(async (error) => {
        console.error(error);
        // If the request failed, try to get the legend graphic for each layer separately
        // This is a workaround for the issue when QGIS server timed out when requesting
        // the legend graphic for multiple layers at once (LAYER parameter with multiple values)
        if (treeLayers.length == 1) {
            // If there is only one layer, there is no need to try to get the legend graphic
            // for each layer separately
            return treeLayers;
        }
        if (!(error instanceof HttpError) || error.statusCode != 504) {
            // If the error is not a timeout, there is no need to try to get the legend graphic
            // for each layer separately
            return treeLayers;
        }
        // Try to get the legend graphic for each layer separately
        for (const treeLayer of treeLayers) {
            await updateLayerTreeLayerSymbology(treeLayer);
        }
    });
    return treeLayers;
}

/**
 * Update the symbology of the tree layer
 * @param {LayerTreeLayerState} treeLayer - The tree layer to be updated
 * @returns {Promise} Promise object represents the tree layer updated
 */
export async function updateLayerTreeLayerSymbology(treeLayer) {
    if (!(treeLayer instanceof LayerTreeLayerState)) {
        throw new TypeError('`updateLayerTreeLayerSymbology` method required a LayerTreeLayerState as parameter!');
    }
    const treeLayers = await updateLayerTreeLayersSymbology([treeLayer])
    return treeLayers[0];
}

/**
 * Update the symbology of the tree layers in the tree group
 * @param {LayerTreeGroupState} treeGroup - The tree layer group in which tree layers will be updated
 * @param {string}              [method]  - HTTP Request method use enum HttpRequestMethods
 * @returns {Promise} Promise object represents the tree layers updated
 */
export async function updateLayerTreeGroupLayersSymbology(treeGroup, method=HttpRequestMethods.GET) {
    if (!(treeGroup instanceof LayerTreeGroupState)) {
        throw new TypeError(
            '`updateLayerTreeGroupLayersSymbology` method required a LayerTreeGroupState as parameter!'
        );
    }
    return await updateLayerTreeLayersSymbology(treeGroup.findTreeLayers(), method);
}