/*
    Make sending lists over take less space

    Since we have a known list of the exercises a class is meant to do during a
    course, we can see it as a list of booleans of which exercises are done.

*/

"use strict";

const base = [ // A list of Base64 characters
    "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M",
    "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
    "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m",
    "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
    "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "+", "."
];

/**
 * Tests if a string looks like a coded exercise list
 * @param {String} The string to be tested
 */
let _test = (str) => ( /^(\w|\.|\+)*$/ ).test(str);

/**
 * Packs an exercise list to a base64 string
 * @param {String[]} fullList The list of all possible exercises
 * @param {String[]} doneList The list of done exercises
 */
let pack = (fullList, doneList) => {

    let result = ""; // Resulting base64 string
    let _f     = fullList; // Shorthand for fullList

    while(_f.length > 0) {
        let b = 0b0; // Will be the base64 character (6-bits)
        let c = _f.splice(0, 6); // Get the next 6 exercises
        if(c.length > 0) { // FIXME : Is this check needed?
            // This could be more elegant but now it's understandable
            b = b || ((doneList.indexOf( c[0] ) > -1) * 0b100000)
                  || ((doneList.indexOf( c[1] ) > -1) * 0b010000)
                  || ((doneList.indexOf( c[2] ) > -1) * 0b001000)
                  || ((doneList.indexOf( c[3] ) > -1) * 0b000100)
                  || ((doneList.indexOf( c[4] ) > -1) * 0b000010)
                  || ((doneList.indexOf( c[5] ) > -1) * 0b000001);
            result += base[b]; // Look up the character for this 6-bit byte
        }
    }

    return result;

}

/**
 * Unpacks the done exercises from a base64 string
 * @param {String[]} fullList The list of all possible exercises
 * @param {String} doneString The string that denotes which exercises are done
 */
let unpack = (fullList, doneString) => {

    // Test if the string is allowed
    if(!_test(doneString)) throw "Malformed";

    let result = []; // Resulting exercise list
    let _f     = fullList; // Shorthand for fullList

    for(let c in doneString) {
        let char = doneString[c];
            char = base.indexOf(char);
        let part = _f.splice(0, 6);

        // Ugly but does the job
        if((char & 0b100000) == 32) result.push( part[0] );
        if((char & 0b010000) == 16) result.push( part[1] );
        if((char & 0b001000) ==  8) result.push( part[2] );
        if((char & 0b000100) ==  4) result.push( part[3] );
        if((char & 0b000010) ==  2) result.push( part[4] );
        if((char & 0b000001) ==  1) result.push( part[5] );
    }

    return result;

}

module.exports = { pack: pack, unpack: unpack, _test: unpack };