"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const traverse_1 = require("@glas/traverse");
const ast_1 = require("../ast");
const ImportDeclaration_1 = __importDefault(require("../ast/ImportDeclaration"));
const ImportNamespaceSpecifier_1 = __importDefault(require("../ast/ImportNamespaceSpecifier"));
const ImportDefaultSpecifier_1 = __importDefault(require("../ast/ImportDefaultSpecifier"));
const ImportSpecifier_1 = __importDefault(require("../ast/ImportSpecifier"));
const common_1 = require("../common");
function fixImports(root, options) {
    return traverse_1.traverse(root, {
        enter(node) {
            if (ast_1.Program.is(node)) {
                return traverse_1.skip;
            }
        },
        leave(node) {
            // refactor default class exports to be a stand alone declaration and a default export let declaration
            if (ast_1.Program.is(node)) {
                let originalImports = node.body.filter(node => ImportDeclaration_1.default.is(node));
                for (let i of originalImports) {
                    if (i.export) {
                        throw common_1.SemanticError("export import not implemented yet: ", i);
                    }
                }
                let others = node.body.filter(node => !ImportDeclaration_1.default.is(node));
                //  start with all imports that have no specifiers (for side-effects only)
                let newImports = originalImports.filter(i => i.specifiers.length === 0);
                for (let declaration of originalImports) {
                    let specifiersArray = new Array();
                    //  first add all ImportNamespaceSpecifiers to their own sets
                    for (let s of declaration.specifiers) {
                        if (ImportNamespaceSpecifier_1.default.is(s)) {
                            specifiersArray.push([s]);
                        }
                    }
                    //  then add ImportDefaulSpecifiers to any existing sets
                    for (let s of declaration.specifiers) {
                        if (ImportDefaultSpecifier_1.default.is(s)) {
                            let addTo = specifiersArray.find(a => a.length === 1 && ImportNamespaceSpecifier_1.default.is(a[0]));
                            if (addTo != null) {
                                addTo.unshift(s);
                            }
                            else {
                                specifiersArray.push([s]);
                            }
                        }
                    }
                    //  finally, add all remaining ImportSpecifiers to a set that can contain them.
                    let specifiers = declaration.specifiers.filter(ImportSpecifier_1.default.is);
                    if (specifiers.length > 0) {
                        let addTo = specifiersArray.find(a => a.length === 1 && ImportDefaultSpecifier_1.default.is(a[0]));
                        if (addTo != null) {
                            addTo.push(...specifiers);
                        }
                        else {
                            specifiersArray.push(specifiers);
                        }
                    }
                    newImports.push(...specifiersArray.map(specifiers => declaration.patch({ specifiers })));
                }
                return node.patch({ body: [...newImports, ...others] });
            }
        }
    });
}
exports.default = fixImports;
