function refreshStatus($id, $source) {
    fetch($source)
    .then( (response) => response.text() )
    .then( (text) => {
        document.getElementById($id).innerText = text;
    });
}

function refreshHTML($id, $source) {
    fetch($source)
    .then( (response) => response.text() )
    .then( (text) => {
        document.getElementById($id).innerHTML = text;
    });
}

function setupRefreshStatus($id, $source, $interval) {
    refreshStatus($id, $source);
    setInterval( function () { refreshStatus($id, $source); }, $interval );
}

function setupRefreshHTML($id, $source, $interval) {
    refreshHTML($id, $source);
    setInterval( function () { refreshHTML($id, $source); }, $interval );
}

function sendCallback($callback, $key, $value) {
    var $body = encodeURIComponent($key)+"="+encodeURIComponent($value);
    fetch($callback, {
        method: "post", 
        headers: {"Content-Type": "application/x-www-form-urlencoded"},
        body: $body
    } );
}

function handleCheckboxChange($id, $callback) {
    var $state = document.getElementById($id).checked;
    sendCallback($callback, $id, $state?"1":"0");
}

function handleChange($id, $callback) {
    var $state = document.getElementById($id).value;
    sendCallback($callback, $id, $state);
}

function reloadContent($id, $source) {
    fetch($source)
    .then( (response) => response.text() )
    .then( (text) => {
        var $elem = document.getElementById($id);
        $elem.value = text;
        if ( $elem.onchange != null ) {
            $elem.onchange();
        }
    });
}

function clearControlPoints($callback) {
    const div = document.createElement("div");
    div.className = "assethome";
    div.innerText = "Recent control points list cleared";

    document.getElementById("controlpoints").replaceWith(div);

    fetch($callback, { method: "post" });
}
function splitLines(arg) {
    return arg.split("\r\n");
}
function browseLevel(arg) {
    let ret = 0;
    for( let i = 0; i < arg.length; ++ i) {
        if ( arg[i] == '\\' ) ++ ret;
    }
    return ret;
}
function stripParent(arg) {
    let base = 0;
    for( let i = 0; i < arg.length; ++ i ) {
        if ( arg[i] == '\\' ) base = i+1;
    }
    return arg.substr(base);
}


// ===== BROWSE TREE CODE =====

const strAtoZ = "{_a_to_z_}";
const strNoTrackListing = "{_no_track_list_}";

class browseItem {
    name = "";
    children = []; // array of browseItem
    trackListing = true;
    AtoZ = false;
    element = null; // <li>
};
// array of browseItem
var g_browseTree = null;
var g_assetID = 0;

var g_browseOptions = null; // array of strings, loaded dynamically

var g_rootElem = null;

function subAssetPath(path) {
    if (g_assetID > 0) {
        path = "/subasset-" + g_assetID + path;
    }
    return path;
}

function browseTreeBuild( items, prefix ) {
    var ret = "";
    items.forEach( (item) => {
        ret += prefix;
        ret += item.name;
        if ( item.AtoZ ) ret += strAtoZ;
        if ( !item.trackListing ) ret += strNoTrackListing;
        ret += "\r\n";
        if ( item.children.length > 0 ) {
            ret += browseTreeBuild( item.children, prefix + item.name + "\\");
        }
    });
    return ret;
}
function browseTreeCommit() {
    var content = browseTreeBuild(g_browseTree, "");
    // console.log(content);
    var target = subAssetPath("/browsetree-save");
    var data = new FormData();
    data.append("Content", content);
    fetch( target, {
        method: 'POST',
        body: data
    });
}

function browseTreeParentRecur( item, parent ) {
    if ( parent.children == null ) return null;
    if ( parent.children.indexOf(item) >= 0 ) return parent;
    for( var i = 0; i < parent.children.length; ++ i ) {
        var ret = browseTreeParentRecur(item, parent.children[i]);
        if ( ret != null ) return ret;
    }
    return null;
}

function browseTreeParent( item ) {
    if ( g_browseTree.indexOf( item ) >= 0 ) {
        return null; // root
    }

    for( var i = 0; i < g_browseTree.length; ++ i ) {
        var ret = browseTreeParentRecur( item, g_browseTree[i] );
        if ( ret != null ) return ret;
    }
    return null; // should not get here
}

function browseTreeParentArray(item) {
    var parent = browseTreeParent(item);
    return (parent == null) ? g_browseTree : parent.children;
}

function browseTreeExpand( li ) {
    var lst = li.getElementsByClassName("tree-ul");
    if ( lst.length > 0 ) lst[0].classList.toggle("tree-active", true);
    lst = li.getElementsByClassName("tree-caret");
    if ( lst.length > 0 ) lst[0].classList.toggle("tree-caret-down", true);
}

function browseTreeRemoveItem(item) {
    var parentItem = browseTreeParent(item);
    var parentArray = (parentItem == null) ? g_browseTree : parentItem.children;
    if ( parentArray == null ) return; // should not be possible
    var index = parentArray.indexOf(item);
    if ( index < 0 ) return; // should not be possible
    parentArray.splice(index, 1);
    browseTreeCommit();

    if ( parentArray.length == 0 && parentItem != null ) {
        // reload parent
        var elem_old = parentItem.li;
        var elem_new = renderTreeItem( parentItem );
        browseTreeExpand( elem_new );
        elem_old.replaceWith( elem_new );
    } else {
        item.li.remove();
    }
}

function makeTreeCaret( ul ) {
    var span = document.createElement("span");
    span.innerText = "\u25B6";
    if ( ul != null ) {
        span.className = "tree-caret";
        span.onclick = function() {
            this.classList.toggle("tree-caret-down");
            ul.classList.toggle("tree-active");
        };
    } else {
        span.className = "tree-caret-dummy";
    }
    return span;
}

function renderTreeItemContent(item) {

    var select = document.createElement("select");
    g_browseOptions.forEach( (str) => {
        var option = document.createElement("option");
        option.text = str;
        option.selected = (str == item.name);
        select.add(option);
    });

    select.onchange = function() {
        item.name = this.value;
        browseTreeCommit();
    };

    return select;
}

function newBrowseItem() {
    var item = new browseItem;
    item.name = g_browseOptions[0];
    return item;
}

// returns <li> of the item
function renderTreeItem(item, expand) {
    var li = document.createElement("li");
    var ul2 = null;
    if ( item.children.length > 0 ) {
        ul2 = renderTree(item.children);
    }
    li.appendChild(makeTreeCaret(ul2));
    li.appendChild(renderTreeItemContent(item));
    var dropdown = document.createElement("div");
    dropdown.className = "dropdown-content";
    var checkbox = document.createElement("input");
    checkbox.type = "checkbox";
    checkbox.checked = item.AtoZ;
    checkbox.onchange = function() {
        item.AtoZ = this.checked;
        browseTreeCommit();
    };
    dropdown.appendChild(checkbox);
    dropdown.insertAdjacentText("beforeend", "A to Z" );
    dropdown.appendChild( document.createElement("br") );
    checkbox = document.createElement("input");
    checkbox.type = "checkbox";
    checkbox.checked = item.trackListing;
    checkbox.onchange = function() {
        item.trackListing = this.checked;
        browseTreeCommit();
    };
    dropdown.appendChild(checkbox);
    dropdown.insertAdjacentText("beforeend", "track listing" );

    dropdown.appendChild( document.createElement("br") );
    {
        var btn = document.createElement("button");
        btn.innerText = "- remove this item";
        btn.onclick = function() {
            if (confirm( item.name != "" ? ("Remove item: " + item.name + " ?") : "Remove this item?")) {
                browseTreeRemoveItem( item );
            }
        };
        dropdown.appendChild(btn);
    }
    dropdown.appendChild( document.createElement("br") );

    {
        var btn;
        btn = document.createElement("button");
        btn.innerText = "+ insert before";
        btn.onclick = function() {
            var parentArray = browseTreeParentArray(item);
            if ( parentArray == null ) return;
            var index = parentArray.indexOf(item);
            if ( index < 0 ) return;
            var item_new = newBrowseItem();
            parentArray.splice( index, 0, item_new);
            var elem_new = renderTreeItem( item_new );
            li.insertAdjacentElement("beforebegin", elem_new);
            dropdown.classList.toggle("dropdown-show", false);
            browseTreeCommit();
        };
        dropdown.appendChild(btn);
        btn = document.createElement("button");
        btn.innerText = "+ insert into";
        btn.onclick = function() {
            var newItem = newBrowseItem();
            if ( item.children == null ) item.children = [newItem];
            else item.children.push(newItem);
            
            if ( ul2 == null ) {
                var elem_old = item.li;
                var elem_new = renderTreeItem( item );
                browseTreeExpand( elem_new );
                elem_old.replaceWith(elem_new);
            } else {
                var elem_new = renderTreeItem( newItem );
                ul2.append( elem_new );
            }
            browseTreeExpand(li);
            dropdown.classList.toggle("dropdown-show", false);
            browseTreeCommit();
        };
        dropdown.appendChild(btn);
        btn = document.createElement("button");
        btn.innerText = "+ insert after";
        btn.onclick = function() {
            var parentArray = browseTreeParentArray(item);
            if ( parentArray == null ) return;
            var index = parentArray.indexOf(item);
            if ( index < 0 ) return;
            var item_new = newBrowseItem();
            parentArray.splice( index + 1, 0, item_new);
            var elem_new = renderTreeItem( item_new );
            li.insertAdjacentElement("afterend", elem_new);
            dropdown.classList.toggle("dropdown-show", false);
            browseTreeCommit();
        };
        dropdown.appendChild(btn);    
    }

    var btn = document.createElement("button");
    btn.innerText = "...";
    btn.onclick = function() {
        var lst = document.getElementsByClassName("dropdown-content");
        for( var i = 0; i < lst.length; ++ i) {
            var dd = lst[i];
            if ( dd != dropdown ) dd.classList.toggle("dropdown-show", false);
        }
        dropdown.classList.toggle("dropdown-show");
    };
    li.insertAdjacentText("beforeend", " "); // spacing before button
    li.appendChild(btn);

    li.appendChild(dropdown);
    if ( ul2 != null ) li.appendChild(ul2);
    item.li = li;
    return li;
}

function renderTree(items) {
    var ul = document.createElement("ul");
    ul.className = "tree-ul tree-nested";
    items.forEach( (item) => {
        ul.appendChild(renderTreeItem(item));
    });
    return ul;
}

function reloadBrowseTree() {
    var ul = renderTree(g_browseTree);
    ul.className = "tree-root tree-ul tree-active";
    g_rootElem.replaceWith(ul);
    g_rootElem = ul;
}

function importBrowseTree(text) {
    let stack = [ new browseItem ];
    splitLines(text).forEach( (line) => {
        let itemLevel = browseLevel(line);
        let label = stripParent(line);
        let stackPos = itemLevel + 1;
        if (stackPos > stack.length) return; // invalid
        while(stack.length > stackPos) stack.pop();
        // now stack.length == stackPos
        var item = new browseItem;
        if ( label.search(strAtoZ) >= 0 ) {
            label = label.replace(strAtoZ, "");
            item.AtoZ = true;
        }
        if ( label.search(strNoTrackListing) >= 0 ) {
            label = label.replace(strNoTrackListing, "");
            item.trackListing = false;
        }
        item.name = label;
        stack[itemLevel].children.push(item);
        stack.push(item);
        // now stack.length == stackPos+1
    });
    g_browseTree = stack[0].children;
}

async function setupBrowseTree(assetID) {
    g_assetID = assetID;
    g_rootElem = document.getElementById("browsetree");

    var req_options = fetch("/browsetree-options");
    
    var text = await (await fetch(subAssetPath("/browsetree-load"))).text();
    importBrowseTree(text);

    var text = await (await req_options).text();
    g_browseOptions = splitLines(text); // fill before renderTree    
    reloadBrowseTree();
}

async function resetBrowseTree() {
    if (!confirm("Discard current settings and load defaults?")) return;
    var text = await (await fetch(subAssetPath("/browsetree-defaults"))).text();
    importBrowseTree( text );
    reloadBrowseTree();
    browseTreeCommit();
}
