/// <summary>
        /// Compiles all decision nodes code and loops code in the given experiment
        /// </summary>
        /// <param name="experiment">The experiment.</param>
        /// <param name="availableInputMappingsPerNode">The available input mappings per node.</param>
        /// <param name="workspaceTypesDirectories">The workspace types directories.</param>
        /// <param name="loggerNameRoot">The logger name root.</param>
        /// <returns>
        /// true if there were no errors, otherwise false
        /// </returns>
        public static bool CompileAllDecisionNodes(IExperiment experiment, InputMappings availableInputMappingsPerNode, 
                                                   List<string> workspaceTypesDirectories, LoggerNameRoot loggerNameRoot)
        {
            bool noErrors = true;

            foreach (ExperimentNode node in experiment.Vertices)
            {
                IDecision decisionMetadata = node.Data.Metadata as IDecision;
                if (decisionMetadata != null)
                {
                    try
                    {
                        //build successor nodes label id lookup
                        Dictionary<string, string> successorNodeLabelIdLookup = PrepareSuccessorNodesLabelIdLookup(node, experiment);
                        Dictionary<string, string> predeccessorsOutputsNameTypeLookup = PreparePredeccessorsOutputsNameTypeLookup(node, availableInputMappingsPerNode);

                        node.ClearError();

                        BuildSourceAndCompileDecisionModule(decisionMetadata, successorNodeLabelIdLookup,
                            predeccessorsOutputsNameTypeLookup, workspaceTypesDirectories, loggerNameRoot);
                    }
                    catch (ArgumentException ex)
                    {
                        noErrors = false;
                        node.SetError(ex.Message);
                    }
                }
            }

            return noErrors;
        }
        /// <summary>
        /// Validates if the list of outputs from incoming vertices satisfies all the inputs for all vertices in the lookup.
        /// </summary>
        /// <returns>true, if all vertices have correct mapping, false if there is any node with input that is not satisfied by previous outputs.</returns>
        public static bool Validate(IExperiment experiment, InputMappings availableInputMappingsPerNode)
        {
            bool retVal = true;

            foreach (ExperimentNode currentNode in availableInputMappingsPerNode.Nodes)
            {
                bool validationResults = ValidateInputMapping(currentNode, availableInputMappingsPerNode[currentNode]);
                if (retVal != false)
                {
                    retVal = validationResults;
                }
            }
    
            return retVal;
        }
        /// <summary>
        /// Creates the input mapping column with combo box.
        /// TODO improve the input mapping combo box:
        /// 1. it doesn't set values until combo box loses focus within table view confirm change - Edited event is raised only then
        /// 2. there is no indication that the field can be modified - render combo box always, OR show some icon that it can be modified
        /// </summary>
        /// <returns>
        /// The input mapping column with combo box.
        /// </returns>
        /// <param name='inputStore'>
        /// Input store.
        /// </param>
        private TreeViewColumn CreateInputMappingColumnWithComboBox(NodeStore inputStore, string columntTitle)
        {
            Gtk.CellRendererCombo comboRenderer = new Gtk.CellRendererCombo();
            
            comboRenderer.HasEntry = false;
            comboRenderer.Mode = CellRendererMode.Editable;
            comboRenderer.TextColumn = 0;
            comboRenderer.Editable = true;

            ListStore comboBoxStore = new ListStore (typeof(string));
            comboRenderer.Model = comboBoxStore;

            //when user activates combo box, refresh combobox store with available input mapping per node
            comboRenderer.EditingStarted += delegate (object o, EditingStartedArgs args) 
            {
                comboBoxStore.Clear ();
                IOItemNode currentItem = (IOItemNode)inputStore.GetNode (new TreePath (args.Path));
                ExperimentNode currentNode = m_component.ExperimentNode;
                string currentType = currentItem.Type;
                InputMappings availableInputMappingsPerNode = new InputMappings (currentNode.Owner);
                if (currentNode != null && availableInputMappingsPerNode.ContainsMappingsForNode (currentNode)) {
                    foreach (string incomingOutput in availableInputMappingsPerNode [currentNode].Keys) {
                        if (string.Equals (currentType, availableInputMappingsPerNode [currentNode] [incomingOutput])) {
                            comboBoxStore.AppendValues (Mono.Unix.Catalog.GetString (incomingOutput));
                        }
                    }
                }
            };

            //when edition has been completed set current item node with proper mapping
            comboRenderer.Edited += delegate (object o, EditedArgs args) {
                IOItemNode n = (IOItemNode)inputStore.GetNode (new TreePath (args.Path));
                n.MappedTo = args.NewText;
                RefreshIOHighlightInExperiment(n.MappedTo);
            };

            //finally create the column with above combo renderer
            var mappedToColumn = new TreeViewColumn ();
            mappedToColumn.Title = columntTitle;
            mappedToColumn.PackStart (comboRenderer, true);

            //this method sets the text view to current mapping, when combo box is not active
            mappedToColumn.SetCellDataFunc (comboRenderer, delegate (TreeViewColumn tree_column, CellRenderer cell, ITreeNode node) {
                IOItemNode currentItem = (IOItemNode)node;
                comboRenderer.Text = currentItem.MappedTo;
            });

            return mappedToColumn;
        }
        /// <summary>
        /// Prepares the predeccessors outputs lookup.
        /// </summary>
        /// <param name="vert">The vert.</param>
        /// <param name="availableInputMappingsPerNode">The available input mappings per node.</param>
        /// <returns>
        /// list of all the outputs from previous nodes. the key is output name, and the value is the type of that output
        /// </returns>
        public static Dictionary<string, string> PreparePredeccessorsOutputsNameTypeLookup(ExperimentNode vert, InputMappings availableInputMappingsPerNode)
        {
            Dictionary<string, string> predeccessorsOutputsNameTypeLookup;

            if (availableInputMappingsPerNode.TryGetValue(vert, out predeccessorsOutputsNameTypeLookup) == false)
            {
                predeccessorsOutputsNameTypeLookup = new Dictionary<string, string>(); //return empty - there is not path from start node to decision
            }

            return predeccessorsOutputsNameTypeLookup;
        }
        /// <summary>
        /// Compiles the decision.
        /// </summary>
        /// <param name="node">The node.</param>
        /// <param name="experiment">The experiment.</param>
        /// <param name="workspaceTypesDirectories">The workspace types directories.</param>
        /// <param name="loggerNameRoot">The logger name root.</param>
        private static void CompileDecisionInternal(ExperimentNode node, IExperiment experiment, List<string> workspaceTypesDirectories, 
                                                    LoggerNameRoot loggerNameRoot, Dictionary<string, string> successorNodeLabelIdLookup)
        {
            InputMappings availableInputMappingsPerNode = new InputMappings(experiment);

            Dictionary<string, string> predeccessorsOutputsNameTypeLookup = PreparePredeccessorsOutputsNameTypeLookup(node, availableInputMappingsPerNode);

            IDecision decisionMetadata = (IDecision)node.Data.Metadata;
            try
            {
                if (decisionMetadata != null)
                {
                    node.ClearError();

                    BuildSourceAndCompileDecisionModule(decisionMetadata, successorNodeLabelIdLookup, predeccessorsOutputsNameTypeLookup, workspaceTypesDirectories, loggerNameRoot);

                    decisionMetadata.CompilationStatus = TraceLab.Core.Components.CompilationStatus.Successful;
                }
            }
            catch (ArgumentException ex)
            {
                decisionMetadata.CompilationStatus = TraceLab.Core.Components.CompilationStatus.Failed;
                node.SetError(ex.Message);
            }
        }