import { window } from 'vscode';

/**
 * Creates a response for a RefactorErl question
 * Request is canceled if the user does not answer it
 * @param Question Array which contains the question data
 * @returns string of the response
 */
export async function CreateQuestionAnswer(Question:any):Promise<string>{
    let ReqID = "{reqid, \""+Question[0][1]+"\"}";
    let QuestionID = Question[2][0];
    
    /** Text to return in case of cancel */
    let cancelText = "{"+ReqID+", cancel, "+QuestionID+"}.\n";
    let format = findPair("format", Question[2][1][0]);
    let Prompt = findPair("text", Question[2][1][0]);

    /** Question is selectlist type */
    if(format === "info"){
        let QPItems = [];
        let CPM = false;
        for(let Elem of Question[2][1].slice(1)){
            QPItems.push(Elem[0][1]);
            if(Elem[1][1] === "checkbox"){ CPM = true; }
        }
        
        let picked = await window.showQuickPick(QPItems, {placeHolder:Prompt, canPickMany:CPM});
        if(picked === undefined){ return cancelText; }

        let PickedArr = CPM ? picked : [picked];
        let answerArr = ["info"];
        for(let Elem of QPItems){
            answerArr.push(PickedArr.indexOf(Elem) !== -1 ? "yes" : "no");
        }
        return "{"+ReqID+", reply, "+QuestionID+", ["+answerArr.join(',')+"]}.\n";
    }
    /** Question is textbox type */
    if(format === "textbox"){
        let validator = findPair("validator", Question[2][1][0]);
        let DefaultValue = findPair("default", Question[2][1][0]);
        let answer = await window.showInputBox({
                prompt : Prompt,
                value: DefaultValue === -1 ? "" : DefaultValue,
                validateInput: (text:string) => validate(text, validator)
            });
        if(answer === undefined) { return cancelText; }
        return "{"+ReqID+", reply, "+QuestionID+", [\""+answer+"\"]}.\n";
    }

    /** Cancel the request in case of unhandled format */
    return cancelText;
}

/**
 * Finds the value pair of a key in the given array
 * @param Key Key to find
 * @param Arr Array in which to search
 */
function findPair(Key:string, Arr:any){
    for(let Elem of Arr){
        if(!Array.isArray(Elem)){ return ""; }
        if(Elem[0] === Key){ return Elem[1]; }
    }
    return "";
}

/**
 * Validates the input written in the textbox if necessary
 * @param input Input to validate
 * @param validator Type of validation
 * @returns null if the input is valid, the text itself otherwise
 */
function validate(input:string, validator:string):string|null{
    if(validator === "header"){ return is_header(input); }
    if(validator === "atom" || validator === "module"){
        return is_atom(input);
    }
    if(validator === "variable"){ return is_var(input); }
    return null;
}

/**
 * Checks if a string is an erlang atom
 * @param text Received string
 * @returns null if yes, the text itself otherwise
 */
function is_atom(text:string):string|null{
    if(text.search(/^[a-z][0-9a-zA-Z_]*$/g) === 0){ return null; }
	return text;
}

/**
 * Checks if a string is an erlang header file name
 * @param text Received string
 * @returns null if yes, the text itself otherwise
 */
function is_header(text:string):string|null{
    if(text.search(/^[a-z][0-9a-zA-Z_]*\.hrl$/g) === 0){ return null; }
	return text;
}

/**
 * Checks if a string is an erlang variable
 * @param text Received string
 * @returns null if yes, the text itself otherwise
 */
function is_var(text:string):string|null{
    if(text.search(/^[A-Z][0-9a-zA-Z_]*$/g) === 0){ return null; }
    return text;
}