import { BimIfcObject } from './loader/bim-ifc-object';
import { BimChangeIfc } from './loader/bim-api-client';
import { Matrix } from './loader/babylonjs-maths-import';

/** Load options of {@link BimIfcObject} instances */
export interface BimApiIfcObjectsLoadOptions {
    /** All {@link BimIfcObject} matching this criteria will be marked with {@link BimIfcObject.hasGeometry} = `false` so
     * that they can not be visualized (no geometry data will be loaded) */
    readonly ifcObjectHasGeometryPredicate?: (o: BimIfcObject) => boolean;

    /**
     * Determines whether leaf nodes in the IFC hierarchy, with no geometry, should be removed during loading.
     * Defaults to `false`.
     */
    removeLeafIfcObjectsWithNoGeometry?: boolean;

    /** Determines if object is initially visible or not. Only valid if {@link ifcObjectHasGeometryPredicate} is not defined or returns `true` for the object.*/
    readonly isIfcObjectVisiblePredicate?: (o: BimIfcObject) => boolean;
}

export interface BimApiSetContainerLoadOptions {
    /** If `true` then property sets are loaded automatically. No call to {@link BimCoreApi.loadPropertySets()} is needed. */
    loadPropertySets: boolean;

    /** If `true` then geometry is loaded automatically.*/
    loadGeometry: boolean;
}

/** Load options to use for loading a specific set of files. Files do not have to be located in the same container */
export interface BimApiLoadOptionsWithExplicitIfcChanges
    extends BimApiIfcObjectsLoadOptions,
        BimApiSetContainerLoadOptions {
    /** If specified, then only changes in the array that are marked for loading will be loaded.
     * If a transform is given it will be applied to all meshes in the IFC change.
     * The transformation will be applied in babylon space.
     */
    readonly ifcChanges: { change: BimChangeIfc; load: boolean; transform?: Matrix }[];
}

/** Load options to use when IFC files in a container needs to match a specified predicate in
 * order to be loaded. Useful when you for example only want to load files with of type disicpline A. */
export interface BimApiLoadOptionsWithIfcChangePredicate
    extends BimApiIfcObjectsLoadOptions,
        BimApiSetContainerLoadOptions {
    /** If specified only {@link BimChangeIfc} instances matching this criteria will be loaded. */
    readonly ifcChangePredicate: (o: BimChangeIfc) => boolean;

    /** Throw exception when {@link  ifcChangePredicate} is applied
     * to a list of {@link BimChangeIfc} and the result is a empty collection. */
    throwOnNoIfcChanges: boolean;

    /**
     * Converts a {@link BimApiLoadOptionsWithIfcChangePredicate} instance to a
     * {@link BimApiLoadOptionsWithExplicitIfcChanges}. This allows a user to
     * specify exactly which ifc files that shall be loaded (for example external files can be
     * added to {@link BimApiLoadOptionsWithExplicitIfcChanges.ifcChanges}).
     * Do note that if ifc files previusly marked as not loadable and any new ifc's that are added
     * will still be subject to the filters ({@link ifcObjectHasGeometryPredicate} and {@link isIfcObjectVisiblePredicate}).
     * Hence if those filters are specified and don't match anything in the files that are marked for load
     * then objects from those files will still not be visible (and may not even get geometry).
     * @param ifcChanges Collection of ifc files that will be initially included in {@link BimApiLoadOptionsWithExplicitIfcChanges.ifcChanges}. Only
     * items matching {@link ifcChangePredicate} will initially be marked for loading.
     */
    toExplicitLoadOptions(ifcChanges: BimChangeIfc[]): BimApiLoadOptionsWithExplicitIfcChanges;
}

/** Options which can be used when loading IFC's. For example when calling {@link BimCoreApi.setContainer}.  */
export type BimApiLoadOptions =
    | BimApiLoadOptionsWithExplicitIfcChanges
    | BimApiLoadOptionsWithIfcChangePredicate
    | 'skip-ifc-load';
