private string generateExecCounterNode(string nidSwitchActivity)
        {
            var sb     = new StringBuilder();
            var nSteps =
                from a in _activities
                select a.Behavior.StepTimings.Count();

            sb.AppendFormat("const step = [{0}];\n", string.Join(", ", nSteps));
            sb.Append(@"
let currActivity = global.get('currActivity') || 1;
let currStep = global.get('currStep') || 0;  // for the first execution.
// Increment the counter.
++currStep;
// Check if the task is over.
if (currActivity === 1 + step.length) {
    return msg;
}
if (step[currActivity - 1] < currStep) {
    ++currActivity;
    currStep = 1;
}
global.set('currActivity', currActivity);
global.set('currStep', currStep);
return msg;
");
            var node = new NRFunctionNode(sb.ToString());

            node.Wire(nidSwitchActivity);
            node.WriteTo(_writer);
            return(node.Id);
        }
        private void generateParallelFlow(ParallelTiming timing, NRFunctionNode prev, NRJoinFunctionNode next)
        {
            var svcmap = _activity.ServiceMap;

            foreach (var anim in timing.Animations)
            {
                var service = svcmap.Lookup(anim.ShapeId);
                if (null == service)
                {
                    // No available service for the shape.
                    continue;
                }

                JObject flowObj;
                using (var flow =
                           anim.Type == AnimationType.Entrance ?
                           service.ActivationFlow :
                           service.DeactivationFlow)
                    using (var flowReader = flow.Reader)
                    {
                        flowObj = (JObject)JToken.ReadFrom(flowReader);
                    }
                var meta   = (JObject)flowObj["meta"];
                var nidIn  = (string)meta["in"];
                var nidOut = (string)meta["out"];

                var topic =
                    $@"{service.nodeName}-{(anim.Type == AnimationType.Entrance ? "activation" : "deactivation")}";
                var nodeTopic = new NRFunctionNode(func: $"msg.topic = '{topic}';return msg;");
                nodeTopic.Wire(next.Id);
                nodeTopic.WriteTo(_writer);

                nidIn = generateCopyOfFlow((JArray)flowObj["flow"], nidIn, nidOut, nodeTopic.Id);

                // If this animation effect has a delay, put a delay node.
                var nidFirst = nidIn;
                if (anim.HasDefiniteDelay && anim.Delay > 0)
                {
                    var nodeDelay = new NRDelayNode(anim.Delay);
                    nodeDelay.Wire(nidIn);
                    nodeDelay.WriteTo(_writer);
                    nidFirst = nodeDelay.Id;
                }

                prev.Wire(nidFirst);

                next.AddTopic(topic);
            }
            prev.WriteTo(_writer);
        }
        private string generateStepFlow(StepTiming timing, string nidReturn)
        {
            var firstNode = new NRFunctionNode();
            var prev      = firstNode;

            foreach (var parTiming in timing.ParallelTimings)
            {
                var next = new NRJoinFunctionNode();
                // prev will be written in this invocation.
                generateParallelFlow(parTiming, prev, next);
                prev = next;
            }
            // For understandability.
            var last = prev;

            last.Wire(nidReturn);
            last.WriteTo(_writer);
            return(firstNode.Id);
        }
        private string generateHttpResFuncNode(string nidHttpRes, int?currActivity, int?currStep, bool taskFinished)
        {
            var    _currActivity = currActivity?.ToString() ?? @"global.get('currActivity')";
            var    _currStep     = currStep?.ToString() ?? @"global.get('currStep')";
            string func          = $@"
msg.payload = {{
    status: {JsonConvert.SerializeObject(HttpResponseBody.StatusType.Success, Converter)},
    curr_activity: {_currActivity},
    curr_step: {_currStep},
    task_finished: {(taskFinished ? "true" : "false")}
}};
msg.headers = msg.headers || {{}};
msg.headers['Content-Type'] = 'application/json';
return msg;
";
            var    node          = new NRFunctionNode(func);

            node.Wire(nidHttpRes);
            node.WriteTo(_writer);
            return(node.Id);
        }
        public string generate(string nidHttpResFunc)
        {
            var returnNode = new NRFunctionNode();
            var switchNode = new NRSwitchNode(NRSwitchNode.PropertyType.GLOBAL, property: "currStep",
                                              checkall: false);
            var i        = 0;
            var behavior = _activity.Behavior;

            foreach (var stepTiming in behavior.StepTimings)
            {
                var nidStep = generateStepFlow(stepTiming, returnNode.Id);
                var rule    = new NRSwitchRule(NRSwitchRule.OperatorType.EQ, (i + 1).ToString(),
                                               NRSwitchRule.ValueType.Num);
                switchNode.AddRule(rule);
                switchNode.Wire(nidStep, i);
                ++i;
            }
            returnNode.Wire(nidHttpResFunc);
            returnNode.WriteTo(_writer);
            switchNode.WriteTo(_writer);
            return(switchNode.Id);
        }