"use strict";
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.ArrayOf = void 0;
const codemodel_v3_1 = require("@azure-tools/codemodel-v3");
const codegen_1 = require("@azure-tools/codegen");
const codegen_csharp_1 = require("@azure-tools/codegen-csharp");
const codegen_csharp_2 = require("@azure-tools/codegen-csharp");
const codegen_csharp_3 = require("@azure-tools/codegen-csharp");
const codegen_csharp_4 = require("@azure-tools/codegen-csharp");
const codegen_csharp_5 = require("@azure-tools/codegen-csharp");
const codegen_csharp_6 = require("@azure-tools/codegen-csharp");
const codegen_csharp_7 = require("@azure-tools/codegen-csharp");
const clientruntime_1 = require("../clientruntime");
const primitive_1 = require("../schema/primitive");
class ArrayOf {
    get defaultOfType() {
        return (0, codegen_csharp_3.toExpression)('null /* arrayOf */');
    }
    constructor(schema, isRequired, elementType, minItems, maxItems, unique) {
        this.schema = schema;
        this.isRequired = isRequired;
        this.elementType = elementType;
        this.minItems = minItems;
        this.maxItems = maxItems;
        this.unique = unique;
        this.isXmlAttribute = false;
        this.isNullable = true;
    }
    get isWrapped() {
        var _a, _b;
        return ((_a = this.schema.serialization) === null || _a === void 0 ? void 0 : _a.xml) && ((_b = this.schema.serialization) === null || _b === void 0 ? void 0 : _b.xml.wrapped) || false;
    }
    get wrapperName() {
        var _a;
        return ((_a = this.schema.serialization) === null || _a === void 0 ? void 0 : _a.xml) && this.isWrapped ? this.schema.serialization.xml.name : undefined;
    }
    get serializedName() {
        var _a;
        return ((_a = this.schema.serialization) === null || _a === void 0 ? void 0 : _a.xml) ? this.schema.serialization.xml.name : undefined;
    }
    get elementTypeDeclaration() {
        return this.elementType.declaration;
    }
    get declaration() {
        return `System.Collections.Generic.List<${this.elementType.declaration}>`;
    }
    get encode() {
        this.schema.extensions = this.schema.extensions || {};
        return this.schema.extensions['x-ms-skip-url-encoding'] ? '' : 'global::System.Uri.EscapeDataString';
    }
    get convertObjectMethod() {
        try {
            const v = (0, primitive_1.pushTempVar)();
            const i = (0, primitive_1.pushTempVar)();
            // return `${v} => ${v} is string || !(${v} is global::System.Collections.IEnumerable) ? new ${this.declaration} {  ${this.elementType.convertObjectMethod}(${v}) } :  System.Linq.Enumerable.ToArray( System.Linq.Enumerable.Select( System.Linq.Enumerable.OfType<object>((global::System.Collections.IEnumerable)${v}), ${this.elementType.convertObjectMethod}))`
            return `${v} => TypeConverterExtensions.SelectToList<${this.elementTypeDeclaration}>(${v}, ${this.elementType.convertObjectMethod})`;
        }
        finally {
            (0, primitive_1.popTempVar)();
            (0, primitive_1.popTempVar)();
        }
    }
    /** emits an expression to deserialize a property from a member inside a container */
    deserializeFromContainerMember(mediaType, container, serializedName, defaultValue) {
        switch (mediaType) {
            case codemodel_v3_1.KnownMediaType.Json: {
                // json array
                const tmp = `__${(0, codegen_1.camelCase)(['json', ...(0, codegen_1.deconstruct)(serializedName)])}`;
                return (0, codegen_csharp_3.toExpression)(`If( ${(0, codegen_csharp_3.valueOf)(container)}?.PropertyT<${clientruntime_1.ClientRuntime.JsonArray}>("${serializedName}"), out var ${tmp}) ? ${this.deserializeFromNode(mediaType, tmp, (0, codegen_csharp_3.toExpression)('null'))} : ${defaultValue}`);
            }
            case codemodel_v3_1.KnownMediaType.Xml: {
                // XElement/XElement
                const tmp = `__${(0, codegen_1.camelCase)(['xml', ...(0, codegen_1.deconstruct)(serializedName)])}`;
                if (this.isWrapped) {
                    // wrapped xml arrays will have a container around them.
                    return (0, codegen_csharp_3.toExpression)(`${this.deserializeFromNode(mediaType, `${(0, codegen_csharp_3.valueOf)(container)}?.Element("${this.serializedName || serializedName}")`, defaultValue)}`);
                }
                else {
                    // whereas non-wrapped will have all the elements in the container directly.
                    return (0, codegen_csharp_3.toExpression)(`${this.deserializeFromNode(mediaType, `${(0, codegen_csharp_3.valueOf)(container)}`, defaultValue)}`);
                }
            }
        }
        return (0, codegen_csharp_3.toExpression)(`null /* deserializeFromContainerMember doesn't support '${mediaType}' ${__filename}*/`);
    }
    /** emits an expression to deserialze a container as the value itself. */
    deserializeFromNode(mediaType, node, defaultValue) {
        try {
            const tmp = (0, primitive_1.pushTempVar)();
            const each = (0, primitive_1.pushTempVar)();
            switch (mediaType) {
                case codemodel_v3_1.KnownMediaType.Json: {
                    // const deser = `System.Linq.Enumerable.ToArray(System.Linq.Enumerable.Select( ${tmp} , (${each})=>(${this.elementType.declaration}) (${this.elementType.deserializeFromNode(mediaType, each, this.elementType.defaultOfType)}) ) )`;
                    const deser = (0, codegen_csharp_3.toExpression)(`${codegen_csharp_2.System.Linq.Enumerable}.ToList(${(0, codegen_csharp_3.valueOf)(codegen_csharp_2.System.Linq.Enumerable.Select(tmp, `(${each})=>(${this.elementType.declaration}) (${this.elementType.deserializeFromNode(mediaType, each, this.elementType.defaultOfType)}`))})`);
                    return (0, codegen_csharp_3.toExpression)(`If( ${(0, codegen_csharp_3.valueOf)(node)} as ${clientruntime_1.ClientRuntime.JsonArray}, out var ${tmp}) ? ${codegen_csharp_2.System.Func(this).new(`()=> ${(0, codegen_csharp_3.valueOf)(deser)} )`)}() : ${defaultValue}`);
                }
                case codemodel_v3_1.KnownMediaType.Xml: {
                    // XElement should be a container of items, right?
                    // if the reference doesn't define an XML schema then use its default name
                    //const defaultName = this.elementType.schema.details.csharp.name;
                    //const deser = `System.Linq.Enumerable.ToArray(System.Linq.Enumerable.Select( ${tmp}.Elements("${this.elementType.schema.xml ? this.elementType.schema.xml.name || defaultName : defaultName}"), (${each})=> ${this.elementType.deserializeFromNode(mediaType, each, toExpression('null'))} ) )`;
                    //return toExpression(`If( ${valueOf(node)}, out var ${tmp}) ? new System.Func<${this.elementType.declaration}[]>(()=> ${deser} )() : ${defaultValue}`);
                }
            }
        }
        finally {
            (0, primitive_1.popTempVar)();
            (0, primitive_1.popTempVar)();
        }
        return (0, codegen_csharp_3.toExpression)(`null /* deserializeFromNode doesn't support '${mediaType}' ${__filename}*/`);
    }
    /** emits an expression to deserialize content from a string */
    deserializeFromString(mediaType, content, defaultValue) {
        switch (mediaType) {
            case codemodel_v3_1.KnownMediaType.Json: {
                return this.deserializeFromNode(mediaType, clientruntime_1.ClientRuntime.JsonArray.Parse(content), defaultValue);
            }
            case codemodel_v3_1.KnownMediaType.Xml: {
                return this.deserializeFromNode(mediaType, `${codegen_csharp_2.System.Xml.Linq.XElement}.Parse(${content})`, defaultValue);
            }
        }
        return undefined;
    }
    /** emits an expression to deserialize content from a content/response */
    deserializeFromResponse(mediaType, content, defaultValue) {
        switch (mediaType) {
            case codemodel_v3_1.KnownMediaType.Xml:
            case codemodel_v3_1.KnownMediaType.Json: {
                return (0, codegen_csharp_3.toExpression)(`${content}.Content.ReadAsStringAsync().ContinueWith( body => ${this.deserializeFromString(mediaType, 'body.Result', defaultValue)})`);
            }
        }
        return (0, codegen_csharp_3.toExpression)(`null /* deserializeFromResponse doesn't support '${mediaType}' ${__filename}*/`);
    }
    /** emits an expression serialize this to a HttpContent */
    serializeToNode(mediaType, value, serializedName, mode) {
        var _a, _b;
        try {
            const each = (0, primitive_1.pushTempVar)();
            switch (mediaType) {
                case codemodel_v3_1.KnownMediaType.Json: {
                    const serArray = `global::System.Linq.Enumerable.ToList(System.Linq.Enumerable.Select(${value}, (${each}) => ${this.elementType.serializeToNode(mediaType, each, serializedName, mode)}))`;
                    return (0, codegen_csharp_3.toExpression)(`null != ${value} ? new ${clientruntime_1.ClientRuntime.XNodeArray}(${serArray}) : null`);
                }
                case codemodel_v3_1.KnownMediaType.Xml: {
                    if (this.isWrapped) {
                        const name = ((_a = this.elementType.schema.serialization) === null || _a === void 0 ? void 0 : _a.xml) ? ((_b = this.elementType.schema.serialization) === null || _b === void 0 ? void 0 : _b.xml.name) || serializedName : serializedName;
                        return (0, codegen_csharp_3.toExpression)(`null != ${value} ? global::new System.Xml.Linq.XElement("${name}", global::System.Linq.Enumerable.ToList(global::System.Linq.Enumerable.Select(${value}, (${each}) => ${this.elementType.serializeToNode(mediaType, each, name, mode)}))`);
                    }
                    else {
                        throw new Error('Can\'t set an Xml Array to the document without wrapping it.');
                    }
                }
                case codemodel_v3_1.KnownMediaType.Cookie:
                case codemodel_v3_1.KnownMediaType.QueryParameter: {
                    const formatSerializedName = serializedName ? `${serializedName}=` : '';
                    return (0, codegen_csharp_3.toExpression)(`(null != ${value}  && ${value}.Count > 0 ? "${formatSerializedName}" + ${this.encode}(global::System.Linq.Enumerable.Aggregate(${value}, (current, each) => current + "," + ( null == each ? ${codegen_csharp_2.System.String.Empty} : each.ToString()) )) : ${codegen_csharp_2.System.String.Empty})`);
                }
                case codemodel_v3_1.KnownMediaType.Header:
                case codemodel_v3_1.KnownMediaType.Text:
                case codemodel_v3_1.KnownMediaType.UriParameter:
                    return (0, codegen_csharp_3.toExpression)(`(null != ${value} ? ${this.encode}(global::System.Linq.Enumerable.Aggregate(${value}, (current,each)=> current + "," + ${this.elementType.serializeToNode(mediaType, 'each', '', mode)})) : ${codegen_csharp_2.System.String.Empty})`);
            }
        }
        finally {
            (0, primitive_1.popTempVar)();
        }
        return (0, codegen_csharp_3.toExpression)(`null /* serializeToNode doesn't support '${mediaType}' ${__filename}*/`);
    }
    /** emits an expression serialize this to the value required by the container */
    serializeToContent(mediaType, value, mode) {
        var _a, _b, _c;
        try {
            const each = (0, primitive_1.pushTempVar)();
            switch (mediaType) {
                case codemodel_v3_1.KnownMediaType.Json: {
                    return codegen_csharp_2.System.Net.Http.StringContent.new(`${(this.serializeToNode(mediaType, value, '', mode))}`, codegen_csharp_2.System.Text.Encoding.UTF8);
                }
                case codemodel_v3_1.KnownMediaType.Xml: {
                    // if the reference doesn't define an XML schema then use its default name
                    const defaultName = ((_a = this.elementType.schema.language.csharp) === null || _a === void 0 ? void 0 : _a.name) || '';
                    return codegen_csharp_2.System.Net.Http.StringContent.new((0, codegen_csharp_6.Ternery)((0, codegen_csharp_1.IsNotNull)(value), `${this.serializeToNode(mediaType, value, ((_b = this.schema.serialization) === null || _b === void 0 ? void 0 : _b.xml) ? ((_c = this.schema.serialization.xml) === null || _c === void 0 ? void 0 : _c.name) || defaultName : defaultName, mode)}).ToString()`, codegen_csharp_2.System.String.Empty), codegen_csharp_2.System.Text.Encoding.UTF8);
                }
                case codemodel_v3_1.KnownMediaType.Cookie:
                case codemodel_v3_1.KnownMediaType.QueryParameter:
                case codemodel_v3_1.KnownMediaType.Header:
                case codemodel_v3_1.KnownMediaType.Text:
                case codemodel_v3_1.KnownMediaType.UriParameter:
                    return (0, codegen_csharp_3.toExpression)(`(null != ${value} ? ${this.encode}(System.Linq.Enumerable.Aggregate(${value}, (current,each)=> current + "," + ${this.elementType.serializeToNode(mediaType, 'each', '', mode)})) : ${codegen_csharp_2.System.String.Empty})`);
            }
        }
        finally {
            (0, primitive_1.popTempVar)();
        }
        return (0, codegen_csharp_3.toExpression)(`null /* serializeToContent doesn't support '${mediaType}' ${__filename}*/`);
    }
    /** emits the code required to serialize this into a container */
    serializeToContainerMember(mediaType, value, container, serializedName, mode) {
        var _a, _b;
        try {
            const each = (0, primitive_1.pushTempVar)();
            const tmp = (0, primitive_1.pushTempVar)();
            switch (mediaType) {
                case codemodel_v3_1.KnownMediaType.Json: {
                    // eslint-disable-next-line @typescript-eslint/no-this-alias
                    const $this = this;
                    return (0, codegen_csharp_5.If)(`null != ${value}`, function* () {
                        const t = new codegen_csharp_7.LocalVariable(tmp, codegen_csharp_2.dotnet.Var, { initializer: `new ${clientruntime_1.ClientRuntime.XNodeArray}()` });
                        yield t.declarationStatement;
                        yield (0, codegen_csharp_4.ForEach)(each, (0, codegen_csharp_3.toExpression)(value), `AddIf(${$this.elementType.serializeToNode(mediaType, each, '', mode)} ,${tmp}.Add);`);
                        yield `${container}.Add("${serializedName}",${tmp});`;
                    });
                }
                case codemodel_v3_1.KnownMediaType.Xml:
                    if (this.isWrapped) {
                        return `AddIf( ${codegen_csharp_2.System.Xml.Linq.XElement.new('"{this.serializedName || serializedName}"', `${this.serializeToNode(mediaType, value, ((_a = this.elementType.schema.serialization) === null || _a === void 0 ? void 0 : _a.xml) ? ((_b = this.elementType.schema.serialization) === null || _b === void 0 ? void 0 : _b.xml.name) || '!!!' : serializedName, mode)}):null`)}, ${container}.Add); `;
                    }
                    else {
                        return (0, codegen_csharp_5.If)(`null != ${value}`, (0, codegen_csharp_4.ForEach)(each, (0, codegen_csharp_3.toExpression)(value), `AddIf(${this.elementType.serializeToNode(mediaType, each, serializedName, mode)}, ${container}.Add);`));
                    }
            }
        }
        finally {
            (0, primitive_1.popTempVar)();
            (0, primitive_1.popTempVar)();
        }
        return (`/* serializeToContainerMember doesn't support '${mediaType}' ${__filename}*/`);
    }
    validatePresence(eventListener, property) {
        if (this.isRequired) {
            return `await ${eventListener}.AssertNotNull(${(0, codegen_1.nameof)(property.value)}, ${property}); `;
        }
        return '';
    }
    validateValue(eventListener, property) {
        // check if the underlyingType has validation.
        if (!this.elementType.validateValue(eventListener, new codegen_csharp_7.LocalVariable(`${property} [{ __i }]`, codegen_csharp_2.dotnet.Var))) {
            return '';
        }
        return `
      if (${property} != null ) {
        for (int __i = 0; __i < ${property}.Count; __i++) {
          ${this.elementType.validateValue(eventListener, new codegen_csharp_7.LocalVariable(`${property}[__i]`, codegen_csharp_2.dotnet.Var))}
        }
      }
      `.trim();
    }
}
exports.ArrayOf = ArrayOf;
//# sourceMappingURL=array.js.map