<!--
    * Licensed to the Apache Software Foundation (ASF) under one
    * or more contributor license agreements.  See the NOTICE file
    * distributed with this work for additional information
    * regarding copyright ownership.  The ASF licenses this file
    * to you under the Apache License, Version 2.0 (the
    * "License"); you may not use this file except in compliance
    * with the License.  You may obtain a copy of the License at
    * 
    *   http://www.apache.org/licenses/LICENSE-2.0
    * 
    * Unless required by applicable law or agreed to in writing,
    * software distributed under the License is distributed on an
    * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    * KIND, either express or implied.  See the License for the
    * specific language governing permissions and limitations
    * under the License.    
-->
<html>
<head>  
<link rel="stylesheet" type="text/css" href="/ui.css">
<script type="text/javascript" src="/util.js"></script>
<script type="text/javascript" src="/elemutil.js"></script>
<script type="text/javascript" src="/xmlutil.js"></script>
<script type="text/javascript" src="/atomutil.js"></script>
<script type="text/javascript" src="/scdl.js"></script>
<script type="text/javascript" src="/ui.js"></script>
<script type="text/javascript" src="/component.js"></script>
<script type="text/javascript" src="graph.js"></script>
</head>  
<body>

<div style="position: absolute; top: 0px; left: 0px; right: 0px;">

<table width="100%">
<tr><th style="width: 338px;">Components</th><th style="padding-top: 0px; padding-bottom: 0px;"><span id="appname"></span><span style="position: absolute; top: 2px; right: 8px;"><input type="button" id="saveButton" style="font-weight: bold;" Value="Save"/></span></th></tr>
</table>

</div>

<script type="text/javascript">
var editWidget = sca.component("EditWidget");
var palettes = sca.reference(editWidget, "palettes");
var apps = sca.reference(editWidget, "apps");

// Setup remote log
//rconsole = sca.defun(sca.reference(editWidget, "log"), "log");

/**
 * The current app name.
 */
var appname = ui.queryParams()['app'];
$('appname').innerHTML = 'Composition: ' + appname;

/**
 * The current app composite.
 */
var composite;

/**
 * Return the composite in an ATOM entry.
 */
function atomcomposite(doc) {
    var entry = atom.readATOMEntryDocument(doc);
    var item = caddr(entry);
    return cddr(item);
}

/**
 * Get and display an app.
 */
function getapp(name, g) {
    if (isNil(name))
        return;
    apps.get(name, function(doc) {
        composite = atomcomposite(doc);
        graph.edit(composite, graph.composite(composite, graph.mkpath().move(350,0)), g);
    });
}

/**
 * Get and display a palette of components.
 */
function getpalette(name, g, bg, palette, gpalettes) {
    if (isNil(name))
        return;
    palettes.get(name, function(doc) {
        gpalettes[name] = graph.composite(atomcomposite(doc), graph.mkpath().move(150,0));
        graph.display(gpalettes[name], name == spalette? g : bg);
    });
}

/**
 * Install a palette, including a button to select the palette, and
 * the palette content.
 */
function installpalette(name, pos, g, bg, palette, gpalettes) {
    var b = graph.mkbutton(name, pos);
    graph.display(mklist(b), g);
    b.onclick = function() {

        // Display the selected palette
        spalette = name;
        for (var pn in gpalettes)
            graph.display(gpalettes[pn], pn == spalette? g : bg);
    }
    getpalette(name, g, bg, palette, gpalettes);
}

/**
 * Save the current edited page.
 */
$('saveButton').onclick = function(e) {

    // Update the page ATOM entry
    var compxml = writeXML(composite, false);
    var entry = '<entry xmlns="http://www.w3.org/2005/Atom">' +
        '<title type="text">' + appname + '</title><id>' + appname + '</id><content type="application/xml"><item>' +
        compxml + '</item></content></entry>';
    apps.put(appname, entry, function() {
    });
};

// Create editor graph area
var g = graph.mkgraph(graph.mkpath().move(0,50));
var bg = graph.mkgroup(graph.mkpath());

// Install the palettes.
var gpalettes = new Array();
var spalette = 'variables';
installpalette('variables', graph.mkpath().move(0,10), g, bg, spalette, gpalettes);
installpalette('control', graph.mkpath().move(0,80), g, bg, spalette, gpalettes);
installpalette('operators', graph.mkpath().move(0,150), g, bg, spalette, gpalettes);
installpalette('social', graph.mkpath().move(0,220), g, bg, spalette, gpalettes);
installpalette('sensors', graph.mkpath().move(0,290), g, bg, spalette, gpalettes);

// Get and display the current app
getapp(appname, g);

</script>
</body>
</html>
