/*
 * Copyright (c) 2018 Mol* contributors, licensed under MIT, See LICENSE file for more info.
 *
 * @author David Sehnal <david.sehnal@gmail.com>
 */

import Type from './type'
import { MSymbol, Arguments, isSymbol } from './symbol'

export function symbol<A extends Arguments, T extends Type<S>, S>(args: A, type: T, description?: string) {
    return MSymbol('', args, type, description);
}

export function normalizeTable(table: any) {
    _normalizeTable('', '', table);
}

export function symbolList(table: any): MSymbol[] {
    const list: MSymbol[] = [];
    _symbolList(table, list);
    return list;
}

function formatKey(key: string) {
    const regex = /([a-z])([A-Z])([a-z]|$)/g;
    // do this twice because 'xXxX'
    return key.replace(regex, (s, a, b, c) => `${a}-${b.toLocaleLowerCase()}${c}`).replace(regex, (s, a, b, c) => `${a}-${b.toLocaleLowerCase()}${c}`);
}

function _normalizeTable(namespace: string, key: string, obj: any) {
    if (isSymbol(obj)) {
        obj.info.namespace = namespace;
        obj.info.name = obj.info.name || formatKey(key);
        obj.id = `${obj.info.namespace}.${obj.info.name}`;
        return;
    }
    const currentNs = `${obj['@namespace'] || formatKey(key)}`;
    const newNs = namespace ? `${namespace}.${currentNs}` : currentNs;
    for (const childKey of Object.keys(obj)) {
        if (typeof obj[childKey] !== 'object' && !isSymbol(obj[childKey])) continue;
        _normalizeTable(newNs, childKey, obj[childKey]);
    }
}

function _symbolList(obj: any, list: MSymbol[]) {
    if (isSymbol(obj)) {
        list.push(obj);
        return;
    }
    for (const childKey of Object.keys(obj)) {
        if (typeof obj[childKey] !== 'object' && !isSymbol(obj[childKey])) continue;
        _symbolList(obj[childKey], list);
    }
}