/* Licensed 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.
 */

package org.activiti.rest.service.api.runtime.task;

import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.activiti.engine.ActivitiException;
import org.activiti.engine.ActivitiIllegalArgumentException;
import org.activiti.engine.task.Task;
import org.activiti.rest.exception.ActivitiForbiddenException;
import org.activiti.rest.service.api.engine.variable.RestVariable;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author Frederik Heremans
 */
@RestController
public class TaskResource extends TaskBaseResource {

  @RequestMapping(value="/runtime/tasks/{taskId}", method = RequestMethod.GET, produces="application/json")
  public TaskResponse getTask(@PathVariable String taskId, HttpServletRequest request) {
    return restResponseFactory.createTaskResponse(getTaskFromRequest(taskId));
  }
  
  @RequestMapping(value="/runtime/tasks/{taskId}", method = RequestMethod.PUT, produces="application/json")
  public TaskResponse updateTask(@PathVariable String taskId, 
      @RequestBody TaskRequest taskRequest, HttpServletRequest request) {
    
    if (taskRequest == null) {
      throw new ActivitiException("A request body was expected when updating the task.");
    }
    
    Task task = getTaskFromRequest(taskId);

    // Populate the task properties based on the request
    populateTaskFromRequest(task, taskRequest);
    
    // Save the task and fetch agian, it's possible that an assignment-listener has updated
    // fields after it was saved so we can't use the in-memory task
    taskService.saveTask(task);
    task = taskService.createTaskQuery().taskId(task.getId()).singleResult();
    
    return restResponseFactory.createTaskResponse(task);
  }
  
  @RequestMapping(value="/runtime/tasks/{taskId}", method = RequestMethod.POST)
  public void executeTaskAction(@PathVariable String taskId, @RequestBody TaskActionRequest actionRequest) {
    if (actionRequest == null) {
      throw new ActivitiException("A request body was expected when executing a task action.");
    }

    Task task = getTaskFromRequest(taskId);
    
    if (TaskActionRequest.ACTION_COMPLETE.equals(actionRequest.getAction())) {
      completeTask(task, actionRequest);
      
    } else if (TaskActionRequest.ACTION_CLAIM.equals(actionRequest.getAction())) {
      claimTask(task, actionRequest);
      
    } else if (TaskActionRequest.ACTION_DELEGATE.equals(actionRequest.getAction())) {
      delegateTask(task, actionRequest);
      
    } else if (TaskActionRequest.ACTION_RESOLVE.equals(actionRequest.getAction())) {
      resolveTask(task, actionRequest);
      
    } else {
      throw new ActivitiIllegalArgumentException("Invalid action: '" + actionRequest.getAction() + "'.");
    }
  }

  @RequestMapping(value="/runtime/tasks/{taskId}", method = RequestMethod.DELETE)
  public void deleteTask(@PathVariable String taskId, @RequestParam(value="cascadeHistory", required=false) Boolean cascadeHistory,
      @RequestParam(value="deleteReason", required=false) String deleteReason, HttpServletResponse response) {
    
    Task taskToDelete = getTaskFromRequest(taskId);
    if (taskToDelete.getExecutionId() != null) {
      // Can't delete a task that is part of a process instance
      throw new ActivitiForbiddenException("Cannot delete a task that is part of a process-instance.");
    }
    
    if (cascadeHistory != null) {
      // Ignore delete-reason since the task-history (where the reason is recorded) will be deleted anyway 
      taskService.deleteTask(taskToDelete.getId(), cascadeHistory);
    } else {
      // Delete with delete-reason
      taskService.deleteTask(taskToDelete.getId(), deleteReason);
    }
    response.setStatus(HttpStatus.NO_CONTENT.value());
  }

  protected void completeTask(Task task, TaskActionRequest actionRequest) {
    if(actionRequest.getVariables() != null) {
      Map<String, Object> variablesToSet = new HashMap<String, Object>(); 
      for(RestVariable var : actionRequest.getVariables()) {
        if(var.getName() == null) {
          throw new ActivitiIllegalArgumentException("Variable name is required");
        }
        
        Object actualVariableValue = restResponseFactory.getVariableValue(var);
        variablesToSet.put(var.getName(), actualVariableValue);
      }
      
      taskService.complete(task.getId(), variablesToSet);
    } else {
      taskService.complete(task.getId());
    }
    
  }

  protected void resolveTask(Task task, TaskActionRequest actionRequest) {
    taskService.resolveTask(task.getId());
  }

  protected void delegateTask(Task task, TaskActionRequest actionRequest) {
    if (actionRequest.getAssignee() == null) {
      throw new ActivitiIllegalArgumentException("An assignee is required when delegating a task.");
    }
    taskService.delegateTask(task.getId(), actionRequest.getAssignee());
  }

  protected void claimTask(Task task, TaskActionRequest actionRequest) {
    // In case the task is already claimed, a ActivitiTaskAlreadyClaimedException is thrown and converted to
    // a CONFLICT response by the ExceptionHandlerAdvice
    taskService.claim(task.getId(), actionRequest.getAssignee());
  }
}

@@ -1378,16 +1378,79 @@
 tParam;%0A
+import org.springframework.web.bind.annotation.ResponseStatus;%0A
 import o
@@ -2851,16 +2851,57 @@
 d.POST)%0A
+  @ResponseStatus(value = HttpStatus.OK)%0A
   public

Fix tests