// @flow
import type FillStyleLayer from '../../style/style_layer/fill_style_layer.js';
import type FillExtrusionStyleLayer from '../../style/style_layer/fill_extrusion_style_layer.js';
import type LineStyleLayer from '../../style/style_layer/line_style_layer.js';

import type {
    BucketFeature,
    PopulateParameters
} from '../bucket.js';

type PatternStyleLayers =
    Array<LineStyleLayer> |
    Array<FillStyleLayer> |
    Array<FillExtrusionStyleLayer>;

export function hasPattern(type: string, layers: PatternStyleLayers, options: PopulateParameters): boolean {
    const patterns = options.patternDependencies;
    let hasPattern = false;

    for (const layer of layers) {
        const patternProperty = layer.paint.get(`${type}-pattern`);
        if (!patternProperty.isConstant()) {
            hasPattern = true;
        }

        const constantPattern = patternProperty.constantOr(null);
        if (constantPattern) {
            hasPattern = true;
            patterns[constantPattern.to] =  true;
            patterns[constantPattern.from] =  true;
        }
    }

    return hasPattern;
}

export function hasMap(type: string, layers: PatternStyleLayers, options: PopulateParameters): boolean {
    const maps = options.mapDependencies;
    let hasMap = false;

    for (const layer of layers) {
        const mapProperty = layer.paint.get(`${type}-map`);
        if (!mapProperty.isConstant()) {
            hasMap = true;
        }

        const constantMap = mapProperty.constantOr(null);
        
        if (constantMap) {
            hasMap = true;
            constantMap.to.forEach(to => maps[to] =  true)
            constantMap.from.forEach(from => maps[from] =  true)
        }
    }
    return hasMap;
}

export function addPatternDependencies(type: string, layers: PatternStyleLayers, patternFeature: BucketFeature, zoom: number, options: PopulateParameters): BucketFeature {
    const patterns = options.patternDependencies;
    for (const layer of layers) {
        const patternProperty = layer.paint.get(`${type}-pattern`);

        const patternPropertyValue = patternProperty.value;
        if (patternPropertyValue.kind !== "constant") {
            let min = patternPropertyValue.evaluate({zoom: zoom - 1}, patternFeature, {}, options.availableImages);
            let mid = patternPropertyValue.evaluate({zoom}, patternFeature, {}, options.availableImages);
            let max = patternPropertyValue.evaluate({zoom: zoom + 1}, patternFeature, {}, options.availableImages);
            min = min && min.name ? min.name : min;
            mid = mid && mid.name ? mid.name : mid;
            max = max && max.name ? max.name : max;
            // add to patternDependencies
            patterns[min] = true;
            patterns[mid] = true;
            patterns[max] = true;

            // save for layout
            patternFeature.patterns[layer.id] = {min, mid, max};
        }
    }
    return patternFeature;
}

export function addMapDependencies(type: string, layers: PatternStyleLayers, patternFeature: BucketFeature, zoom: number, options: PopulateParameters): BucketFeature {
    const patterns = options.patternDependencies;
    
    for (const layer of layers) {
        const patternProperty = layer.paint.get(`${type}-map`);

        const patternPropertyValue = patternProperty.value;
        if (patternPropertyValue.kind !== "constant") {
            let min = patternPropertyValue.evaluate({zoom: zoom - 1}, patternFeature, {}, options.availableImages);
            let mid = patternPropertyValue.evaluate({zoom}, patternFeature, {}, options.availableImages);
            let max = patternPropertyValue.evaluate({zoom: zoom + 1}, patternFeature, {}, options.availableImages);
            min = min && min.name ? min.name : min;
            mid = mid && mid.name ? mid.name : mid;
            max = max && max.name ? max.name : max;
            // add to patternDependencies
            patterns[min] = true;
            patterns[mid] = true;
            patterns[max] = true;

            // save for layout
            patternFeature.maps[layer.id] = {min, mid, max};
        }
    }
    return patternFeature;
}
