// 01122011 AMD1 startWidget listWidgets getWidget implemented
/* wrapper as a module
 var iphone_wm_gui = (function () {
 */
// to make sure the initialization is done only once
var init = true;

// constant
var xlinkns = 'http://www.w3.org/1999/xlink';
//var evns = 'http://www.w3.org/2001/xml-events';

// state of the widget manager: displays homepage (value=home) or executes widget (value="exec")
var state = 'home';

// convenience variables for SVG elements
var homepage = null, arrows = null, icons = null, widgetContainer = null, homebar = null, execbar = null;

// where is the index into pages of icons on the home page
var where = 0,maxwhere = 0,whereW = 0;

// array of activated widgets
var activatedWidgets = new Array();
var numActivatedWidgets = 0;

// variables for flexible layout
// variables for flexible layout
var totalWidth = 0,totalHeight = 0,iconNbHoriz = 0,iconNbVert = 0,iconsPerPage = 0;

//previous size
var previousWidth = 0,previousHeight = 0;

// to differentiate between install icon and scan dir for icons
var isThisAScan = null;

// preferred icon type
var preferredIconType = '.svg';

// adapt layout to the size of the screen
function adaptLayoutToSize() {
    if (l_deb < log_level) {
        alert("[UI] adaptLayoutToSize");
    }
    display_width = parseInt(scene.get_option('GUI', 'LastWidth'));
    display_height = parseInt(scene.get_option('GUI', 'LastHeight'));
    alert("display "+display_width+" "+display_height);
    if (!scene.fullscreen && display_width && display_height) {
     scene.set_size(display_width, display_height);
    }
    var tmpObject, tmpObj2;
    // get size to adapt to
    totalWidth = document.documentElement.viewport.width;
    totalHeight = document.documentElement.viewport.height;
    if (totalWidth == 0) {
        totalWidth = 160;
    }
    if (totalHeight == 0) {
        totalHeight = 280;
    }
    while (totalWidth < 160 || totalHeight < 280) {
        totalWidth *= 4;
        totalHeight *= 4;
    }
    // min size is 160 by 280
    if (totalWidth < 160) {
        totalWidth = 160;
    }
    if (totalHeight < 280) {
        totalHeight = 280;
    }
    // round to lower multiple of 80
    totalWidth -= totalWidth % 80;
    var iconHeight = totalHeight - 120;
    iconHeight -= iconHeight % 80;
    // how many lines and columns of icons
    iconNbHoriz = totalWidth / 80;
    iconNbVert = iconHeight / 80;
    totalHeight = iconHeight + 120;
    // 120 is upper bar (60) + lower bar (60)
    iconsPerPage = iconNbHoriz * iconNbVert;
    // fix svg viewbox
    document.getElementById("svg").setAttribute("viewBox", "0 0 " + totalWidth + " " + totalHeight);
    // fix odd line
    tmpObj2 = document.getElementById("odd");
    var i, already = tmpObj2.getElementsByTagName("use").length;
    //alert("odd line "+already+" "+iconNbHoriz);
    for (i = already; i < iconNbHoriz; i++) {
        tmpObject = document.createElement("use");
        tmpObject.setAttribute("x", i * 80);
        tmpObject.setAttributeNS(xlinkns, "href", (((i % 2) == 0) ? "#lightRect" : "#darkRect" ));
        tmpObj2.appendChild(tmpObject);
    }
    // fix even line
    tmpObj2 = document.getElementById("even");
    already = tmpObj2.getElementsByTagName("use").length;
    //alert("even line "+already+" "+iconNbHoriz);
    for (i = already; i < iconNbHoriz; i++) {
        tmpObject = document.createElement("use");
        tmpObject.setAttribute("x", i * 80);
        tmpObject.setAttributeNS(xlinkns, "href", (((i % 2) == 0) ? "#darkRect" : "#lightRect" ));
        tmpObj2.appendChild(tmpObject);
    }
    // fix frame (black with rounded corners)
    tmpObject = document.getElementById("frame");
    tmpObject.setAttribute("width", totalWidth);
    tmpObject.setAttribute("height", totalHeight);
    tmpObject = document.getElementById("frame2");
    tmpObject.setAttribute("width", totalWidth);
    tmpObject.setAttribute("height", totalHeight);
    // fix screen (white)
    tmpObject = document.getElementById("screen");
    tmpObject.setAttribute("width", totalWidth);
    tmpObject.setAttribute("height", totalHeight - 120);
    // fix grid back (gray)
    tmpObject = document.getElementById("gridback");
    tmpObject.setAttribute("width", totalWidth);
    tmpObject.setAttribute("height", totalHeight - 120);
    // fix icon background grid
    tmpObject = document.getElementById("grid");
    already = tmpObject.getElementsByTagName("use").length;
    for (i = already; i < iconNbVert; i++) {
        tmpObj2 = document.createElement("use");
        tmpObj2.setAttribute("y", i * 80);
        tmpObj2.setAttributeNS(xlinkns, "href", (((i % 2) == 0) ? "#odd" : "#even" ));
        tmpObject.appendChild(tmpObj2);
    }
    // if there are already too many lines, remove the extra ones otherwise they are rendered on top of the lower
    // part of the decoration
    if (already > iconNbVert) {
        while (already-- > iconNbVert) {
            tmpObject.removeChild(tmpObject.lastChild);
        }
    }
    // fix commands (lower bar)
    document.getElementById("commands").setAttribute("transform", "translate(0, " + (totalHeight - 60) + ")");
    document.getElementById("homeButton").setAttribute("transform", "translate(" + (totalWidth / 2) + ", 30)");
    document.getElementById("right").setAttribute("transform", "translate(" + (totalWidth - 50) + ", 10)");
    document.getElementById("rightW").setAttribute("transform", "translate(" + (totalWidth - 50) + ", 10)");
    // fix the cuts (white rects left and right because we have no clipping)
    tmpObject = document.getElementById("leftCut");
    tmpObject.setAttribute("width", totalWidth);
    tmpObject.setAttribute("height", totalHeight);
    tmpObject.setAttribute("x", -1 - totalWidth);
    tmpObject = document.getElementById("rightCut");
    tmpObject.setAttribute("width", totalWidth);
    tmpObject.setAttribute("height", totalHeight);
    tmpObject.setAttribute("x", 1 + totalWidth);
    // respace executing widgets if any
    tmpObject = widgetContainer.getElementsByTagName("g");
    for (i = 0; i < tmpObject.length; i++) {
        var gg = tmpObject.item(i);
        gg.setAttribute("transform", "translate(" + (totalWidth * (i - 1)) + ", 0)");
        if (gg.firstElementChild != null) {
            gg.firstElementChild.setAttribute("width", totalWidth);
            gg.firstElementChild.setAttribute("height", totalHeight - 120);
        }
    }
}

//
// widget close on click at "Kill" button
//
function on_kill_widget() {
    if (state == 'exec') {
        widget_close(activatedWidgets[whereW]);
    }
}

//
// widget get on click at "GetW" button
//
function on_get_widget() {
    alert("on_get_widget " + WidgetManager.MPEGUStandardServiceProviders.length);
    if (WidgetManager.MPEGUStandardServiceProviders.length != 0) {
        upnp_renders = selector_window1();
        upnp_renders.on_select = function(item) {
            upnp_renders.unregister(root);
            upnp_renders = null;
            if (item == -1) {
                return;
            }
            alert("upnp_renders.on_select(" + item + ")");
            var device = WidgetManager.MPEGUStandardServiceProviders[item];
            device.standardService.SetActionListener("listWidgets", get_widget_callback(device), true);
            device.standardService.CallAction("listWidgets", new Array());
        }
        upnp_renders.register(root);
    }
}

function get_widget_callback(device) {
    return function() {
        //alert("get_widget_callback");
        // msgHandler is the first argument, the next arguments are from the reply to listWidgets
        var act = arguments[0];
        var act1 = act.GetArgumentValue("widgetCodes");
        var act2 = act.GetArgumentValue("widgetNames");
        //alert(act1+" "+act2);
        target_widgets = selector_window2(act1.split(" "), act2.split(" "));
        target_widgets.on_select = function(item) {
            alert("target_widgets.on_select");
            target_widgets.unregister(root);
            target_widgets = null;
            if (item == -1) {
                return;
            }
            alert("target_widgets.on_select(" + item + ")");
            var args = new Array();
            args[0] = "widgetCode";
            args[1] = item;
            device.standardService.SetActionListener("getWidget", get_widget_callback2, true);
            device.standardService.CallAction("getWidget", args);
        }
        target_widgets.register(root);
    }
}

function get_widget_callback2() {
    // msgHandler is the first argument, the next arguments are from the reply to listWidgets
    alert("callback2-1");
    var act = arguments[0];
    var act1 = act.GetArgumentValue("widgetUrl");
    var act2 = act.GetArgumentValue("widgetContext");
    alert("callback2-2 " + act1 + " " + act2);
    var wid = WidgetManager.load(act1, null, act2);
    WidgetManager.on_widget_add(wid);
}

//
// creates the menu of available targets for pushing a widget elsewhere
//
function selector_window1() {
    var i, count, render;
    var selector = document.createElement('g'), obj, child;
    selector.setAttribute('transform', 'translate(10,10)');
    count = WidgetManager.MPEGUStandardServiceProviders.length;
    selector.appendChild(rect(0, 0, 300, 20 * (count + 1), 'white', 'black', null));
    for (i = 0; i < count; i++) {
        render = WidgetManager.MPEGUStandardServiceProviders[i];
        obj = createtext(render.Name, 'black', 5, 17 + (20 * i), 15, 'sans-serif');
        obj.setAttribute('id', "select" + i);
        selector.appendChild(obj);
        obj.addEventListener('mouseover', sw1("select" + i), false);
        obj.addEventListener('mouseout', sw2("select" + i), false);
        obj.addEventListener('click', sw4(i), false);
    }
    obj = createtext('Cancel', 'rgb(0,0,120)', 55, 17 + (20 * i), 15, 'sans-serif');
    obj.setAttribute('id', "canc");
    selector.appendChild(obj);
    obj.addEventListener('mouseover', function() { document.getElementById("canc").setAttribute("fill", "red"); }, false);
    obj.addEventListener('mouseout', function() { document.getElementById("canc").setAttribute("fill", "black"); }, false);
    obj.addEventListener('click', function() { upnp_renders.on_select(-1); }, false);
    selector.register = function(disp) {
        disp.appendChild(this);
    };
    selector.unregister = function(disp) {
        disp.removeChild(this);
    };
    return selector;
}

//
// creates the menu of available targets for pushing a widget elsewhere
//
function selector_window2(codes, names) {
    alert("selector_window2");
    var i, count, render;
    var selector = document.createElement('g'), obj, child;
    selector.setAttribute('transform', 'translate(10,10)');
    count = codes.length;
    selector.appendChild(rect(0, 0, 300, 20 * (count + 1), 'white', 'black', null));
    for (i = 0; i < count; i++) {
        render = names[i];
        obj = createtext(render, 'black', 5, 17 + (20 * i), 15, 'sans-serif');
        obj.setAttribute('id', "selecto" + i);
        selector.appendChild(obj);
        obj.addEventListener('mouseover', sw1("selecto" + i), false);
        obj.addEventListener('mouseout', sw2("selecto" + i), false);
        obj.addEventListener('click', sw5(i), false);
    }
    obj = createtext('Cancel', 'rgb(0,0,120)', 55, 17 + (20 * i), 15, 'sans-serif');
    obj.setAttribute('id', "cance");
    selector.appendChild(obj);
    obj.addEventListener('mouseover', function() { document.getElementById("cance").setAttribute("fill", "red"); }, false);
    obj.addEventListener('mouseout', function() { document.getElementById("cance").setAttribute("fill", "black"); }, false);
    obj.addEventListener('click', function() { target_widgets.on_select(-1); }, false);
    selector.register = function(disp) {
        disp.appendChild(this);
    };
    selector.unregister = function(disp) {
        disp.removeChild(this);
    };
    return selector;
}

function sw4(si) {
    return function() { upnp_renders.on_select(si); };
}

function sw5(si) {
    return function() { target_widgets.on_select(si); };
}

//
// when deleting an executing widgets, all executing widgets to its right are moved to the left
//
function recurseMoveAfterDelete(target) {
    if (target != null && target.nextElementSibling != null) {
        var v = target.nextElementSibling;
        recurseMoveAfterDelete(v);
        v.setAttribute("transform", target.getAttribute("transform"));
    }
}

//
// click on home button to switch from icons to executing widgets
//
function home_button(evt) {
    if (l_deb < log_level) {
        alert("[UI] home_button");
    }
    if (state != 'home') {
        state = 'home';
        widgetContainer.setAttribute('display', 'none');
        homepage.setAttribute('display', 'inline');
        homebar.setAttribute('display', 'inline');
        execbar.setAttribute('display', 'none');
        arrows.setAttribute('display', 'inline');
        arrowsW.setAttribute('display', 'none');
        widgetAddList.setAttribute('display', 'none');
    } else {
        state = 'exec';
        widgetContainer.setAttribute('display', 'inline');
        homepage.setAttribute('display', 'none');
        homebar.setAttribute('display', 'none');
        execbar.setAttribute('display', 'inline');
        arrows.setAttribute('display', 'none');
        arrowsW.setAttribute('display', 'inline');
        widgetAddList.setAttribute('display', 'none');
    }
}

// constants
var adjustFrom = "0,0";
var animDue = true;

//
// after each change of icon page, this function adjusts the visibility of arrows in the lower bar
//
function adjustwhere(animDue) {
    if (l_deb < log_level) {
        alert("[UI] adjust " + where + " 0 " + maxwhere);
    }
    document.getElementById("left").setAttribute("display", ((where > 0) ? "inline" : "none"));
    document.getElementById("right").setAttribute("display", ((where < maxwhere) ? "inline" : "none"));
    if (!animDue) {
        icons.setAttribute("transform", 'translate(' + (-80 * iconNbHoriz * where) + ',0)');
    } else {
        var aw = document.createElement("animateTransform");
        aw.setAttribute("attributeName", "transform");
        aw.setAttribute("type", "translate");
        //alert('time '+document.documentElement.getCurrentTime());
        aw.setAttribute("begin", document.documentElement.getCurrentTime());
        aw.setAttribute("dur", "1s");
        aw.setAttribute("fill", "freeze");
        aw.setAttributeNS(xlinkns, "href", "#icons");
        aw.setAttribute("from", adjustFrom);
        aw.setAttribute("to", (-80 * iconNbHoriz * where) + ",0");
        document.documentElement.appendChild(aw);
    }
    adjustFrom = (-80 * iconNbHoriz * where) + ",0";
}

//
// action of the left button on the lower bar
//
function left_button() {
    if (l_deb < log_level) {
        alert("[UI] left button " + where + " 0");
    }
    if (where > 0) {
        where--;
        adjustwhere(true);
    }
}

//
// action of the right button of the lower bar
//
function right_button() {
    if (l_deb < log_level) {
        alert("[UI] right button " + where + " " + maxwhere);
    }
    if (where < maxwhere) {
        where++;
        adjustwhere(true);
    }
}

var adjustFromW = "0,0";
var oldwhereW = -1;

//
// after each change of icon page, this function adjusts the visibility of arrows in the lower bar
//
function adjustWhereWidgets(animDue) {
    if (oldwhereW != whereW) {
        // hide oldwhereW
        if (oldwhereW >= 0 && activatedWidgets[oldwhereW] != null) {
            WidgetManager.corein_message(activatedWidgets[oldwhereW], "hide");
        }
    }
    if (l_deb < log_level) {
        alert("[UI] adjustW " + whereW + " 0 " + (numActivatedWidgets - 1));
    }
    document.getElementById("leftW").setAttribute("display", ((whereW > 0) ? "inline" : "none"));
    document.getElementById("rightW").setAttribute("display", ((whereW < (numActivatedWidgets - 1)) ? "inline" : "none"));
    if (!animDue) {
        widgetContainer.setAttribute("transform", "translate(" + (-totalWidth * whereW) + ",0)");
    } else {
        var aw = document.createElement("animateTransform");
        aw.setAttribute("attributeName", "transform");
        aw.setAttribute("type", "translate");
        aw.setAttribute("begin", document.documentElement.getCurrentTime());
        aw.setAttribute("dur", "1s");
        aw.setAttribute("fill", "freeze");
        aw.setAttributeNS(xlinkns, "href", "#widget");
        aw.setAttribute("from", adjustFromW);
        aw.setAttribute("to", (-totalWidth * whereW) + ",0");
        document.documentElement.appendChild(aw);
    }
    adjustFromW = (-totalWidth * whereW) + ",0";
    document.getElementById("widgetName").textContent =
            (whereW >= 0 && activatedWidgets[whereW] != null ? activatedWidgets[whereW].shortName : '-');
    if (oldwhereW != whereW) {
        // show whereW
        if (whereW >= 0 && activatedWidgets[whereW] != null) {
            WidgetManager.corein_message(activatedWidgets[whereW], "show");
        }
        oldwhereW = whereW;
    }
}

//
// action of the left button on the lower bar
//
function left_buttonW() {
    if (l_deb < log_level) {
        alert("[UI] left button " + whereW);
    }
    if (whereW > 0) {
        whereW--;
        adjustWhereWidgets(animDue);
    }
}

//
// action of the right button of the lower bar
//
function right_buttonW() {
    if (l_deb < log_level) {
        alert("[UI] right button " + whereW + " " + (numActivatedWidgets - 1));
    }
    if (whereW < (numActivatedWidgets - 1)) {
        whereW++;
        adjustWhereWidgets(animDue);
    }
}

//
// action of each icon, starting the matching widget
//
function activating_widget(w) {
    if (l_deb < log_level) {
        alert("[UI] activating widget: " + w.name);
    }
    widget_add(w);
}

//
// main initialization function
// init variables, then init the widget manager C code, then inits UPnP
//
function initialize() {
    if (l_deb < log_level) {
        alert("[UI] initialize");
    }
    init = false;
    var display_width = parseInt(scene.get_option('Widgets', 'LastWMWidth'));
    var display_height = parseInt(scene.get_option('Widgets', 'LastWMHeight'));
    if (display_width && display_height) {
        scene.set_size(display_width, display_height);
    }
    root = document.documentElement;
    homepage = document.getElementById('homepage');
    homebar = document.getElementById('homebar');
    execbar = document.getElementById('execbar');
    arrows = document.getElementById('arrows');
    arrowsW = document.getElementById('arrowsW');
    icons = document.getElementById('icons');
    widgetContainer = document.getElementById('widget');
    widgetAddList = document.getElementById('widgetAddList');
    /* Setup the GPAC Widget Manager - this will also scan the available widgets */
    log_level = l_inf;
    widget_manager_init();
    WidgetManager.on_widget_remove = widget_remove;
    WidgetManager.on_widget_add = widget_add;
    /* register the callback to be notified of incoming widgets */
    has_upnp = (typeof UPnP != 'undefined');
    if (has_upnp) {
        /* setting the callback to allow other devices to push their widgets */
        UPnP.onMediaConnect = onMediaConnect;
        /* Tell GPAC that the calls to the main Renderer (like open, ...) must be forwared to this scene */
        UPnP.BindRenderer();
    }
    WidgetManager.coreOutShow = coreOutShowImplementation;
    WidgetManager.coreOutGetAttention = coreOutGetAttentionImplementation;
    WidgetManager.coreOutHide = coreOutHideImplementation;
    WidgetManager.coreOutRequestDeactivate = coreOutRequestDeactivateImplementation;
    WidgetManager.coreOutInstallWidget = coreOutInstallWidgetImplementation;
    WidgetManager.coreOutActivateTemporaryWidget = coreOutActivateTemporaryWidgetImplementation;
    WidgetManager.coreOutMigrateComponent = coreOutMigrateComponentImplementation;
    WidgetManager.coreOutRequestMigrationTargets = coreOutRequestMigrationTargetsImplementation;
}

//
// implementation of core:out install widget
//
function coreOutInstallWidgetImplementation(wid, args) {
    var w = widgetInstall(args[0], true, false, wid);
    var ifce = getInterfaceByType(wid, "urn:mpeg:mpegu:schema:widgets:core:out:2010");
    if (ifce != null) {
        wmjs_core_out_invoke_reply(coreOut.installWidgetMessage, ifce.get_message("installWidget"),
                wid, (w != null ? 1 : 0)); // send return code 1 = success
    }
}

//
// implementation of core:out activate temporary widget
//
function coreOutActivateTemporaryWidgetImplementation(wid, args) {
    var w = widgetInstall(args[0], true, true, null);
    if (w != null) {
        activating_widget(w);
    }
    var ifce = getInterfaceByType(wid, "urn:mpeg:mpegu:schema:widgets:core:out:2010");
    if (ifce != null) {
        wmjs_core_out_invoke_reply(coreOut.activateTemporaryWidgetMessage, ifce.get_message("activateTemporaryWidget"),
                wid, (w != null ? 1 : 0)); // send return code 1 = success
    }
}

//
// implementation of core:out migrate component
//
function coreOutMigrateComponentImplementation(wid, args) {
    //alert("coreOutMigrateComponent "+wid.name+" "+args.length);
    var comp = wid.get_component(args[0], true);
    var ifce = getInterfaceByType(wid, "urn:mpeg:mpegu:schema:widgets:core:out:2010");
    if (comp == null) {
        log(l_err, 'Component ' + args[0] + ' cannot be found in widget ' + wid.name);
        if (ifce != null) {
            wmjs_core_out_invoke_reply(coreOut.migrateComponentMessage, ifce.get_message("migrateComponent"), wid, 0);
        }
        return;
    }
    if (args.length > 1 && args[1] != null) {
        //WidgetManager.migrate_widget(UPnP.GetMediaRenderer(parseInt(args[1])), comp);
        WidgetManager.migrate_widget(WidgetManager.get_mpegu_service_providers(parseInt(args[1])), comp);
        widget_close(comp);
    } else {
        upnp_renders = selector_window(comp);
        upnp_renders.on_select = function(item, wid) {
            upnp_renders.unregister(root);
            upnp_renders = null;
            if (item == -1) {
                return;
            }
            if (comp != null) {
                alert("upnp_renders.on_select(" + item + "," + comp.name + ")");
                //WidgetManager.migrate_widget(UPnP.GetMediaRenderer(item), comp);
                WidgetManager.migrate_widget(WidgetManager.get_mpegu_service_providers(item), comp);
                widget_close(comp);
            }
        };
        upnp_renders.register(root);
    }
    if (ifce != null) {
        wmjs_core_out_invoke_reply(coreOut.migrateComponentMessage, ifce.get_message("migrateComponent"), wid, 1); // send return code 1 = success
    }
}

//
// implementation of core:out request migration targets
//
function coreOutRequestMigrationTargetsImplementation(wid, args) {
    var count = UPnP.MediaRenderersCount, codes = new Array(), names = new Array(), descriptions = new Array(), i;
    for (i = 0; i < count; i++) {
        var render = UPnP.GetMediaRenderer(i);
        codes.push("" + i);
        names.push(render.Name);
        descriptions.push(render.HostName + " " + render.UUID);
    }
    i = null;
    var ifce_count = wid.num_interfaces, j;
    for (j = 0; j < ifce_count; j++) {
        var ifce = wid.get_interface(j);
        if (ifce.type == "urn:mpeg:mpegu:schema:widgets:core:out:2010") {
            i = ifce;
            break;
        }
    }
    if (i != null) {
        wmjs_core_out_invoke_reply(coreOut.requestMigrationTargetsMessage, i.get_message("requestMigrationTargets"),
                wid, codes, names, descriptions);
    }
}

//
// implementation of core:out Show message
// this is a request by the widget to be shown
//
function coreOutShowImplementation(wid, args) {
    //alert("core:out show "+wid.name);
    var target = widgetContainer.firstElementChild;
    var i;
    for (i = 0; i < numActivatedWidgets; i++) {
        //alert("is it "+activatedWidgets[i].name);
        if (activatedWidgets[i] == wid) {
            break;
        }
        target = target.nextElementSibling;
    }
    // here, i is the index of the current widget
    //alert(" "+i+" "+numActivatedWidgets);
    if (i < numActivatedWidgets) {
        whereW = i;
        adjustWhereWidgets(false);
    }
    var ifce = getInterfaceByType(wid, "urn:mpeg:mpegu:schema:widgets:core:out:2010");
    if (ifce != null) {
        wmjs_core_out_invoke_reply(coreOut.showMessage, ifce.get_message("show"), wid, 1); // send return code 1 = success
    }
}

//
// implementation of core:out GetAttention message
// this is a request by the widget to be shown and some special signal is given
//
function coreOutGetAttentionImplementation(wid, args) {
    //alert("core:out getAttention "+wid.name);
    var target = widgetContainer.firstElementChild;
    var i;
    for (i = 0; i < numActivatedWidgets; i++) {
        //alert("is it "+activatedWidgets[i].name);
        if (activatedWidgets[i] == wid) {
            break;
        }
        target = target.nextElementSibling;
    }
    // here, i is the index of the current widget
    //alert(" "+i+" "+numActivatedWidgets);
    if (i < numActivatedWidgets) {
        whereW = i;
        adjustWhereWidgets(false);
    }
    document.getElementById("getAttention").beginElement();
    var ifce = getInterfaceByType(wid, "urn:mpeg:mpegu:schema:widgets:core:out:2010");
    if (ifce != null) {
        wmjs_core_out_invoke_reply(coreOut.getAttentionMessage, ifce.get_message("getAttention"), wid, 1); // send return code 1 = success
    }
}

//
// implementation of core:out hide message
// this is a request by the widget to be hidden (some other widget (if any) is shown)
//
function coreOutHideImplementation(wid, args) {
    //alert("core:out hide "+wid.name);
    var target = widgetContainer.firstElementChild;
    var i;
    for (i = 0; i < numActivatedWidgets; i++) {
        //alert("is it "+activatedWidgets[i].name);
        if (activatedWidgets[i] == wid) {
            break;
        }
        target = target.nextElementSibling;
    }
    // here, i is the index of the current widget
    //alert("hide "+i+" "+numActivatedWidgets);
    if (i < numActivatedWidgets) {
        if (whereW > 0) {
            whereW--;
        }
        else if (whereW < numActivatedWidgets - 1) {
            whereW++;
        }
        else {
            return;
        }
        adjustWhereWidgets(false);
    }
    var ifce = getInterfaceByType(wid, "urn:mpeg:mpegu:schema:widgets:core:out:2010");
    if (ifce != null) {
        wmjs_core_out_invoke_reply(coreOut.hideMessage, ifce.get_message("hide"), wid, 1); // send return code 1 = success
    }
}

//
// implementation of core:out requestDeactivate message
// this is a request by the widget to be stopped
//
function coreOutRequestDeactivateImplementation(wid, args) {
    //alert("core:out hide "+wid.name);
    var target = widgetContainer.firstElementChild;
    var i;
    for (i = 0; i < numActivatedWidgets; i++) {
        //alert("is it "+activatedWidgets[i].name);
        if (activatedWidgets[i] == wid) {
            break;
        }
        target = target.nextElementSibling;
    }
    // here, i is the index of the current widget
    //alert("hide "+i+" "+numActivatedWidgets);
    if (i < numActivatedWidgets) {
        widget_close(activatedWidgets[i]);
    }
    var ifce = getInterfaceByType(wid, "urn:mpeg:mpegu:schema:widgets:core:out:2010");
    if (ifce != null) {
        wmjs_core_out_invoke_reply(coreOut.requestDeactivateMessage, ifce.get_message("requestDeactivate"), wid, 1); // send return code 1 = success
    }
}

//
// WM callback for when a component is activated by its parent
//
function widget_add(w) {
    log(l_inf, "widget add " + w.name);
    if (!w.activated) {
        if (sameFileIgnoringSVGView(w.icon, w.main)) {
            // same file in icon and main
        } else {
            widget_launch(w, document.createElement("animation"));
        }
    } else if (w.multipleInstances) {
        var newwid = WidgetManager.open(w.manifest, null);
        widget_launch(newwid, document.createElement("animation"));
    } else {
        return false;
    }
    state = 'exec';
    widgetContainer.setAttribute('display', 'inline');
    homepage.setAttribute('display', 'none');
    homebar.setAttribute('display', 'none');
    execbar.setAttribute('display', 'inline');
    arrows.setAttribute('display', 'none');
    arrowsW.setAttribute('display', 'inline');
    widgetAddList.setAttribute('display', 'none');
    return true;
}

function sameFileIgnoringSVGView(name1, name2) {
    if (name1 == name2) {
        return true;
    }
    if (name1 == null) {
        return false;
    }
    var i1 = name1.indexOf("#");
    var i2 = name2.indexOf("#");
    if (i1 < 0) {
        i1 = name1.length;
    }
    else {
        i1--;
    }
    if (i2 < 0) {
        i2 = name2.length;
    }
    else {
        i2--;
    }
    return name1.substring(0, i1) == name2.substring(0, i2);
}

//
// recompute the number of widgets loaded currently
//
function getNbWidgets() {
    var i, nbWidgets = 0;
    for (i = 0; i < WidgetManager.num_widgets; i++) {
        var w = WidgetManager.get(i);
        if (w != null && w.loaded) {
            nbWidgets++;
        }
    }
    return nbWidgets;
}

//
// just resize the window and viewport, and initialize the first time this is called
//
function resize() {
    if (init) {
        initialize();
    }
    if (document.documentElement.viewport.width == previousWidth && document.documentElement.viewport.height == previousHeight) {
        return;
    }
    if (l_deb < log_level) {
        alert("[UI] start initialize() w:" + document.documentElement.viewport.width + " h:" + document.documentElement.viewport.height);
    }
    adaptLayoutToSize();
    // start by filling the "home page" with known icons
    where = 0;
    var nbWidgets = getNbWidgets();
    maxwhere = ((nbWidgets - 1) - ((nbWidgets - 1) % iconsPerPage)) / iconsPerPage;
    var wid;
    var iconIterator = document.getElementById("icons").firstElementChild;
    var position = 0;
    for (i = 1; i <= WidgetManager.num_widgets; i++) {
        wid = WidgetManager.get(i - 1);
        // alert("build:"+wid.main+" "+wid.loaded);
        if (wid.loaded) {
            insert_icon(wid, position, i - 1, iconIterator);
            WidgetManager.corein_message(wid, 'setSize', 'width', totalWidth, 'height', totalHeight - 120, 'dpi', 96);
            position++;
            if (iconIterator != null) {
                iconIterator = iconIterator.nextElementSibling;
            }
        }
    }
    adjustwhere(false);
    adjustWhereWidgets(false);
    previousWidth = document.documentElement.viewport.width;
    previousHeight = document.documentElement.viewport.height;
    scene.set_option("Widgets", "LastWMWidth", '' + previousWidth);
    scene.set_option("Widgets", "LastWMHeight", '' + previousHeight);
}

//
// function inserting an icon on the home page
//
function insert_icon(widget, position, widgetIndex, previousIcon) {
    if (l_deb < log_level) {
        alert("[UI] insert_icon: " + widget.shortName + " " + position + " " + widgetIndex + " WMnw:" + WidgetManager.num_widgets);
    }
    widget.loaded = true;
    if (l_deb < log_level) {
        alert("[UI] widget name: " + widget.name);
    }
    var icon = null, original = null;
    for (var i = 0; i < widget.icons.length; i++) {
        // default to the first icon even if not of the preferred type
        if (i == 0) {
            icon = widget.icons[0].relocated_src;
            //original = widget.icons[0].original;
            // alert("choosing default icon " + icon);
        }
        // check for preferred type
        if (widget.icons[i].relocated_src.indexOf(preferredIconType) > 0) {
            icon = widget.icons[i].relocated_src;
            //original = widget.icons[i].original;
            break;
        }
    }
    var shortName = widget.shortName;
    if (typeof shortName == 'undefined') {
        shortName = widget.name.substring(0, 9);
    }
    createIconSVGdecoration(previousIcon, widget, (((position % iconNbHoriz) * 80) + ((80 * (position - (position % iconsPerPage))) / iconNbVert)),
            ((((position % iconsPerPage) - (position % iconNbHoriz)) / iconNbHoriz) * 80), "icons", icon,
            shortName, widgetIndex);
}

// constant
// const corein = "urn:mpeg:mpegu:schema:widgets:core:in:2010";

//
// commodity method to empty a list of children
//
function removeAllChildren(o) {
    if (o != null && o.hasChildNodes()) {
        while (o.childNodes.length >= 1) {
            o.removeChild(o.firstChild);
        }
    }
}

//
// create the home page icon with all its behaviors
//
function createIconSVGdecoration(previousIcon, widget, x, y, fatherId, iconUrl, name, widIndex) {
    var g, g2;
    if (l_inf < log_level) {
        alert("[UI] createIconSVGdecoration " + iconUrl + " " + x + " " + y);
    }
    if (previousIcon != null) {
        g = previousIcon;
    } else {
        g = document.createElement("g");
        document.getElementById(fatherId).appendChild(g);
    }
    g.setAttribute("transform", 'translate(' + x + ',' + y + ')');
    if (previousIcon != null) {
        g2 = g.firstElementChild;
    } else {
        g2 = document.createElement("g");
        g2.setAttribute("transform", 'translate(15,10)');
        g.appendChild(g2);
    }
    if (iconUrl == null || iconUrl == "") {
        iconUrl = "icons/face-surprise.svg";
    }
    //
    // process differently cases where widget.icon == widget.main
    //
    var container;
    if (sameFileIgnoringSVGView(iconUrl, widget.main) && widget.main.indexOf('.svg') >= 0) {
        // see if the animation already exists
        container = document.getElementById(name);
        if (container == null) {
            // if the animation does not exist yet, create it
            container = media('animation', iconUrl, 50, 50);
            // store the animation in the main defs
            document.getElementById("mainDefs").appendChild(container);
            container.setAttribute('id', name);
        }
        if (previousIcon == null) {
            // put the container in a use
            var use = document.createElement("use");
            use.setAttribute('id', 'iconContainer' + name);
            use.setAttributeNS(xlinkns, 'href', '#' + name);
            g2.appendChild(use);
        }
    } else {
        if (previousIcon == null) {
            container = appropriateElementForMedia(iconUrl, 50, 50);
            container.setAttribute('id', name);
            g2.appendChild(container);
        }
    }
    if (previousIcon == null) {
        g2 = document.createElement("g");
        g2.setAttribute("transform", 'translate(40,70)');
        g.appendChild(g2);
        var anim = createtext(name, 'white', 0, 0, 14, 'Arial Unicode MS');
        anim.setAttribute("text-anchor", "middle");
        anim.setAttribute("display-align", "center");
        g2.appendChild(anim);
        var rect = invisible_rect(80, 80);
        g.appendChild(rect);
        rect.addEventListener("click", csi(widget), false);
    }
}

function csi(widget) {
    return function(evt) { activating_widget(widget);};
}

//
// widget closing action (WM callback)
//
function widget_close(wid) {
    if (wid == null) {
        return;
    }
    if (l_inf <= log_level) {
        alert('[UI] widget_close:' + wid.name);
    }
    // maybe inform the widget that it is going to be deactivated
    WidgetManager.corein_message(wid, "deactivate");
    var target = widgetContainer.firstElementChild;
    var i;
    for (i = 0; i < numActivatedWidgets; i++) {
        if (activatedWidgets[i] == wid) {
            break;
        }
        target = target.nextElementSibling;
    }
    if (target != null) {
        // move next widgets back one slot
        recurseMoveAfterDelete(target);
        // stop the subscene
        if (target.firstElementChild != null) {
            target.firstElementChild.setAttributeNS(xlinkns, "href", "");
        }
        // end trying
        widgetContainer.removeChild(target);
    }
    wid.deactivate();
    wid.activated = false;
    activatedWidgets.splice(i, 1);
    numActivatedWidgets--;
    whereW = (whereW >= i ? (whereW > 0 ? whereW - 1 : 0) : whereW);
    adjustWhereWidgets(false);
    // if no more widgets, go back to the icons
    if (numActivatedWidgets == 0) {
        state = 'home';
        widgetContainer.setAttribute('display', 'none');
        homepage.setAttribute('display', 'inline');
        homebar.setAttribute('display', 'inline');
        execbar.setAttribute('display', 'none');
        arrows.setAttribute('display', 'inline');
        arrowsW.setAttribute('display', 'none');
        widgetAddList.setAttribute('display', 'none');
    }
    if (!wid.permanent) {
        WidgetManager.unload(wid, false);
    }
}

//
// widget unloading action (WM callback)
//
function widget_remove(wid) {
    if (l_deb <= log_level) {
        alert('[UI] widget_remove:' + wid.name);
    }
    widget_close(wid);
    WidgetManager.unload(wid, false);
}

//
// widget launcher action
//
function widget_launch(wid, scene_container) {
    if (l_inf <= log_level) {
        alert('[UI] widget_launch:' + wid.name);
    }
    var tmp = document.createElement("g");
    tmp.setAttribute("transform", "translate(" + (totalWidth * numActivatedWidgets) + ", 0)");
    widgetContainer.appendChild(tmp);
    var icon = null;
    alert("wid: " + wid.name + "|" + wid.shortName);
    if (typeof wid.shortName != 'undefined') {
        var container = document.getElementById(wid.shortName);
        if (container != null) {
            icon = container.getAttributeNS(xlinkns, 'href');
        }
    }
    if (icon != null &&
            sameFileIgnoringSVGView(icon, wid.main) &&
            endsWith(wid.main, '.svg')) {
        // get the animation with id=shortName stored in mainDefs
        scene_container = document.getElementById(wid.shortName);
        // get the original use on it, used in the icon
        var iconContainer = document.getElementById('iconContainer' + wid.shortName);
        // create a new use
        var use = document.createElement('use');
        // point to the animation
        use.setAttributeNS(xlinkns, 'href', '#' + wid.shortName);
        // resize the animation
        scene_container.setAttribute("width", totalWidth);
        scene_container.setAttribute("height", totalHeight - 120);
        // resize the original use
        //should do: fix the aspect ratio conservation
        var m, t = Math.abs(totalHeight - 120 - totalWidth) / 2;
        if (totalWidth > totalHeight - 120) {
            m = 50 / (totalHeight - 120);
            iconContainer.setAttribute('transform', 'scale(' + m + ',' + m + ') translate(' + (-t) + ',0)');
        } else {
            m = 50 / totalWidth;
            iconContainer.setAttribute('transform', 'scale(' + m + ',' + m + ') translate(0,' + (-t) + ') ');
        }
        // add the new use as widget execution container
        tmp.appendChild(use);
        wid.activate(scene_container);
    } else {
        scene_container.setAttribute("width", totalWidth);
        scene_container.setAttribute("height", totalHeight - 120);
        tmp.appendChild(scene_container);
        scene_container.setAttributeNS(xlinkns, 'href', wid.main);
        wid.activate(scene_container);
    }
    wid.activated = true;
    activatedWidgets.splice(numActivatedWidgets, 0, wid);
    whereW = numActivatedWidgets;
    numActivatedWidgets++;
    adjustWhereWidgets(false);
    wid.load_component = widget_load_component;
    wid.permanent = true;
    wid.on_load = function () {
        WidgetManager.corein_message(this, 'setSize', 'width', totalWidth, 'height', totalHeight - 120, 'dpi', 96);
    };
    //
    if (log_level > l_inf) {
        var i = 0;
        alert(">>>>>>>>>>>>> " + wid.name + " interfaces:");
        for (; i < wid.num_interfaces; i++) {
            alert("" + wid.get_interface(i).type);
        }
    }
    //
}

//
// widget load component (WM callback)
//
function widget_load_component(comp, is_unload) {
    if (l_deb <= log_level) {
        alert('[UI] widget_load_component:' + comp.name);
    }
    if (is_unload) {
        widget_close(comp);
        comp.parent = null;
    } else {
        widget_add(comp);
        comp.permanent = false;
        comp.parent = this;
    }
}

var upnp_renders = null, target_widgets = null;

//
// widget remoting function
//
function on_widget_remote() {
    if (WidgetManager.MPEGUStandardServiceProviders.length != 0 && numActivatedWidgets > 0) {
        upnp_renders = selector_window(activatedWidgets[whereW]);
        upnp_renders.on_select = function(item, wid) {
            upnp_renders.unregister(root);
            upnp_renders = null;
            if (item == -1) {
                return;
            }
            if (wid != null) {
                alert("upnp_renders.on_select(" + item + "," + wid.name + ")");
                //WidgetManager.migrate_widget(UPnP.GetMediaRenderer(item), wid);
                WidgetManager.migrate_widget(WidgetManager.get_mpegu_service_providers(item), wid);
                widget_close(wid);
            }
        };
        upnp_renders.register(root);
    }
}

//
// creates the menu of available targets for pushing a widget elsewhere
//
function selector_window(widget) {
    var i, count, render;
    var selector = document.createElement('g'), obj, child;
    selector.setAttribute('transform', 'translate(10,10)');
    count = WidgetManager.MPEGUStandardServiceProviders.length;
    selector.appendChild(rect(0, 0, 300, 20 * (count + 1), 'white', 'black'));
    for (i = 0; i < count; i++) {
        render = WidgetManager.MPEGUStandardServiceProviders[i];
        obj = createtext(render.Name, 'black', 5, 17 + (20 * i), 15, 'sans-serif');
        obj.setAttribute('id', "selector" + i);
        selector.appendChild(obj);
        obj.addEventListener('mouseover', sw1("selector" + i), false);
        obj.addEventListener('mouseout', sw2("selector" + i), false);
        obj.addEventListener('click', sw3(i, widget), false);
    }
    obj = createtext('Cancel', 'rgb(0,0,120)', 55, 17 + (20 * i), 15, 'sans-serif');
    obj.setAttribute('id', "cancel");
    selector.appendChild(obj);
    obj.addEventListener('mouseover', function(evt) { document.getElementById("cancel").setAttribute("fill", "red"); }, false);
    obj.addEventListener('mouseout', function(evt) { document.getElementById("cancel").setAttribute("fill", "black"); }, false);
    obj.addEventListener('click', function(evt) { upnp_renders.on_select(-1, null); }, false);
    selector.register = function(disp) {
        disp.appendChild(this);
    };
    selector.unregister = function(disp) {
        disp.removeChild(this);
    };
    return selector;
}

function sw1(s) {
    return function(evt) { document.getElementById(s).setAttribute("fill", "blue"); };
}

function sw2(s) {
    return function(evt) { document.getElementById(s).setAttribute("fill", "black"); };
}

function sw3(si, widget) {
    return function(evt) { upnp_renders.on_select(si, widget); };
}

//
// when a widget is pushed to here, install the widget and execute it
//
function onMediaConnect(url, src_ip) {
    if (l_inf <= log_level) {
        alert('[UI] onMediaConnect :\"' + url + '\"');
    }
    if (WidgetManager.probe(url)) {
        var w = WidgetManager.open(url, src_ip);
        if (w == null) {
            return;
        }
        widget_add(w);
        adjustWhereWidgets(false);
        w.permanent = false;
    }
}

//
// file list vars
//
var flstart = 0,fllist = null,maxFileNames = 14;

//
// create a file menu in the main screen, allowing to navigate directories and choose widget config files
//
function on_widget_add_menu() {
    state = 'list';
    widgetContainer.setAttribute('display', 'none');
    homepage.setAttribute('display', 'none');
    homebar.setAttribute('display', 'none');
    execbar.setAttribute('display', 'inline');
    arrows.setAttribute('display', 'none');
    arrowsW.setAttribute('display', 'none');
    widgetAddList.setAttribute('display', 'inline');
    maxFileNames = Math.round(((iconNbVert * 80) / 25) - 1.4);
    isThisAScan = false;
    refillWidgetAddList(false);
}

//
// create a file menu in the main screen, allowing to navigate directories and choose a directory to scan for widgets
// and load all their icons
//
function on_dir_scan() {
    state = 'list';
    widgetContainer.setAttribute('display', 'none');
    homepage.setAttribute('display', 'none');
    homebar.setAttribute('display', 'none');
    execbar.setAttribute('display', 'inline');
    arrows.setAttribute('display', 'none');
    arrowsW.setAttribute('display', 'none');
    widgetAddList.setAttribute('display', 'inline');
    maxFileNames = Math.round(((iconNbVert * 80) / 25) - 1.4);
    isThisAScan = true;
    refillWidgetAddList(true);
}

//
// remove all installed icons
//
function on_clean_up() {
    var i;
    //if (l_inf <= log_level) alert('[UI] unloading ' + WidgetManager.num_widgets + ' widgets');
    for (i = WidgetManager.num_widgets - 1; i >= 0; i--) {
        var w = WidgetManager.get(i);
        if (w.loaded) {
            alert("unloading " + w.name);
            w.loaded = false;
            WidgetManager.unload(w, false);
        }
    }
    where = 0;
    maxwhere = 0;
    removeAllChildren(document.getElementById("icons"));
    adjustwhere(false);
}

//
// install, but do not launch, the widget whose config.xml has been chosen, and return to the home page
//
function widgetInstall(uri, manual, temporary, parent_wid) {
    var wid, j, count = WidgetManager.num_widgets, nbWidgets = getNbWidgets();
    for (j = 0; j < count; j++) {
        wid = WidgetManager.get(j);
        if (wid.url == uri) {
            if (wid.loaded) {
                break;
            }
            if (temporary) {
                wid.permanent = false;
            }
            else {
                insert_icon(wid, nbWidgets, nbWidgets);
            }
        }
    }
    if (j == count) {
        wid = WidgetManager.open(uri, null, parent_wid);
        if (wid != null) {
            if (temporary) {
                wid.permanent = false;
            }
            else {
                insert_icon(wid, nbWidgets, nbWidgets);
            }
        }
    }
    if (manual) {
        return wid;
    }
    state = 'home';
    widgetContainer.setAttribute('display', 'none');
    homepage.setAttribute('display', 'inline');
    homebar.setAttribute('display', 'inline');
    execbar.setAttribute('display', 'none');
    arrows.setAttribute('display', 'inline');
    arrowsW.setAttribute('display', 'none');
    removeAllChildren(widgetAddList);
    maxwhere = ((nbWidgets - 1) - ((nbWidgets - 1) % iconsPerPage)) / iconsPerPage;
    where = maxwhere;
    adjustwhere(false);
    return wid;
}

//
// clean up file list space and refill it
//
function refillWidgetAddList(flag) {
    removeAllChildren(widgetAddList);
    fllist = null;
    flstart = 0;
    fllist = Sys.enum_directory(Sys.last_wdir, "", false);
    fillWidgetAddList(flag);
}

//
// go to parent directory
//
function flUpDir(evt) {
    var s = Sys.last_wdir;
    if (l_inf <= log_level) {
        alert("[UI] lwd:" + Sys.last_wdir);
    }
    var index = s.lastIndexOf("\\");
    if (index != -1) {
        Sys.last_wdir = s.substring(0, index);
        refillWidgetAddList(isThisAScan);
    } else {
        index = s.lastIndexOf("/");
        if (index != -1) {
            Sys.last_wdir = s.substring(0, index);
            refillWidgetAddList(isThisAScan);
        } else {
            Sys.last_wdir = "/";
            refillWidgetAddList(isThisAScan);
        }
    }
}

//
// go to a named directory
//
function flGoTo(newDir) {
    //alert("goto "+newDir);
    var s = Sys.last_wdir;
    if (s == "/") {
        Sys.last_wdir = newDir;
    } else {
        var c = s.charAt(s.length - 1);
        if (c != '\\' && c != '/') {
            s += "/";
        }
        Sys.last_wdir = s + newDir;
    }
    //alert(Sys.last_wdir);
    refillWidgetAddList(isThisAScan);
}

//
// if the directory contains more files that can be shown, show previous page of file names
//
function flPrevFiles(evt) {
    if (flstart == 0) {
        return;
    }
    flstart -= maxFileNames;
    if (flstart < 0) {
        flstart = 0;
    }
    removeAllChildren(widgetAddList);
    fillWidgetAddList(isThisAScan);
}

//
// if the directory contains more files that can be shown, show next page of file names
//
function flNextFiles(evt) {
    if (flstart + maxFileNames < fllist.length) {
        flstart += maxFileNames;
        removeAllChildren(widgetAddList);
        fillWidgetAddList(isThisAScan);
    }
}

//
// scan the current directory recursively for widgets, clean up and return to home page
//
function flScanDir(evt) {
    scan_directory(Sys.last_wdir);
    state = 'home';
    var nbWidgets = getNbWidgets();
    widgetContainer.setAttribute('display', 'none');
    homepage.setAttribute('display', 'inline');
    homebar.setAttribute('display', 'inline');
    execbar.setAttribute('display', 'none');
    arrows.setAttribute('display', 'inline');
    arrowsW.setAttribute('display', 'none');
    removeAllChildren(widgetAddList);
    maxwhere = ((nbWidgets - 1) - ((nbWidgets - 1) % iconsPerPage)) / iconsPerPage;
    where = maxwhere;
    adjustwhere(false);
}

//
// scanning
//
function scan_directory(dir) {
    var ii, j, count, list, w, uri, loadedWidgets = 0;
    list = Sys.enum_directory(dir, '.xml;.wgt', 0);
    for (ii = 0; ii < list.length; ii++) {
        uri = list[ii].path + list[ii].name;
        if (list[ii].directory) {
            scan_directory(uri);
        } else {
            count = WidgetManager.num_widgets;
            for (j = 0; j < count; j++) {
                var wid = WidgetManager.get(j);
                if (wid.loaded) {
                    loadedWidgets++;
                }
                if (wid.url == uri) {
                    if (wid.loaded) {
                        break;
                    }
                    insert_icon(wid, getNbWidgets(), j);
                    break;
                }
            }
            if (j == count) {
                w = WidgetManager.open(uri, null);
                if (w != null) {
                    insert_icon(w, loadedWidgets, WidgetManager.num_widgets - 1);
                }
            }
        }
    }
}

//
// create the up, prev, next button, show current directory and as many file names as possible
// the file names are active: clicking on a directory name goes to that directory
// clicking on a file tries to load that file as a widget
//
function fillWidgetAddList(flag) {
    if (flag) {
        widgetAddList.appendChild(use("cartoucheflag"));
        document.getElementById("dirflag").textContent = Sys.last_wdir;
    } else {
        widgetAddList.appendChild(use("cartouche"));
        document.getElementById("dir").textContent = Sys.last_wdir;
    }
    // next lines are file names
    var obj;
    for (i = 0; i < (fllist.length - flstart) && i < maxFileNames; i++) {
        obj = use("fileMenuElement" + i);
        obj.setAttribute('transform', 'translate(0,' + (25 * (i + 1)) + ')');
        widgetAddList.appendChild(obj);
        document.getElementById("fileMenuElement" + i + "u").setAttributeNS(xlinkns, 'href', "#" + (fllist[i + flstart].directory ? 'folder' : 'new'));
        document.getElementById("fileMenuElement" + i + "t").textContent = fllist[i + flstart].name;
        if (obj.listener != null) {
            obj.removeEventListener("click", obj.listener);
        }
        if (fllist[i + flstart].directory) {
            obj.listener = createGoto(escaping(fllist[i + flstart].name));
            obj.addEventListener("click", obj.listener, false);
        } else if (isWidgetFileName(fllist[i + flstart].name)) {
            obj.listener = createWidgetInstall(escaping(Sys.last_wdir + '/' + fllist[i + flstart].name));
            obj.addEventListener("click", obj.listener, false);
        }
    }
}

function createGoto(s) {
    return function () {
        flGoTo(s);
    };
}

function createWidgetInstall(s) {
    return function () {
        widgetInstall(s, false, false, null);
    };
}

// // // // // // // // // // // // // // //
// function library
// // // // // // // // // // // // // // //

function isWidgetFileName(s) {
    if (endsWith(s, 'config.xml')) {
        return true;
    }
    if (endsWith(s, '.wgt')) {
        return true;
    }
    return false;
}

//
// replace globally \ with / in a string
//
function escaping(s) {
    s = s.replace(/\\/g, '/');
    return s;
}

//
// create rect
//
function rect(x, y, w, h, fill, stroke, id) {
    var child = document.createElement('rect');
    if (id != null) {
        child.setAttribute('id', id);
    }
    child.setAttribute('x', x);
    child.setAttribute('y', y);
    child.setAttribute('width', w);
    child.setAttribute('height', h);
    child.setAttribute('fill', fill);
    child.setAttribute('stroke', stroke);
    return child;
}

//
// create text
//
function createtext(content, fill, x, y, size, family) {
    var child = document.createElement('text');
    child.setAttribute('fill', fill);
    child.textContent = content;
    child.setAttribute('x', x);
    child.setAttribute('y', y);
    child.setAttribute('font-size', size);
    child.setAttribute('font-family', family);
    return child;
}

//
// create invisible rect getting all events
//
function invisible_rect(w, h) {
    var child = document.createElement('rect');
    child.setAttribute('width', w);
    child.setAttribute('height', h);
    child.setAttribute('fill', 'none');
    child.setAttribute('stroke', 'none');
    child.setAttribute('pointer-events', 'all');
    return child;
}

//
// create animation
//
function media(etype, uri, w, h) {
    var child = document.createElement(etype);
    child.setAttributeNS(xlinkns, 'href', uri);
    child.setAttribute('width', w);
    child.setAttribute('height', h);
    if (etype == 'animation') {
        child.setAttributeNS('https://gpac.io/svg-extensions', 'use-as-primary', 'false');
    }
    return child;
}

//
// create use
//
function use(uri) {
    var child = document.createElement('use');
    child.setAttributeNS(xlinkns, 'href', '#' + uri);
    return child;
}

//
// create appropriate element for media reference by the given uri
//
function appropriateElementForMedia(uri, w, h) {
    if (uri.indexOf('#') != -1) {
        return media('animation', uri, w, h);
    }
    if (endsWith(uri, '.svg')) {
        return media('animation', uri, w, h);
    }
    if (endsWith(uri, '.bt')) {
        return media('animation', uri, w, h);
    }
    if (endsWith(uri, '.png')) {
        return media('image', uri, w, h);
    }
    if (endsWith(uri, '.jpg')) {
        return media('image', uri, w, h);
    }
    if (endsWith(uri, '.gif')) {
        return media('image', uri, w, h);
    }
    if (l_war <= log_level) {
        alert("[UI] WARNING: bad suffix for an icon URI: " + uri);
    }
    return media('image', uri, w, h);
}

//
// substitute for the useful predefined function endsWith
//
function endsWith(s1, s2) {
    return s1.toLowerCase().substring(s1.length - s2.length) == s2;
}

/* wrapper as a module
 // export the resize function as the resize member of iphone_wm_gui, as well as other functions
 return {
 resize: resize,
 left_button: left_button,
 right_button: right_button,
 left_buttonW: left_buttonW,
 right_buttonW: right_buttonW,
 home_button: home_button,
 on_dir_scan: on_dir_scan,
 on_clean_up: on_clean_up,
 on_widget_add_menu: on_widget_add_menu,
 on_kill_widget: on_kill_widget,
 on_get_widget: on_get_widget,
 on_widget_remote: on_widget_remote,
 flUpDir: flUpDir,
 flPrevFiles: flPrevFiles,
 flNextFiles: flNextFiles,
 flScanDir: flScanDir,
 get_widget_callback2: get_widget_callback2
 }

 }());*/

function widget_activated_and_bound(wid) {
    WidgetManager.corein_message(wid, "activate");
}

function printAllFieldsOf(obj, printableName) {
    var details = "fields of " + printableName + ":\n";
    for (var field in obj) {
        fieldContents = obj[field];
        if (typeof(fieldContents) == "function") {
            fieldContents = "(function)";
        }
        details += "  " + field + ": " + fieldContents + "\n";
    }
    alert(details);
}
