package com.capgemini.reports.common.scheduling;

import com.capgemini.framework.teamcenter.authent.TcSession;
import com.capgemini.reports.checkdata.CheckingDataHelper;
import com.capgemini.reports.common.ServletMessageHelper;
import com.capgemini.reports.database.DataBaseReportHelper;
import com.capgemini.reports.database.HibernateUtil;
import com.capgemini.reports.database.javabean.DbSchedulingReport;
import com.capgemini.reports.database.javabean.DbUser;
import com.capgemini.reports.database.javabean.DbUser.UserData;
import com.capgemini.reports.database.manager.MngSchedulingReport;
import com.capgemini.reports.database.manager.MngUser;
import com.capgemini.reports.exceptions.*;
import com.capgemini.reports.execution.AbstractExecutionReport;
import com.capgemini.reports.periodicity.SchedulingPeriod;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.json.JSONObject;
import org.quartz.SchedulerException;

import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;

/**
 * Class providing the framework for modifying a scheduling.<br>
 * The old scheduled report will be destroyed and the new scheduled report will be submitted and checked.<br>
 */
@Slf4j
@WebServlet("/scheduling/modify")
public class ModifyServletScheduling extends AbstractGenerateScheduledTemplateServlet {

  private static final long serialVersionUID = 3233963187725874998L;

  @Override
  protected JSONObject perform(final HttpServletRequest request, final TcSession tcSession) throws SchedulerException, NotSupportedException,
    InvalidUserInputException, DuplicateSchedulingEntryFound, FileLoadingException {
    SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
    Session session = sessionFactory.openSession();
    try {
      // Identify the requestor
      UserData adUser = identifyUser(request);
      final DbUser dbUser = new MngUser().fetchOrUpdateOrCreateUser(session, adUser);

      // Obtain all parameters from the request
      String schedulingReportIdStr = request.getParameter(KEY_SCHEDULING_REPORT_ID);
      Long schedulingReportId = Long.valueOf(schedulingReportIdStr);
      String planifName = super.getPlanificationName(request);
      AbstractExecutionReport<?, ?> report = super.getExecutionReportImpl(request);
      report.setScheduling(schedulingReportId, planifName);
      SchedulingPeriod period = super.getSchedulingData(request);

      checkDuplicateName(session, schedulingReportId, planifName);

      // Check the report is STILL valid
      CheckingDataHelper.doQuickCheck(tcSession, report);

      // Update the DB
      DataBaseReportHelper.updateScheduling(schedulingReportId, report, planifName, period, dbUser);

      // Update the functional (JobDetail) and temporal (Trigger) parameters
      schedulingServer.replaceJob(schedulingReportId, report, report.getPriorityCode(), period, planifName);

      // Return a success message
      return successMessage(report);
    }
    finally {
      session.close();
    }
  }

  /**
   * Fails if the name has changed AND the new name is already used.
   */
  private void checkDuplicateName(Session session, Long schedulingReportId, String planifName) throws DuplicateSchedulingEntryFound {
    MngSchedulingReport mngScheduling = new MngSchedulingReport();
    DbSchedulingReport oldScheduling = mngScheduling.searchById(session, schedulingReportId);
    if (!planifName.equals(oldScheduling.getSchedulingName())) {
      // the scheduling name has changed, check that it doesn't interfere with an other one!
      DbSchedulingReport potentialDuplicate = mngScheduling.searchByName(session, planifName);
      if (potentialDuplicate != null) {
        throw new DuplicateSchedulingEntryFound("La planification " + planifName + " existe d&eacute;j&agrave;. veuillez saisir un autre nom.");
      }
    }
  }

  private JSONObject successMessage(final AbstractExecutionReport<?, ?> reportImpl) {
    return ServletMessageHelper.successMessage("Le rapport \"" + reportImpl.getReportIdentifier().getReportTitle() + "\" planifié est modifié");
  }
}
