/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
/** @packageDocumentation
 * @module Views
 */
import { assert, BeEvent, Id64, JsonUtils } from "@itwin/core-bentley";
import { ClipVector, Geometry } from "@itwin/core-geometry";
import { ModelClipGroups } from "./ModelClipGroup";
/** Describes the orientation of the grid displayed within a [Viewport]($frontend).
 * @public
 * @extensions
 */
export var GridOrientationType;
(function (GridOrientationType) {
    /** Oriented with the view. */
    GridOrientationType[GridOrientationType["View"] = 0] = "View";
    /** Top */
    GridOrientationType[GridOrientationType["WorldXY"] = 1] = "WorldXY";
    /** Right */
    GridOrientationType[GridOrientationType["WorldYZ"] = 2] = "WorldYZ";
    /** Front */
    GridOrientationType[GridOrientationType["WorldXZ"] = 3] = "WorldXZ";
    /** Oriented by the auxiliary coordinate system. */
    GridOrientationType[GridOrientationType["AuxCoord"] = 4] = "AuxCoord";
})(GridOrientationType || (GridOrientationType = {}));
/** Encapsulates access to optional view details stored in JSON properties.
 * @see [[ViewDetailsProps]] for the JSON representation.
 * @see [ViewDefinition.details]($backend) and [ViewState.details]($frontend).
 * @public
 */
export class ViewDetails {
    /** @internal */
    _json;
    _clipVector;
    /** Event raised just before assignment to the [[clipVector]] property. */
    onClipVectorChanged = new BeEvent();
    /** @internal */
    constructor(jsonProperties) {
        if (!jsonProperties.viewDetails)
            jsonProperties.viewDetails = {};
        this._json = jsonProperties.viewDetails;
    }
    /** The Id of the auxiliary coordinate system for the view. */
    get auxiliaryCoordinateSystemId() {
        return Id64.fromJSON(this._json.acs);
    }
    set auxiliaryCoordinateSystemId(id) {
        this._json.acs = Id64.isValidId64(id) ? id : undefined;
    }
    /** Maximum aspect ratio skew. Apps can override this by changing its value. */
    static maxSkew = 25;
    /** The aspect ratio skew (x/y, usually 1.0) used to exaggerate the y axis of the view. */
    get aspectRatioSkew() {
        const maxSkew = ViewDetails.maxSkew;
        const skew = JsonUtils.asDouble(this._json.aspectSkew, 1.0);
        return Geometry.clamp(skew, 1 / maxSkew, maxSkew);
    }
    set aspectRatioSkew(skew) {
        this._json.aspectSkew = 1.0 !== skew ? skew : undefined;
    }
    /** The orientation of the view's grid. */
    get gridOrientation() {
        return JsonUtils.asInt(this._json.gridOrient, GridOrientationType.WorldXY);
    }
    set gridOrientation(orientation) {
        this._json.gridOrient = GridOrientationType.WorldXY === orientation ? undefined : orientation;
    }
    /** The number of grids per ref for the view. */
    get gridsPerRef() {
        return JsonUtils.asInt(this._json.gridPerRef, 10);
    }
    set gridsPerRef(gridsPerRef) {
        this._json.gridPerRef = 10 === gridsPerRef ? undefined : gridsPerRef;
    }
    /** The grid spacing for the view. */
    get gridSpacing() {
        const x = JsonUtils.asDouble(this._json.gridSpaceX, 1.0);
        const y = JsonUtils.asDouble(this._json.gridSpaceY, x);
        return { x, y };
    }
    set gridSpacing(spacing) {
        this._json.gridSpaceX = 1.0 !== spacing.x ? spacing.x : undefined;
        this._json.gridSpaceY = spacing.x !== spacing.y ? spacing.y : undefined;
    }
    /** Clipping volume for the view.
     * @note Do *not* modify the returned ClipVector. If you wish to change the ClipVector, clone the returned ClipVector, modify it as desired, and pass the clone back to the setter.
     */
    get clipVector() {
        if (undefined === this._clipVector) {
            const clip = this._json.clip;
            this._clipVector = (undefined !== clip ? ClipVector.fromJSON(clip) : ClipVector.createEmpty());
        }
        return this._clipVector.isValid ? this._clipVector : undefined;
    }
    set clipVector(clip) {
        const curClip = this.clipVector;
        if (curClip === clip)
            return;
        if (!curClip) {
            assert(undefined !== clip);
            // An empty clip is equivalent to no clip.
            if (!clip.isValid)
                return;
        }
        clip = clip ?? ClipVector.createEmpty();
        this.onClipVectorChanged.raiseEvent(clip.isValid ? clip : undefined);
        this._clipVector = clip;
        if (clip.isValid)
            this._json.clip = clip.toJSON();
        else
            delete this._json.clip;
    }
    /** Returns the internal JSON representation. This is *not* a copy.
     * @internal
     */
    getJSON() {
        return this._json;
    }
}
/** Encapsulates access to optional 3d view details stored in JSON properties.
 * @see [[ViewDetails3dProps]] for the JSON representation.
 * @public
 */
export class ViewDetails3d extends ViewDetails {
    _modelClipGroups;
    get _json3d() {
        return this._json;
    }
    /** Event raised when just before assignment to the [[modelClipGroups]] property. */
    onModelClipGroupsChanged = new BeEvent();
    /** @internal */
    constructor(jsonProperties) {
        super(jsonProperties);
    }
    /** Controls whether viewing tools are allowed to operate on the view in 3 dimensions. */
    get allow3dManipulations() {
        return !JsonUtils.asBool(this._json3d.disable3dManipulations, false);
    }
    set allow3dManipulations(allow) {
        this._json3d.disable3dManipulations = allow ? undefined : true;
    }
    /** Groups of models associated with [ClipVector]($core-geometry)s by which those models should be clipped.
     * If the view and the model both have a clip vector defined, geometry in the model will be clipped by the intersection of the two clip vectors.
     * [[ViewFlags.clipVolume]] has no effect on model clips, only the view clip - model clips are always applied.
     * @note Do **not** modify the returned object directly. Instead, clone it, modify the clone, and pass the clone to the property setter.
     */
    get modelClipGroups() {
        if (!this._modelClipGroups)
            this._modelClipGroups = ModelClipGroups.fromJSON(this._json3d.modelClipGroups);
        return this._modelClipGroups;
    }
    set modelClipGroups(groups) {
        this.onModelClipGroupsChanged.raiseEvent(groups);
        this._modelClipGroups = groups;
        this._json3d.modelClipGroups = groups.toJSON();
    }
    /** Returns the internal JSON representation. This is *not* a copy.
     * @internal
     */
    getJSON() {
        return this._json3d;
    }
}
//# sourceMappingURL=ViewDetails.js.map