/**
 * Copyright (c) 2020-present, Goldman Sachs
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import packageJson from '../../../../../package.json' with { type: 'json' };
import { assertType, guaranteeNonEmptyString, assertNonNullable, guaranteeNonNullable, } from '@finos/legend-shared';
import { deserialize, serialize } from 'serializr';
import { getOwnBinding, getOwnSchemaSet, } from '../../../helpers/DSL_ExternalFormat_GraphManagerHelper.js';
import { PackageableElementReference } from '../../../../graph/metamodel/pure/packageableElements/PackageableElementReference.js';
import { ExternalFormatConnection } from '../../../../graph/metamodel/pure/packageableElements/externalFormat/connection/DSL_ExternalFormat_ExternalFormatConnection.js';
import { UrlStream } from '../../../../graph/metamodel/pure/packageableElements/externalFormat/connection/DSL_ExternalFormat_UrlStream.js';
import { Schema } from '../../../../graph/metamodel/pure/packageableElements/externalFormat/schemaSet/DSL_ExternalFormat_Schema.js';
import { SchemaSet } from '../../../../graph/metamodel/pure/packageableElements/externalFormat/schemaSet/DSL_ExternalFormat_SchemaSet.js';
import { Binding } from '../../../../graph/metamodel/pure/packageableElements/externalFormat/store/DSL_ExternalFormat_Binding.js';
import { ModelUnit } from '../../../../graph/metamodel/pure/packageableElements/externalFormat/store/DSL_ExternalFormat_ModelUnit.js';
import { PureProtocolProcessorPlugin, } from '../PureProtocolProcessorPlugin.js';
import { V1_ExternalFormatConnection } from '../v1/model/packageableElements/externalFormat/connection/V1_DSL_ExternalFormat_ExternalFormatConnection.js';
import { V1_UrlStream } from '../v1/model/packageableElements/externalFormat/connection/V1_DSL_ExternalFormat_UrlStream.js';
import { V1_Schema } from '../v1/model/packageableElements/externalFormat/schemaSet/V1_DSL_ExternalFormat_Schema.js';
import { V1_SchemaSet } from '../v1/model/packageableElements/externalFormat/schemaSet/V1_DSL_ExternalFormat_SchemaSet.js';
import { V1_Binding } from '../v1/model/packageableElements/externalFormat/store/V1_DSL_ExternalFormat_Binding.js';
import { V1_ModelUnit } from '../v1/model/packageableElements/externalFormat/store/V1_DSL_ExternalFormat_ModelUnit.js';
import { V1_initPackageableElement } from '../v1/transformation/pureGraph/from/V1_CoreTransformerHelper.js';
import { V1_resolveBinding, V1_resolveSchemaSet, } from '../v1/transformation/pureGraph/to/V1_DSL_ExternalFormat_GraphBuilderHelper.js';
import { V1_ElementBuilder } from '../v1/transformation/pureGraph/to/V1_ElementBuilder.js';
import { V1_buildFullPath, } from '../v1/transformation/pureGraph/to/V1_GraphBuilderContext.js';
import { V1_bindingModelSchema, V1_BINDING_ELEMENT_PROTOCOL_TYPE, V1_externalFormatConnectionModelSchema, V1_EXTERNAL_FORMAT_CONNECTION_ELEMENT_PROTOCOL_TYPE, V1_schemaSetModelSchema, V1_SCHEMA_SET_ELEMENT_PROTOCOL_TYPE, } from '../v1/transformation/pureProtocol/serializationHelpers/V1_DSL_ExternalFormat_ProtocolHelper.js';
const BINDING_ELEMENT_CLASSIFIER_PATH = 'meta::external::format::shared::binding::Binding';
const SCHEMA_SET_ELEMENT_CLASSIFIER_PATH = 'meta::external::format::shared::metamodel::SchemaSet';
export class DSL_ExternalFormat_PureProtocolProcessorPlugin extends PureProtocolProcessorPlugin {
    constructor() {
        super(packageJson.extensions.dsl_external_format_pureProtocolProcessorPlugin, packageJson.version);
    }
    V1_getExtraElementBuilders() {
        return [
            new V1_ElementBuilder({
                elementClassName: Binding.name,
                _class: V1_Binding,
                firstPass: (elementProtocol, context) => {
                    assertType(elementProtocol, V1_Binding);
                    const element = new Binding(elementProtocol.name);
                    const path = V1_buildFullPath(elementProtocol.package, elementProtocol.name);
                    context.currentSubGraph.setOwnStore(path, element);
                    return element;
                },
                secondPass: (elementProtocol, context) => {
                    assertType(elementProtocol, V1_Binding);
                    const path = V1_buildFullPath(elementProtocol.package, elementProtocol.name);
                    const element = getOwnBinding(path, context.currentSubGraph);
                    element.schemaId = elementProtocol.schemaId;
                    element.schemaSet = elementProtocol.schemaSet
                        ? V1_resolveSchemaSet(elementProtocol.schemaSet, context)
                        : undefined;
                    element.contentType = guaranteeNonEmptyString(elementProtocol.contentType, `Binding 'contentType' '${elementProtocol.contentType}' is not supported`);
                    assertNonNullable(elementProtocol.modelUnit, `Binding 'modelUnit' field is missing`);
                    const modelUnit = new ModelUnit();
                    modelUnit.packageableElementIncludes =
                        elementProtocol.modelUnit.packageableElementIncludes.map((e) => context.resolveElement(e, true));
                    modelUnit.packageableElementExcludes =
                        elementProtocol.modelUnit.packageableElementExcludes.map((e) => context.resolveElement(e, true));
                    element.modelUnit = modelUnit;
                },
            }),
            new V1_ElementBuilder({
                elementClassName: SchemaSet.name,
                _class: V1_SchemaSet,
                firstPass: (elementProtocol, context) => {
                    assertType(elementProtocol, V1_SchemaSet);
                    const element = new SchemaSet(elementProtocol.name);
                    const path = V1_buildFullPath(elementProtocol.package, elementProtocol.name);
                    context.currentSubGraph.setOwnElementInExtension(path, element, SchemaSet);
                    return element;
                },
                secondPass: (elementProtocol, context) => {
                    assertType(elementProtocol, V1_SchemaSet);
                    const path = V1_buildFullPath(elementProtocol.package, elementProtocol.name);
                    const element = getOwnSchemaSet(path, context.currentSubGraph);
                    element.format = guaranteeNonEmptyString(elementProtocol.format);
                    element.schemas = elementProtocol.schemas.map((schema) => {
                        const schemaElement = new Schema();
                        schemaElement.content = guaranteeNonEmptyString(schema.content, `Schema 'content' field is missing or empty`);
                        schemaElement.id = schema.id;
                        schemaElement.location = schema.location;
                        return schemaElement;
                    });
                },
            }),
        ];
    }
    V1_getExtraElementClassifierPathGetters() {
        return [
            (elementProtocol) => {
                if (elementProtocol instanceof V1_Binding) {
                    return BINDING_ELEMENT_CLASSIFIER_PATH;
                }
                else if (elementProtocol instanceof V1_SchemaSet) {
                    return SCHEMA_SET_ELEMENT_CLASSIFIER_PATH;
                }
                return undefined;
            },
        ];
    }
    V1_getExtraElementProtocolSerializers() {
        return [
            (elementProtocol, plugins) => {
                if (elementProtocol instanceof V1_Binding) {
                    return serialize(V1_bindingModelSchema, elementProtocol);
                }
                else if (elementProtocol instanceof V1_SchemaSet) {
                    return serialize(V1_schemaSetModelSchema, elementProtocol);
                }
                return undefined;
            },
        ];
    }
    V1_getExtraElementProtocolDeserializers() {
        return [
            (json, plugins) => {
                if (json._type === V1_BINDING_ELEMENT_PROTOCOL_TYPE) {
                    return deserialize(V1_bindingModelSchema, json);
                }
                else if (json._type === V1_SCHEMA_SET_ELEMENT_PROTOCOL_TYPE) {
                    return deserialize(V1_schemaSetModelSchema, json);
                }
                return undefined;
            },
        ];
    }
    V1_getExtraElementTransformers() {
        return [
            (metamodel, context) => {
                if (metamodel instanceof Binding) {
                    const protocol = new V1_Binding();
                    V1_initPackageableElement(protocol, metamodel);
                    protocol.name = metamodel.name;
                    protocol.package = metamodel.package?.path ?? '';
                    protocol.schemaId = metamodel.schemaId;
                    protocol.schemaSet = metamodel.schemaSet?.valueForSerialization;
                    protocol.contentType = metamodel.contentType;
                    const modelUnit = new V1_ModelUnit();
                    modelUnit.packageableElementExcludes =
                        metamodel.modelUnit.packageableElementExcludes.map((path) => path instanceof PackageableElementReference
                            ? (path.valueForSerialization ?? '')
                            : path);
                    modelUnit.packageableElementIncludes =
                        metamodel.modelUnit.packageableElementIncludes.map((path) => path instanceof PackageableElementReference
                            ? (path.valueForSerialization ?? '')
                            : path);
                    protocol.modelUnit = modelUnit;
                    protocol.includedStores = [];
                    return protocol;
                }
                else if (metamodel instanceof SchemaSet) {
                    const protocol = new V1_SchemaSet();
                    V1_initPackageableElement(protocol, metamodel);
                    protocol.name = metamodel.name;
                    protocol.package = metamodel.package?.path ?? '';
                    protocol.format = metamodel.format;
                    protocol.schemas = metamodel.schemas.map((schema) => {
                        const schemaProtocol = new V1_Schema();
                        schemaProtocol.content = schema.content;
                        schemaProtocol.id = schema.id;
                        schemaProtocol.location = schema.location;
                        return schemaProtocol;
                    });
                    return protocol;
                }
                return undefined;
            },
        ];
    }
    V1_getExtraConnectionBuilders() {
        return [
            (connection, context, store) => {
                if (connection instanceof V1_ExternalFormatConnection) {
                    const Store = !store
                        ? V1_resolveBinding(guaranteeNonNullable(connection.store, `External format connection 'store' field is missing`), context)
                        : connection.store
                            ? V1_resolveBinding(connection.store, context)
                            : (() => {
                                assertType(store.value, Binding, `External format connection store must be a Binding`);
                                return store;
                            })();
                    const externalFormatConnection = new ExternalFormatConnection(Store);
                    assertNonNullable(connection.externalSource, `External format connection 'externalSource' field is missing`);
                    const urlStream = new UrlStream();
                    urlStream.url = guaranteeNonEmptyString(connection.externalSource.url, `URL stream 'url' field is missing or empty`);
                    externalFormatConnection.externalSource = urlStream;
                    return externalFormatConnection;
                }
                return undefined;
            },
        ];
    }
    V1_getExtraConnectionTransformers() {
        return [
            (metamodel, context) => {
                if (metamodel instanceof ExternalFormatConnection) {
                    const connection = new V1_ExternalFormatConnection();
                    connection.store = metamodel.store.valueForSerialization ?? '';
                    const urlStream = new V1_UrlStream();
                    urlStream.url = metamodel.externalSource.url;
                    connection.externalSource = urlStream;
                    return connection;
                }
                return undefined;
            },
        ];
    }
    V1_getExtraConnectionProtocolSerializers() {
        return [
            (connectionProtocol) => {
                if (connectionProtocol instanceof V1_ExternalFormatConnection) {
                    return serialize(V1_externalFormatConnectionModelSchema, connectionProtocol);
                }
                return undefined;
            },
        ];
    }
    V1_getExtraConnectionProtocolDeserializers() {
        return [
            (json) => {
                if (json._type === V1_EXTERNAL_FORMAT_CONNECTION_ELEMENT_PROTOCOL_TYPE) {
                    return deserialize(V1_externalFormatConnectionModelSchema, json);
                }
                return undefined;
            },
        ];
    }
}
//# sourceMappingURL=DSL_ExternalFormat_PureProtocolProcessorPlugin.js.map