"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.SchemaDefinitionResolver = void 0;
const codemodel_1 = require("@autorest/codemodel");
const codemodel_v3_1 = require("@azure-tools/codemodel-v3");
const message = require("../messages");
const array_1 = require("./array");
const binary_1 = require("./binary");
const boolean_1 = require("./boolean");
const byte_array_1 = require("./byte-array");
const fixed_array_1 = require("./fixed-array");
const date_1 = require("./date");
const date_time_1 = require("./date-time");
const duration_1 = require("./duration");
const integer_1 = require("./integer");
const object_1 = require("./object");
const string_1 = require("./string");
const uri_1 = require("./uri");
const Uuid_1 = require("./Uuid");
const password_1 = require("./password");
class SchemaDefinitionResolver {
    add(schema, value) {
        var _a, _b;
        this.cache.set(((_b = (_a = schema.language) === null || _a === void 0 ? void 0 : _a.csharp) === null || _b === void 0 ? void 0 : _b.fullname) || '', value);
        return value;
    }
    constructor(fixedArrayConfig) {
        this.cache = new Map();
        this.fixedArrayConfig = fixedArrayConfig;
    }
    // isFixedArray is used to determine if we want to use a fixed array or not
    resolveTypeDeclaration(schema, required, state, isFixedArray) {
        var _a;
        if (!schema) {
            throw new Error('SCHEMA MISSING?');
        }
        // determine if we need a new model class for the type or just a known type object
        switch (schema.type) {
            case codemodel_1.SchemaType.Array: {
                // can be recursive!
                // handle boolean arrays as booleans (powershell will try to turn it into switches!)
                const ar = schema;
                const elementType = (ar.elementType.type === codemodel_1.SchemaType.Boolean) ? new boolean_1.Boolean(schema, true) : this.resolveTypeDeclaration(ar.elementType, true, state.path('items'), this.fixedArrayConfig);
                if (isFixedArray) {
                    return new fixed_array_1.FixedArrayOf(schema, required, elementType, ar.minItems, ar.maxItems, ar.uniqueItems);
                }
                else {
                    return new array_1.ArrayOf(schema, required, elementType, ar.minItems, ar.maxItems, ar.uniqueItems);
                }
            }
            case codemodel_1.SchemaType.Any:
            case codemodel_1.SchemaType.Dictionary:
            case codemodel_1.SchemaType.Object: {
                const result = schema.language.csharp && this.cache.get(schema.language.csharp.fullname || '');
                if (result) {
                    return result;
                }
                return this.add(schema, new object_1.ObjectImplementation(schema));
            }
            case codemodel_1.SchemaType.Time:
            case codemodel_1.SchemaType.ArmId:
            case codemodel_1.SchemaType.String: {
                return new string_1.String(schema, required);
            }
            case codemodel_1.SchemaType.Credential: {
                return new password_1.Password(schema, required);
            }
            case codemodel_1.SchemaType.Binary:
                return new binary_1.Binary(schema, required);
            case codemodel_1.SchemaType.Duration:
                return new duration_1.Duration(schema, required);
            case codemodel_1.SchemaType.Uri:
                return new uri_1.Uri(schema, required);
            case codemodel_1.SchemaType.Uuid:
                return new Uuid_1.Uuid(schema, required);
            case codemodel_1.SchemaType.DateTime:
                if (schema.format === codemodel_v3_1.StringFormat.DateTimeRfc1123) {
                    return new date_time_1.DateTime1123(schema, required);
                }
                return new date_time_1.DateTime(schema, required);
            case codemodel_1.SchemaType.Date:
                return new date_1.Date(schema, required);
            case codemodel_1.SchemaType.ByteArray:
                return new byte_array_1.ByteArray(schema, required);
            case codemodel_1.SchemaType.Boolean:
                return new boolean_1.Boolean(schema, required);
            case codemodel_1.SchemaType.Integer:
                switch (schema.precision) {
                    case 64:
                        return new integer_1.Numeric(schema, required, required ? 'long' : 'long?');
                    // skip-for-time-being
                    // case IntegerFormat.UnixTime:
                    //   return new UnixTime(schema, required);
                    case 16:
                    case 32:
                        return new integer_1.Numeric(schema, required, required ? 'int' : 'int?');
                }
                // fallback to int if the format isn't recognized
                return new integer_1.Numeric(schema, required, required ? 'int' : 'int?');
            case codemodel_1.SchemaType.UnixTime:
                return new date_time_1.UnixTime(schema, required);
            case codemodel_1.SchemaType.Number:
                switch (schema.precision) {
                    case 64:
                        return new integer_1.Numeric(schema, required, required ? 'double' : 'double?');
                    case 32:
                        return new integer_1.Numeric(schema, required, required ? 'float' : 'float?');
                    case 128:
                        return new integer_1.Numeric(schema, required, required ? 'decimal' : 'decimal?');
                }
                // fallback to float if the format isn't recognized
                return new integer_1.Numeric(schema, required, required ? 'float' : 'float?');
            case codemodel_1.SchemaType.Constant:
                return this.resolveTypeDeclaration(schema.valueType, required, state);
            case codemodel_1.SchemaType.Choice:
            case codemodel_1.SchemaType.SealedChoice: {
                return this.resolveTypeDeclaration(schema.choiceType, required, state);
            }
            case undefined:
                if (schema.extensions && schema.extensions['x-ms-enum']) {
                    return this.resolveTypeDeclaration(schema.choiceType, required, state);
                }
                // "any" case
                // this can happen when a model is just an all-of something else. (sub in the other type?)
                break;
        }
        state.error(`Schema '${(_a = schema.language.csharp) === null || _a === void 0 ? void 0 : _a.name}' is declared with invalid type '${schema.type}'`, message.UnknownJsonType);
        throw new Error('Unknown Model. Fatal.');
    }
}
exports.SchemaDefinitionResolver = SchemaDefinitionResolver;
//# sourceMappingURL=schema-resolver.js.map