import { Named, Map, List, Optional, } from "@wapc/widl/ast";
import { translations, primitives } from "./constant";
import { snakeCase } from "../utils";
/**
 * Takes an array of ValuedDefintions and returns a string based on supplied params.
 * @param sep seperator between name and type
 * @param joinOn string that each ValuedDefintion is joined on
 * @returns string of format <name> <sep> <type><joinOn>...
 */
export function mapVals(vd, sep, joinOn) {
    return vd
        .map((vd) => `${vd.name.value}${sep} ${expandType(vd.type, undefined, true, isReference(vd.annotations))}`)
        .join(joinOn);
}
/**
 * Return default value for a FieldDefinition. Default value of objects are instantiated.
 * @param fieldDef FieldDefinition Node to get default value of
 */
export function defValue(fieldDef) {
    const name = fieldDef.name.value;
    const type = fieldDef.type;
    if (fieldDef.default) {
        let returnVal = fieldDef.default.getValue();
        if (fieldDef.type instanceof Named) {
            returnVal =
                fieldDef.type.Name.value == "string"
                    ? strQuote(returnVal)
                    : returnVal;
        }
        return returnVal;
    }
    switch (type.constructor) {
        case Optional:
            return "None";
        case List:
            return "Vec::new()";
        case Map:
            return "Map::new()";
        case Named:
            switch (type.Name.value) {
                case "ID":
                case "string":
                    return '""';
                case "bool":
                    return "false";
                case "i8":
                case "u8":
                case "i16":
                case "u16":
                case "i32":
                case "u32":
                case "i64":
                case "u64":
                case "f32":
                case "f64":
                    return "0";
                case "bytes":
                    return "Vec::new()";
                default:
                    return `${capitalize(name)}()`; // reference to something else
            }
    }
    return `???${expandType(type, undefined, false, isReference(fieldDef.annotations))}???`;
}
export function defaultValueForType(type, packageName) {
    switch (type.constructor) {
        case Optional:
            return "None";
        case List:
            return "Vec::new()";
        case Map:
            return "Map::new()";
        case Named:
            switch (type.Name.value) {
                case "ID":
                case "string":
                    return '"".to_string()';
                case "bool":
                    return "false";
                case "i8":
                case "u8":
                case "i16":
                case "u16":
                case "i32":
                case "u32":
                case "i64":
                case "u64":
                case "f32":
                case "f64":
                    return "0";
                case "bytes":
                    return "Vec::new()";
                default:
                    const prefix = packageName != undefined && packageName != ""
                        ? packageName + "."
                        : "";
                    return `${prefix}${capitalize(type.Name.value)}::default()`; // reference to something else
            }
    }
    return "???";
}
/**
 * returns string in quotes
 * @param s string to have quotes
 */
export const strQuote = (s) => {
    return `\"${s}\"`;
};
/**
 * returns string of the expanded type of a node
 * @param type the type node that is being expanded
 * @param useOptional if the type that is being expanded is optional
 * @param isReference if the type that is being expanded has a `@ref` annotation
 */
export const expandType = (type, packageName, useOptional, isReference) => {
    switch (true) {
        case type instanceof Named:
            if (isReference) {
                return "String";
            }
            var namedValue = type.Name.value;
            const translation = translations.get(namedValue);
            if (translation != undefined) {
                return (namedValue = translation);
            }
            if (isObject(type) && packageName != undefined && packageName != "") {
                return packageName + "." + namedValue;
            }
            return namedValue;
        case type instanceof Map:
            return `std::collections::HashMap<${expandType(type.keyType, packageName, true, isReference)}, ${expandType(type.valueType, packageName, true, isReference)}>`;
        case type instanceof List:
            return `Vec<${expandType(type.type, packageName, true, isReference)}>`;
        case type instanceof Optional:
            const nestedType = type.type;
            let expanded = expandType(nestedType, packageName, true, isReference);
            if (useOptional) {
                return `Option<${expanded}>`;
            }
            return expanded;
        default:
            return "unknown";
    }
};
/**
 * Determines if a node is a void node
 * @param t Node that is a Type node
 */
export function isVoid(t) {
    if (t instanceof Named) {
        return t.Name.value == "void";
    }
    return false;
}
/**
 * Determines if Type Node is a Named node and if its type is not one of the base translation types.
 * @param t Node that is a Type node
 */
export function isObject(t) {
    if (t instanceof Named) {
        return !primitives.has(t.Name.value);
    }
    return false;
}
/**
 * Determines if one of the annotations provided is a reference
 * @param annotations array of Annotations
 */
export function isReference(annotations) {
    for (let annotation of annotations) {
        if (annotation.name.value == "ref" ||
            annotation.name.value == "reference") {
            return true;
        }
    }
    return false;
}
/**
 * Capitalizes a given string
 * @param str string to be capitlized
 * @returns string with first character capitalized. If empty string returns empty string.
 */
export function capitalize(str) {
    if (str.length == 0)
        return str;
    if (str.length == 1)
        return str[0].toUpperCase();
    return str[0].toUpperCase() + str.slice(1);
}
export function functionName(str) {
    return snakeCase(str);
}
export function fieldName(str) {
    return snakeCase(str);
}
/**
 * Given an array of OperationDefintion returns them as functions with their arguments
 * @param ops
 */
export function opsAsFns(ops) {
    return ops
        .map((op) => {
        return `func ${op.name.value}(${mapArgs(op.arguments)}) ${expandType(op.type, undefined, true, isReference(op.annotations))} {\n}`;
    })
        .join("\n");
}
/**
 * returns string of args mapped to their type
 * @param args InputValueDefintion array which is an array of the arguments
 */
export function mapArgs(args, template = false) {
    return args
        .map((arg) => {
        return mapArg(arg, template);
    })
        .join(", ");
}
export function mapArg(arg, template = false) {
    return ((template ? "_" : "") +
        `${arg.name.value}: ${expandType(arg.type, undefined, true, isReference(arg.annotations))}`);
}
/**
 * returns if a widl type is a node
 * @param o ObjectDefintion which correlates to a widl Type
 */
export function isNode(o) {
    for (const field of o.fields) {
        if (field.name.value.toLowerCase() == "id") {
            return true;
        }
    }
    return false;
}
export function varAccessArg(variable, args) {
    return args
        .map((arg) => {
        return `${variable}.${snakeCase(arg.name.value)}`;
    })
        .join(", ");
}
//# sourceMappingURL=helpers.js.map