"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.
 */
const debug_1 = __importDefault(require("debug"));
const path_1 = require("path");
const fs_extra_1 = require("fs-extra");
const to_import_1 = require("./transfer/to-import");
const to_typescript_1 = require("./transfer/to-typescript");
const ts_simple_ast_1 = __importDefault(require("ts-simple-ast"));
const log = debug_1.default('j2t:core:inteprethandle');
const ast = new ts_simple_ast_1.default();
/**
 * Translations for individual files
 */
class IntepretHandle {
    constructor(classPath, interpreterRequest) {
        this.dependencies = [];
        this.hasAst = classPath => {
            return this.request.hasAst(classPath);
        };
        this.getTypeInfo = classPath => {
            return this.request.getTypeInfo(classPath);
        };
        this.isTypeParam = typeName => {
            for (let typeParamItem of this.astJava.typeParams) {
                if (typeParamItem.name === typeName) {
                    return true;
                }
            }
            return false;
        };
        this.classPath = classPath;
        this.request = interpreterRequest;
        log('Start translating :%s, outputDir:%s', classPath, interpreterRequest.outputDir);
    }
    get to() {
        return path_1.join(this.request.outputDir, this.classPath.split('.').join('/') + '.ts');
    }
    get astJava() {
        return this.request.getAst(this.classPath);
    }
    get providerSuffix() {
        return this.request.providerSuffix;
    }
    async work() {
        await this.prepare();
        await this.doItRecursively();
    }
    /**
     *
     * @returns {Promise<void>}
     */
    async prepare() {
        ast.addSourceFileFromText(this.to, '//generate by interpret-cli dubbo2.js');
        this.sourceFile = ast.getSourceFile(this.to);
        await fs_extra_1.ensureDir(path_1.parse(this.to).dir);
    }
    /**
     * Adding dependencies
     *
     * @param classPath
     * @param className
     * @returns {Promise<void>}
     */
    async addDenpend(classPath) {
        if (!(await this.request.hasAst(classPath))) {
            log(`No class ast found:${classPath}`);
            return;
        }
        if (classPath === this.classPath) {
            log(`ignore self reference:${this.classPath}`);
            let className = this.getTypeInfo(classPath).className;
            return {
                classPath,
                name: className,
                importName: className
            };
        }
        log(`Adding dependencies ${this.classPath}`);
        let dependItem = this.getDependItem(classPath);
        if (!dependItem) {
            if (!this.request.isRecorded(classPath)) {
                this.request.record(classPath);
                try {
                    await new IntepretHandle(classPath, this.request).work();
                }
                catch (err) {
                    console.error('Error in translating file::', classPath, err.stack);
                    throw err;
                }
            }
            dependItem = this.createDependItem(classPath);
            this.dependencies.push(dependItem);
            try {
                this.sourceFile.addImport(to_import_1.toImport({
                    className: dependItem.name != dependItem.importName ? `${dependItem.name} as ${dependItem.importName}` : dependItem.name,
                    classPath,
                    packagePath: this.getTypeInfo(this.classPath).packagePath,
                }));
            }
            catch (err) {
                console.error(`Error in adding dependencies :add ${classPath} in ${this.classPath}`);
                console.error(err);
            }
            return dependItem;
        }
        else {
            return dependItem;
        }
    }
    getDependItem(classPath) {
        for (let dependItem of this.dependencies) {
            if (dependItem.classPath === classPath) {
                return dependItem;
            }
        }
        return null;
    }
    createDependItem(classPath) {
        let name = this.getTypeInfo(classPath).className;
        let importName = name;
        let index = 0;
        while (this.isDependNameExist(importName)) {
            importName += index;
        }
        return {
            classPath,
            name,
            importName: importName
        };
    }
    isDependNameExist(importName) {
        let isExist = false;
        for (let dependItem of this.dependencies) {
            if (dependItem.importName === importName) {
                isExist = true;
            }
        }
        return isExist;
    }
    /**
     *
     * @returns {Promise<void>}
     */
    async doItRecursively() {
        await to_typescript_1.toTypescript(this);
        await ast.saveUnsavedSourceFiles();
    }
}
exports.IntepretHandle = IntepretHandle;
