Index: branches/OaaS/HeuristicLab.Services.Optimization.Web/Views/Experiment/New.cshtml
===================================================================
--- branches/OaaS/HeuristicLab.Services.Optimization.Web/Views/Experiment/New.cshtml	(revision 9227)
+++ branches/OaaS/HeuristicLab.Services.Optimization.Web/Views/Experiment/New.cshtml	(revision 9227)
@@ -0,0 +1,542 @@
+﻿@model HeuristicLab.Services.Optimization.Web.Models.ExperimentViewModel
+@{
+    ViewBag.Title = "Index.cshtml";
+}
+
+
+<script type="text/javascript">
+  function Experiment() {
+    this.algorithms = [];
+    this.nodeMapping = {};
+    this.name = "My Experiment"
+  }
+    
+  Experiment.prototype.buildAndStore = function(node, index, tree, ctx) {
+    var result = this.build(node, index, tree, 'Experiment');
+    this.algorithms = result.algorithms;
+    this.nodeMapping = result.mapping;
+  }
+
+  Experiment.prototype.build = function(node, index, tree, ctx) {
+    var stack = new Array();
+    var root = {name : node.title, children: [], context: ctx};
+    var nodeMapping = {};
+    this.fetchNode(root, node, index, tree);
+    if (node.title != 'Experiment')
+      nodeMapping[node.key] = root;
+      
+    if (node.children)
+        for (var i=0; i < node.children.length; i++) { 
+          stack.push({parent: root, child: node.children[node.children.length - 1 - i], index: node.children.length - 1 - i});
+        }
+    while(stack.length > 0) {
+      var tmp = stack.pop();
+      var parent = tmp.parent;
+      var child = tmp.child;
+      var newChild = { name : child.title, children: [], context: ctx}
+      // fetch the nodes from the server
+      this.fetchNode(newChild, child, tmp.index, tree);
+      nodeMapping[tmp.child.key] = newChild;      
+      parent.children.push(newChild);
+      if (child.children)
+          for (var i=0; i < child.children.length; i++) {
+            stack.push({parent: newChild, child: child.children[child.children.length - 1 - i], index: child.children.length - 1 - i});
+          }
+    }
+    return {algorithms: root, mapping: nodeMapping};
+  }
+
+  Experiment.prototype.fetchNode = function(modelNode, dynaNode, index, tree) {
+    if (modelNode.name == 'Experiment')
+      return;
+    var self = this;
+    var node = tree.getNodeByKey(dynaNode.key);
+    $.ajax({
+        type: "GET",
+        url: '/Experiment/GetParameters',
+        data: { scenario: modelNode.name, context: modelNode.context, index: index },
+        contentType: "application/json; charset=utf-8",
+        dataType: "json",
+        success: function (result) {
+            if (result.Type == "Complex") {
+                // extend the tree element
+                node.removeChildren();
+                var parent = self.nodeMapping[node.data.key];
+                for (var i=0; i < result.Subnames.length; i++) {
+                    // add node to dynatree
+                    var childNode = node.addChild({title: result.Subnames[i]});
+                    var internalResult = self.build(childNode.toDict(true), i, tree, modelNode.name);  
+                    parent.children.push(internalResult.algorithms);
+                    for (var attrname in internalResult.mapping) { self.nodeMapping[attrname] = internalResult.mapping[attrname]; }                  
+                }
+            } else if (result.Type == "Basic") {      
+                // replace the wizard    
+                previousWizards[node.data.key] = replaceWizard(result);
+                saveParameters(previousWizards[node.data.key], node);
+            }
+        }
+    });
+  }
+
+  Experiment.prototype.pushNode = function(parentKey, nodeKey, entryName, ctx) {
+    var entry = {name: entryName, children: [], context: ctx};
+    this.nodeMapping[parentKey].children.push(entry);
+    this.nodeMapping[nodeKey] = entry;
+  }
+
+  var experiment = new Experiment();
+  var previousWizards = {};
+
+  function saveExperiment() {
+    $('.buttonFinish').attr('disabled', 'disabled');
+    experiment["name"] = $('#name').val();
+    experiment["run"] = $('#runImmediately').attr('checked') == 'checked';
+    experiment["repititions"] = $('#repititions').val();
+    experiment["group"] = $('#group').val();
+
+     $.ajax({ type: "POST",
+      url: '/Experiment/SaveExperiment',
+      data: JSON.stringify(experiment),
+      contentType: "application/json; charset=utf-8",
+      dataType: "json",
+      success: function (result) {
+        $('#status-dialog').dialog("open");
+      },
+      error: function (result) {
+      }
+     });
+  }
+
+  function treeIndexOf(sibling) {
+    var i = 0;
+    var prev = sibling.getPrevSibling()
+    while (prev != null) {
+        i++;
+        prev = prev.getPrevSibling()
+    }
+    return i;
+  }
+
+  function saveParameters(wiz, node) {
+    var wiz = typeof wiz !== 'undefined' ? $(wiz) : $('.wizard', '#parameter-dialog-content');
+    var id = wiz.attr('id');
+    var node = typeof node !== 'undefined' ? node : $('#container2').dynatree("getActiveNode");
+    var data = {};   
+
+    for (var i = 1; i < 3; i++) {
+      var stepId = '#' + id + '_' + i;
+      var step = $(stepId);
+      if (step.length == 0) {
+        break;
+      }
+      var stepDesc = $('a[href="' + stepId + '"] span', wiz).contents()[0].data;
+      var dataEntries = $('input, select', step);
+      var entry = { };
+      var mapper = new DatatypeMapper();
+      for (var j = 0; j < dataEntries.length; j++) {
+        entry[dataEntries[j].name] = mapper.mapString(dataEntries[j].value);
+      }
+      data[stepDesc] = entry;
+    }
+    
+    // aggregate tables:
+    var mapper = new DatatypeMapper();
+    mapper.aggregateTables(data);
+
+    var experimentEntry = experiment.nodeMapping[node.data.key];
+    // we are at the node, update data
+    experimentEntry["data"] = data;
+    // Close dialog
+    $('#params').dialog("close");
+  }
+
+  function createParamterDiv(name, parameters) {
+    var mapper = new DatatypeMapper();
+    // get algorithm parameters
+    var paramsDiv = $('<div />').data("name", name);
+    for (var i=0; i < parameters.length; i++) {
+      var property = parameters[i];
+      var content = mapper.mapHtml(property.Value);
+
+      // add to canvas              
+      $('<h2/>').text(property.Value.Name).appendTo(paramsDiv);
+      content.appendTo(paramsDiv);
+      $('<div />').addClass('clearer').appendTo(paramsDiv);
+    }
+    return paramsDiv;
+  }
+
+  function createWizard(name, steps) {
+    var wizard = $('<div />', { id: name }).addClass('wizard swMain');
+    var stepMenu = $('<ul />');
+    var prefix = name + '_';
+    for (var i = 0; i < steps.length; i++) {
+      var step = steps[i];
+      var a = $('<a></a>', {href: '#' + prefix + (i + 1)});
+      $('<label />').addClass("stepNumber").text((i + 1)).appendTo(a);
+      $('<span />').addClass("stepDesc").html(step.heading + '<br /><small>' + step.description + '</small>').appendTo(a);
+      var li = $('<li />').append(a);
+      li.appendTo(stepMenu);
+    }
+    stepMenu.appendTo(wizard);
+    for (var i = 0; i < steps.length; i++) {
+      var div = $('<div />', { id: prefix + (i + 1) });
+      if (steps[i].content && steps[i].content != null)
+        div.append(steps[i].content);
+      div.appendTo(wizard);
+    }
+    return wizard;
+  }
+
+
+  function makeTree() {
+    var tree = $('#container').dynatree({
+      onActivate: function (node) {
+        if (node && node.data.title !== "Experiment") {
+          $('input[name="RemoveNode"]').removeAttr("disabled");
+        } else if (node) {
+          $('input[name="RemoveNode"]').attr("disabled", "disabled");
+        }
+      },
+      onDeactivate: function (node) {
+      },
+      dnd: {
+        autoExpandMS: 750,
+
+        onDragStart: function (node) {
+          return node.data.title !== "Experiment";
+        },
+        onDragEnter: function (node, sourceNode) {
+          return true;
+        },
+        onDragOver: function (node, sourceNode, hitMode) {
+          return node.data.title !== "Experiment" || hitMode === "over";
+        },
+        onDrop: function (node, sourceNode, hitMode, ui, draggable) {
+          if (sourceNode) {
+            sourceNode.move(node, hitMode);
+          }
+          else {
+            newNode = { title: draggable.element[0].id };
+            if (hitMode == "over") {
+              node.addChild(newNode);
+              node.expand(true);
+            }
+            else if (hitMode == "before") {
+              node.parent.addChild(newNode, node);
+            }
+            else {
+              node.parent.addChild(newNode, node.getNextSibling());
+            }
+          }
+        },
+        onDragLeave: function (node, sourceNode) {
+        }
+      }
+    });
+
+    $('.dragables').each(function () {
+      $(this).draggable({
+        revert: true,
+        connectToDynatree: true,
+        cursorAt: { top: -5, left: -5 },
+        helper: "clone"
+      });
+    });
+
+    $('input[name="RemoveNode"]').click(function () {
+      var node = $("#container").dynatree("getActiveNode");
+      if (node && node.data.title !== "Experiment")
+        node.remove();
+      $(this).attr("disabled", "disabled");
+    });
+  }
+
+  function leaveStep(obj) {
+    var stepNum = obj.attr("rel");
+    return validateStep(stepNum);
+  }
+
+  function validateStep(stepNum) {
+    var isStepValid = true;
+    if (stepNum == 1) {
+      previousWizards = {}
+      experiment = new Experiment();
+      var data = $("#container").dynatree("getTree").toDict().children;
+      $("#container2").dynatree({
+        onActivate: editElement
+      });
+      var rootNode = $("#container2").dynatree("getRoot");
+      rootNode.removeChildren();
+      rootNode.addChild(data);
+      // based on the data rebuild the experiment
+      experiment.buildAndStore(data[0], 0, $("#container2").dynatree("getTree"));
+    }
+    return isStepValid;
+  }
+
+  function resetDialog() {
+    var canvas = $('#parameter-dialog-content');
+    canvas.empty();
+    $('<img />').attr('alt', 'Loading animation').attr('src', '@Url.Content("~/Content/ajax-loader.gif")').attr('class', 'loader').appendTo(canvas);
+    $('<div />').text("Loading...").appendTo(canvas);        
+  }
+
+  globalCounter = 0;
+
+  function replaceWizard(result) {
+    var canvas = $('#parameter-dialog-content');
+    canvas.empty();
+
+    // get parameters as div
+    var algoParamsDiv = null;
+
+    if (result.Algorithm.Parameters) {
+        algoParamsDiv = createParamterDiv("Algorithm Parameters", result.Algorithm.Parameters.Items);
+    }
+
+    var problemParamsDiv = null;
+    if (result.Algorithm.Problem && result.Algorithm.Problem.Parameters) {
+     problemParamsDiv = createParamterDiv("Problem Parameters", result.Algorithm.Problem.Parameters.Items);
+    }
+
+    var wizard = null;
+    if (result.Algorithm.Problem)
+     wizard = createWizard("TestWizard", [
+        { heading: "Algorithm Parameters", description: "Adjust algorithm parameters", content: algoParamsDiv },
+        { heading: "Problem Parameters", description: "Adjust problem parameters", content: problemParamsDiv }
+    ]);
+    else
+     wizard = createWizard("TestWizard", [
+        { heading: "Algorithm Parameters", description: "Adjust algorithm parameters", content: algoParamsDiv }
+    ]);
+
+    wizard.appendTo(canvas);
+    $(".wizard", canvas).smartWizard({
+        onFinish: saveParameters,
+        labelFinish: 'Save'
+    });
+    return wizard;
+  }
+
+  function editElement(node) {
+    resetDialog();
+    $("#params").dialog("open");
+    // if we opened this windows before, use the previously created wizard
+    if (node.data.key in previousWizards) {
+      var canvas = $('#parameter-dialog-content');
+      canvas.empty();  
+      $(previousWizards[node.data.key]).appendTo(canvas);
+      var wiz = $(".wizard", canvas).smartWizard({
+        onFinish: saveParameters,
+        labelFinish: 'Save'
+      });
+      // we have to recreate the wizard, otherwise it is not responsive -> remove some multiple occuring wizard elements.
+      var parent = $('.stepContainer.content', wiz).parent('.stepContainer:not(.content)');
+      var elem = $('.stepContainer.content .content', wiz).detach();
+      elem.appendTo(parent);
+      $('.stepContainer.content', wiz).detach();
+      $('.actionBar.content', wiz).detach();
+    }
+    else {
+        $.ajax({
+          type: "GET",
+          url: '/Experiment/GetParameters',
+          data: { scenario: node.data.title, context: experiment.nodeMapping[node.data.key].context, index: treeIndexOf(node) },
+          contentType: "application/json; charset=utf-8",
+          dataType: "json",
+          success: function (result) {
+            if (result.Type == "Complex") $("#params").dialog("close");
+            /*if (result.Type == "Complex") {
+              // extend the tree element     
+              $("#params").dialog("close");     
+              node.removeChildren();
+              for (var i=0; i < result.Subnames.length; i++) {
+                // add node to dynatree
+                var childNode = node.addChild({title: result.Subnames[i]});
+                // add node to model
+                experiment.pushNode(node.data.key, childNode.data.key, result.Subnames[i], node.data.title);
+              }
+            } else*/
+            if (result.Type == "Basic") {      
+              // replace the wizard    
+              previousWizards[node.data.key] = replaceWizard(result);
+              saveParameters(previousWizards[node.data.key], node);
+            }
+          }
+        });
+     }
+  }
+
+  $(document).ready(function () {
+    var wiz = $(".wizard").smartWizard({
+      /*updateHeight: false*/
+      onLeaveStep: leaveStep,
+      onFinish: saveExperiment
+    });
+    makeTree();
+
+    $("#params").dialog({
+      autoOpen: false,
+      width: 1024,
+      height: 768,
+      /*modal: true,
+      buttons: {
+        "Save parameters": function () {
+          
+        }
+        ,
+        "Cancel": function () {
+          $(this).dialog("close");
+        }
+      },
+      close: function () {
+      }*/
+    });
+
+    $("#status-dialog").dialog({
+      autoOpen: false,
+      resizable: false,
+      height: 100,
+      modal: true,
+      buttons: { "OK" : function() { $(this).dialog('close'); $('.buttonFinish').removeAttr('disabled'); } }
+    });
+
+    $('#runImmediately').change(
+        function() {
+            if ($(this).is(':checked')) {
+                $('#repititions').removeAttr('disabled');
+                $('#group').removeAttr('disabled');
+            }
+            else {
+                $('#repititions').attr('disabled', 'disabled');
+                $('#group').attr('disabled', 'disabled');
+            }
+        });
+  });
+</script>
+
+<h2>Experiment</h2>
+
+<div class="wizard swMain">
+  <ul>
+    <li>
+      <a href="#step1">
+        <label class="stepNumber">1</label>
+        <span class="stepDesc">
+          Structure<br />
+          <small>Build your experiment</small>
+        </span>
+      </a>
+    </li>
+    <li>
+      <a href="#step2">
+        <label class="stepNumber">2</label>
+        <span class="stepDesc">
+          Customization<br />
+          <small>Change experiment parameters</small>
+        </span>
+      </a>
+    </li>
+    <li>
+      <a href="#step3">
+        <label class="stepNumber">3</label>
+        <span class="stepDesc">
+          Experiment Details<br />
+          <small>Set name of experiment</small>
+        </span>
+      </a>
+    </li>
+  </ul>
+  <div id="step1">
+  @using (Html.BeginForm("TreeData", "Tree"))
+  {
+  <fieldset>    
+    <div>
+    <p>Experiment Tree:</p>
+    </div>
+
+    <div id="container" class="treeStyle">
+      <ul>
+        <li id="root">Experiment</li>
+      </ul>
+    </div>
+    <input style="margin-top:5px;"  name="RemoveNode" type="button" value="Remove" disabled="disabled" />
+
+    
+     @if (Model.Scenarios.Count > 0) {
+        <p>Choose an algorithm:</p>
+        foreach (var scen in Model.Scenarios) {
+            <div class="dragables" id="@scen"><p>@scen</p></div>
+        }        
+        <div class="clearer"/>    
+     }
+    
+    @if (Model.Scenarios.Count > 0) {
+        <p>Choose from your stored experiments:</p>
+        foreach (var scen in Model.Experiments) {
+            <div class="dragables" id="@scen"><p>@scen</p></div>
+        }
+        <div class="clearer"/>
+    }   
+    
+  </fieldset>
+  }
+  </div>
+  <div id="step2">
+  <h2>Click on a experiment to adjust its parameters:</h2>
+  <div id="container2" class="treeStyle">
+      <ul>
+        <li>Experiment</li>
+      </ul>
+    </div>
+  </div>
+  <div id="step3">
+    <div class="editor-label">
+      <label for="name">Experiment Template Name:</label>
+    </div>
+
+    <div class="editor-field">
+      <input id="name" name="Name" type="text" value="My Experiment" />
+    </div>
+
+    <div class="editor-label">
+      <label for="name">Run experiment immediately?</label>
+    </div>
+
+    <div class="editor-field">
+      <input id="runImmediately" name="RunImmediately" type="checkbox" />
+    </div>
+
+    <div class="editor-label">
+      <label for="name">Repititions</label>
+    </div>
+
+    <div class="editor-field">
+      <input id="repititions" name="Repititions" type="text" value="1" disabled="disabled" />
+    </div>
+
+    <div class="editor-label">
+      <label for="name">Group</label>
+    </div>
+
+    <div class="editor-field">
+      <input id="group" name="Group" type="text" value="TESTAZURE" disabled="disabled" />
+    </div>
+  </div>  
+</div>
+
+<div id="status-dialog">
+    <div>
+      Experiment has been saved!
+    </div>            
+</div>
+
+<div id="params" title="Update parameters">
+    <!-- Note: The content must be loaded asynchronously -->
+    <div id="parameter-dialog-content">
+      <img src="@Url.Content("~/Content/ajax-loader.gif")" alt="Loading animation" class="loader" />
+      Loading ...      
+    </div>
+            
+  </div>
