/*
    PUA2OT: A utility for converting MUFI PUA characters to standard
    Unicode with Junicode's OpenType features.

    Code for charlist.html, a test and reference page for pua2ot.

    Copyright © 2025-26 by Peter S. Baker
    Licensed under the Apache License, version 2.0:
    https://www.apache.org/licenses/LICENSE-2.0
*/


const otagpref =   ['otag', 'utag', 'zwj', 'entity', 'enla'];
const utagpref =   ['utag', 'otag', 'zwj', 'entity', 'enla'];
const zwjpref =    ['zwj', 'utag', 'otag', 'entity', 'enla'];
const entitypref = ['entity', 'zwj', 'utag', 'otag', 'enla'];
const enlapref =   ['enla', 'entity', 'zwj', 'utag', 'otag'];

//const table = document.getElementById('tbl');
const dialog =     document.getElementById('method_info');
const info_para =  document.getElementById("dialogtext");
const dlg_header = document.getElementById("dialogheadertext");
const tbl_head =   document.getElementById("table_head");
const tbl_body =   document.getElementById("table_body");
const copy_text =  document.getElementById("copyText");

let isMark = false;

let lastSelection = null;

/**
 * Converts a string hex code to a character.
 * 
 * @param {string} hexString - The hex code of the desired character.
 * @returns {string} A one-character string.
 */
function hexToChar(hexString) {
    let i = parseInt(hexString, 16);
    return String.fromCodePoint(i);
}

/**
 * For each character in a string, get the hex code and save it
 * in a space-separated list.
 * 
 * @param {string} s - A string to get the hex codes for.
 * @returns {string} string containing the hex codes for each character in a string.
 */
function makeHex(s) {
    let result = "";
    for (const c of s) {
        const i = c.codePointAt(0);
        let hexstr = i.toString(16).toUpperCase();
        while (hexstr.length < 4) {
            hexstr = '0' + hexstr;
        }
        if (result.length > 0) {
            result = result + ' ';
        }
        result = result + hexstr
    }
    return result;
}

/**
 * Make one row of the table generated by this script.
 * 
 * @param {string} hex - The hex code for this row.
 * @param {string} vartext - Text for the "var" column of the table.
 * @param {Object} block - The block recording the methods for this row.
 * @param {string} desc - The MUFI description for this glyph.
 * @returns {object} The row generated by this function.
 */
function makeRow(hex, vartext, block, desc) {
    let ch = hexToChar(hex);
    //
    // HEX CODE
    //
    const row = document.createElement("tr");
    const hexcell = document.createElement("td");
    cellContent = hex;
    hexcell.innerHTML = cellContent;
    hexcell.classList.add("hex");
    row.appendChild(hexcell);
    //
    // VAR LABEL
    //
    const varcell = document.createElement("td");
    varcell.classList.add("varc");
    if (vartext != null) {
        varcell.textContent = vartext;
    }
    row.appendChild(varcell);
    //
    // DESCRIPTION
    //
    const desccell = document.createElement("td");
    desccell.classList.add("desc");
    desccell.innerHTML = desc.toLowerCase();
    row.appendChild(desccell);
    //
    // PUA CHARACTER
    //
    const puacell = document.createElement("td");
    puacell.classList.add("char");
    let b = ch;
    if (isMark) {
        b = "\u25CC" + b;
    }
    puacell.textContent = b;
    row.appendChild(puacell);
    //
    // BASE
    //
    const basecell = document.createElement("td");
    basecell.classList.add("basec");
    if ("base" in block) {
        b = block["base"];
        if (isMark) {
            b = "\u25CC" + b;
        }
        basecell.textContent = b;
    }
    row.appendChild(basecell);
    //
    // OTAG
    //
    const otagcell = document.createElement("td");
    otagcell.classList.add("otag");
    if ("otag" in block) {
        options.prefList = otagpref;
        b = ch;
        if (isMark) {
            b = "\u25CC" + b;
        }
        otagcell.innerHTML = convert(b);
    }
    row.appendChild(otagcell);
    //
    // UTAG
    //
    const utagcell = document.createElement("td");
    utagcell.classList.add("utag");
    if ("utag" in block) {
        options.prefList = utagpref;
        b = convert(ch);
        if (isMark) {
            b = "\u25CC" + b;
        }
        utagcell.innerHTML = b;
    }
    row.appendChild(utagcell);
    //
    // ZWJ 
    //
    const zwjcell = document.createElement("td");
    zwjcell.classList.add("zwj");
    if ("zwj" in block) {
        options.prefList = zwjpref;
        b = convert(ch);
        if (isMark) {
            b = "\u25CC" + b;
        }
        zwjcell.innerHTML = b;
    }
    row.appendChild(zwjcell);
    //
    // ENTITY
    //
    const entitycell = document.createElement("td");
    entitycell.classList.add("entity");
    if ("entity" in block) {
        options.prefList = entitypref;
        b = convert(ch);
        if (isMark) {
            b = "\u25CC" + b;
        }
        entitycell.textContent = b;
    }
    row.appendChild(entitycell);
    //
    // ENLA
    //
    const enlacell = document.createElement("td");
    enlacell.classList.add("enla");
    if ("enla" in block) {
        options.prefList = enlapref;
        b = convert(ch);
        enlacell.innerHTML = b;
    }
    row.appendChild(enlacell);

    return row;
}

/**
 * Make a cell for the table header.
 * 
 * @param {string} name - A name for this cell.
 * @param {object} parent - the parent element to which we will add this cell.
*/
function tableHeaderCell(name, parent) {
    const cell = document.createElement("th");
    cell.textContent = name;
    parent.appendChild(cell);
}

/**
 * Figures out which members two arrays have in common and returns
 * an array with just those members.
 * 
 * @param {array} a - one of the arrays to compare.
 * @param {array} b - the other array to comnpare.
 * @returns {array} an array containing the common elements.
 */
function intersect(a, b) {
    var t;
    if (b.length > a.length) t = b, b = a, a = t;
    return a.filter(function (e) {
        return b.indexOf(e) > -1;
    });
}

/**
 * Copies text to the clipboard.
 * 
 * @param {string} t - The text to copy.
 */
async function toClipboard(t) {
    try {
        await navigator.clipboard.writeText(t);
    } catch (err) {
        console.error('Failed to copy text: ', err);
    }
}

/*
  Helper for "Filter" input event.
*/
function filterTable () {
  let input, filter, table, tr, td, i, txtValue;
  input = document.getElementById("tblfilter");
  filter = input.value.toUpperCase();
  isFilterHex = isHex(filter);
  table = document.getElementById("tbl");
  tr = table.getElementsByTagName("tr");
  for (i = 0; i < tr.length; i++) {
    td = tr[i].getElementsByTagName("td")[isFilterHex ? 0 : 2];
    if (td) {
        txtValue = td.textContent || td.innerText;
        idx = txtValue.toUpperCase().indexOf(filter);
        tr[i].style.display = (isFilterHex ? idx == 0 : idx > -1) ? "" : "none";
    }
  }
}

document.getElementById("tblfilter").addEventListener("input", function(e) {
    filterTable();
});

/**
 * Sets up listeners that make many cells in the table
 * clickable.
 */
function setupListeners() {
    tbl_body.addEventListener('click', function(e) {
        tgt = e.target.closest('td');
        if (lastSelection != null) {
            lastSelection.style = '';
        }
        lastSelection = tgt;
        const cl = Array.from(tgt.classList);
        if (intersect(cl, otagpref).length > 0) {
            let tc = tgt.innerHTML;
            tc = tc.replaceAll("&amp;", "&");
            tc = tc.replaceAll("\u200D", "&zwj;");
            if (tc.length > 0) {
                tgt.style.backgroundColor = "DarkSeaGreen";
                dlg_header.innerHTML = "Character code:";
                info_para.innerText = tc;
                dialog.showModal();
           }
        } else if (cl.includes("basec")) {
            tgt.style.backgroundColor = "DarkSeaGreen";
            let hs = tgt.innerText;
            dlg_header.innerHTML = "Base code points:";
            info_para.innerText = makeHex(hs);
            dialog.showModal();
        }
    })
    copy_text.addEventListener('click', function(e) {
        toClipboard(info_para.innerText);
    });
}

// We need to be able to see these Unicode tags.
options.utagEntities = true;

let toprow = document.createElement("tr");
tableHeaderCell("hex", toprow);
tableHeaderCell("var", toprow);
tableHeaderCell("description", toprow);
tableHeaderCell("pua", toprow);
tableHeaderCell("base", toprow);
tableHeaderCell("otag", toprow);
tableHeaderCell("utag", toprow);
tableHeaderCell("zwj", toprow);
tableHeaderCell("entity", toprow);
tableHeaderCell("enla", toprow);
tbl_head.appendChild(toprow);

let PUA_LIST = [];
for (h in PUA_DATA) {
    PUA_LIST.push(hex2int(h));
}
let puaCounter = 0
PUA_LIST.sort((a, b) => a - b);
for (const hi of PUA_LIST) {
    const h = int2hex(hi);
    let description = "";
    let block = PUA_DATA[h];
    if ("desc" in block) {
        description = block.desc;
        isMark = block.desc.includes("COMBINING");
    } else {
        isMark = false;
    }
    let topbase = "";
    if ("base" in block) {
        topbase = block["base"];
    }
    if ("var" in block) {
        dbl = block["var"];
        for (d in dbl) {
            const varbackup = options.basePreferences;
            options.basePreferences = [d];
            let r = makeRow(h, d, dbl[d], description);
            tbl_body.appendChild(r);
            options.basePreferences = varbackup;
            puaCounter += 1;
        }
    } else {
        r = makeRow(h, null, block, description);
        tbl_body.appendChild(r);
        puaCounter += 1;
    }
}
console.log("Rows:", puaCounter);

setupListeners();
