package org.mwg.core.task;

import org.mwg.Callback;
import org.mwg.Constants;
import org.mwg.Node;
import org.mwg.base.BaseNode;
import org.mwg.plugin.Resolver;
import org.mwg.plugin.SchedulerAffinity;
import org.mwg.task.Task;
import org.mwg.task.TaskContext;
import org.mwg.task.TaskResult;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class CF_ActionAtomic extends CF_Action {

    private final String[] _variables;
    private final Task _subTask;

    CF_ActionAtomic(final Task p_subTask, final String... variables) {
        super();
        this._subTask = p_subTask;
        this._variables = variables;
    }

    @Override
    public void eval(final TaskContext ctx) {
        final List<TaskResult> collected = new ArrayList<TaskResult>();
        for (int i = 0; i < _variables.length; i++) {
            String varName = _variables[i];
            TaskResult resolved;
            if (varName.equals("result")) {
                resolved = ctx.result();
            } else {
                resolved = ctx.variable(varName);
            }
            if (resolved != null) {
                collected.add(resolved);
            }
        }
        //acquire lock
        final Resolver resolver = ctx.graph().resolver();
        for (int i = 0; i < collected.size(); i++) {
            TaskResult toLock = collected.get(i);
            for (int j = 0; j < toLock.size(); j++) {
                Object o = toLock.get(j);
                if (o instanceof BaseNode) {
                    resolver.externalLock((Node) o);
                }
            }
        }
        final TaskResult previous = ctx.result();
        _subTask.executeFrom(ctx, previous, SchedulerAffinity.SAME_THREAD, new Callback<TaskResult>() {
            @Override
            public void on(TaskResult result) {
                Exception exceptionDuringTask = null;
                if (result != null) {
                    if (result.output() != null) {
                        ctx.append(result.output());
                    }
                    if (result.exception() != null) {
                        exceptionDuringTask = result.exception();
                    }
                    result.free();
                }
                for (int i = 0; i < collected.size(); i++) {
                    TaskResult toLock = collected.get(i);
                    for (int j = 0; j < toLock.size(); j++) {
                        Object o = toLock.get(j);
                        if (o instanceof BaseNode) {
                            resolver.externalUnlock((Node) o);
                        }
                    }
                }
                if (exceptionDuringTask != null) {
                    ctx.endTask(previous, exceptionDuringTask);
                } else {
                    ctx.continueWith(previous);
                }
            }
        });
    }

    @Override
    public Task[] children() {
        Task[] children_tasks = new Task[1];
        children_tasks[0] = _subTask;
        return children_tasks;
    }

    @Override
    public void cf_serialize(StringBuilder builder, Map<Integer, Integer> dagIDS) {
        builder.append(ActionNames.LOOP);
        builder.append(Constants.TASK_PARAM_OPEN);
        final CoreTask castedAction = (CoreTask) _subTask;
        final int castedActionHash = castedAction.hashCode();
        if (dagIDS == null || !dagIDS.containsKey(castedActionHash)) {
            builder.append(Constants.SUB_TASK_OPEN);
            castedAction.serialize(builder, dagIDS);
            builder.append(Constants.SUB_TASK_CLOSE);
        } else {
            builder.append("" + dagIDS.get(castedActionHash));
        }
        for (int i = 0; i < _variables.length; i++) {
            builder.append(Constants.TASK_PARAM_SEP);
            TaskHelper.serializeString(_variables[i], builder, true);
        }
        builder.append(Constants.TASK_PARAM_CLOSE);
    }


}

@@ -1610,58 +1610,8 @@
   %7D%0A
-        final TaskResult previous = ctx.result();%0A
     
@@ -1640,24 +1640,28 @@
 om(ctx, 
-previous
+ctx.result()
 , Schedu
@@ -2148,43 +2148,8 @@
   %7D%0A
-                    result.free();%0A
     
@@ -2658,24 +2658,22 @@
 endTask(
-p
 re
-vious
+sult
 , except
@@ -2754,16 +2754,14 @@
 ith(
-p
 re
-vious
+sult
 );%0A 

fix atomic