/* 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.camunda.bpm.engine.impl.persistence.entity;

import java.util.List;

import org.camunda.bpm.engine.impl.DeploymentQueryImpl;
import org.camunda.bpm.engine.impl.Page;
import org.camunda.bpm.engine.impl.ProcessDefinitionQueryImpl;
import org.camunda.bpm.engine.impl.context.Context;
import org.camunda.bpm.engine.impl.event.MessageEventHandler;
import org.camunda.bpm.engine.impl.jobexecutor.TimerStartEventJobHandler;
import org.camunda.bpm.engine.impl.persistence.AbstractManager;
import org.camunda.bpm.engine.repository.Deployment;
import org.camunda.bpm.engine.repository.ProcessDefinition;
import org.camunda.bpm.engine.runtime.Job;


/**
 * @author Tom Baeyens
 */
public class DeploymentManager extends AbstractManager {

  public void insertDeployment(DeploymentEntity deployment) {
    getDbSqlSession().insert(deployment);

    for (ResourceEntity resource : deployment.getResources().values()) {
      resource.setDeploymentId(deployment.getId());
      getResourceManager().insertResource(resource);
    }

    Context
      .getProcessEngineConfiguration()
      .getDeploymentCache()
      .deploy(deployment);
  }

  public void deleteDeployment(String deploymentId, boolean cascade) {
    List<ProcessDefinition> processDefinitions = getDbSqlSession()
            .createProcessDefinitionQuery()
            .deploymentId(deploymentId)
            .list();

    if (cascade) {

      // delete process instances
      for (ProcessDefinition processDefinition: processDefinitions) {
        String processDefinitionId = processDefinition.getId();

        getProcessInstanceManager()
          .deleteProcessInstancesByProcessDefinition(processDefinitionId, "deleted deployment", cascade);

      }
    }

    for (ProcessDefinition processDefinition : processDefinitions) {
      String processDefinitionId = processDefinition.getId();
      // remove related authorization parameters in IdentityLink table
      getIdentityLinkManager().deleteIdentityLinksByProcDef(processDefinitionId);
    }

    // delete process definitions from db
    getProcessDefinitionManager()
      .deleteProcessDefinitionsByDeploymentId(deploymentId);

    for (ProcessDefinition processDefinition : processDefinitions) {
      String processDefinitionId = processDefinition.getId();

      // remove process definitions from cache:
      Context
        .getProcessEngineConfiguration()
        .getDeploymentCache()
        .removeProcessDefinition(processDefinitionId);

      // remove timer start events:
      List<Job> timerStartJobs = Context.getCommandContext()
        .getJobManager()
        .findJobsByConfiguration(TimerStartEventJobHandler.TYPE, processDefinition.getKey());

      if (timerStartJobs != null && timerStartJobs.size() > 0) {

        long nrOfVersions = new ProcessDefinitionQueryImpl(Context.getCommandContext())
          .processDefinitionKey(processDefinition.getKey())
          .count();

        long nrOfProcessDefinitionsWithSameKey = 0;
        for (ProcessDefinition p : processDefinitions) {
          if (!p.getId().equals(processDefinition) && p.getKey().equals(processDefinition)) {
            nrOfProcessDefinitionsWithSameKey++;
          }
        }

        if (nrOfVersions - nrOfProcessDefinitionsWithSameKey <= 1) {
          for (Job job : timerStartJobs) {
            ((JobEntity)job).delete();
          }
        }

      }

      // remove message event subscriptions:
      List<EventSubscriptionEntity> findEventSubscriptionsByConfiguration = Context
        .getCommandContext()
        .getEventSubscriptionManager()
        .findEventSubscriptionsByConfiguration(MessageEventHandler.EVENT_HANDLER_TYPE, processDefinition.getId());
      for (EventSubscriptionEntity eventSubscriptionEntity : findEventSubscriptionsByConfiguration) {
        eventSubscriptionEntity.delete();
      }

      // delete job definitions
      Context.getCommandContext()
        .getJobDefinitionManager()
        .deleteJobDefinitionsByProcessDefinitionId(processDefinition.getId());

    }

    getResourceManager()
      .deleteResourcesByDeploymentId(deploymentId);

    getDbSqlSession().delete("deleteDeployment", deploymentId);
  }


  public DeploymentEntity findLatestDeploymentByName(String deploymentName) {
    List<?> list = getDbSqlSession().selectList("selectDeploymentsByName", deploymentName, 0, 1);
    if (list!=null && !list.isEmpty()) {
      return (DeploymentEntity) list.get(0);
    }
    return null;
  }

  public DeploymentEntity findDeploymentById(String deploymentId) {
    return (DeploymentEntity) getDbSqlSession().selectById(DeploymentEntity.class, deploymentId);
  }

  public long findDeploymentCountByQueryCriteria(DeploymentQueryImpl deploymentQuery) {
    return (Long) getDbSqlSession().selectOne("selectDeploymentCountByQueryCriteria", deploymentQuery);
  }

  @SuppressWarnings("unchecked")
  public List<Deployment> findDeploymentsByQueryCriteria(DeploymentQueryImpl deploymentQuery, Page page) {
    final String query = "selectDeploymentsByQueryCriteria";
    return getDbSqlSession().selectList(query, deploymentQuery, page);
  }

  @SuppressWarnings("unchecked")
  public List<String> getDeploymentResourceNames(String deploymentId) {
    return getDbSqlSession().getSqlSession().selectList("selectResourceNamesByDeploymentId", deploymentId);
  }

  public void close() {
  }

  public void flush() {
  }
}

@@ -736,71 +736,8 @@
 ge;%0A
-import org.camunda.bpm.engine.impl.ProcessDefinitionQueryImpl;%0A
 impo
@@ -3200,127 +3200,48 @@
     
-if (timerStartJobs != null && timerStartJobs.size() %3E 0) %7B%0A%0A        long nrOf
+ProcessDefinitionEntity latest
 Version
-s
  = 
-new ProcessDefinitionQueryImpl(
 Cont
@@ -3263,20 +3263,17 @@
 ontext()
-)%0A  
+%0A
         
@@ -3277,305 +3277,200 @@
    .
-processDefinitionKey(processDefinition.getKey())%0A          .count();%0A%0A        long nrOfProcessDefinitionsWithSameKey = 0;%0A        for (ProcessDefinition p : processDefinitions) %7B%0A          if (!p.getId().equals(processDefinition) && p.getKey().equals(processDefinition)) %7B%0A            nrOfP
+getProcessDefinitionManager()%0A        .findLatestProcessDefinitionByKey(processDefinition.getKey());%0A%0A      // delete timer start event jobs only if this is the latest version of the p
 rocess
-D
+ d
 efin
@@ -3478,112 +3478,99 @@
 tion
-sWithSameKey++;%0A          %7D%0A        %7D%0A%0A        if (nrOfVersions - nrOfProcessDefinitionsWithSameKey %3C= 1
+.%0A      if(latestVersion != null && latestVersion.getId().equals(processDefinition.getId())
 ) %7B%0A
@@ -3573,26 +3573,24 @@
 ) %7B%0A        
- 
- 
 for (Job job
@@ -3606,26 +3606,24 @@
 tartJobs) %7B%0A
-  
           ((
@@ -3659,22 +3659,9 @@
     
-  %7D%0A        %7D%0A
+%7D
 %0A   

simplify job deletion logic