/**
  * ************************************************************************ Start Database Process
  *
  * @param ProcedureName PL/SQL procedure name
  * @return true if success
  */
 private boolean startDBProcess(String ProcedureName) {
   //  execute on this thread/connection
   log.fine(ProcedureName + "(" + m_pi.getAD_PInstance_ID() + ")");
   String sql = "{call " + ProcedureName + "(?)}";
   try {
     CallableStatement cstmt = DB.prepareCall(sql, ResultSet.CONCUR_UPDATABLE, null); // 	ro??
     cstmt.setInt(1, m_pi.getAD_PInstance_ID());
     cstmt.executeUpdate();
     cstmt.close();
   } catch (Exception e) {
     log.log(Level.SEVERE, sql, e);
     m_pi.setSummary(Msg.getMsg(m_wscctx, "ProcessRunError") + " " + e.getLocalizedMessage());
     m_pi.setError(true);
     return false;
   }
   //	log.fine(Log.l4_Data, "ProcessCtl.startProcess - done");
   return true;
 } //  startDBProcess
  /**
   * Async Process - Do it all. <code>
   * - Get Instance ID
   * - Get Parameters
   * - execute (lock - start process - unlock)
   *  </code> Creates a ProcessCtl instance, which calls lockUI and unlockUI if parent is a
   * ASyncProcess <br>
   * Called from ProcessCtl.startProcess, ProcessDialog.actionPerformed, APanel.cmd_print,
   * APanel.actionButton, VPaySelect.cmd_generate
   *
   * @param parent ASyncProcess & Container
   * @param WindowNo window no
   * @param pi ProcessInfo process info
   * @param trx Transaction
   * @return worker started ProcessCtl instance or null for workflow
   */
  public static WProcessCtl process(
      Object parent, int WindowNo, ProcessInfo pi, Trx trx, HttpServletRequest request) {
    log.fine("WindowNo=" + WindowNo + " - " + pi);
    WebSessionCtx wsc = WebSessionCtx.get(request);
    MPInstance instance = new MPInstance(wsc.ctx, pi.getAD_Process_ID(), pi.getRecord_ID());

    if (!instance.save()) {
      pi.setSummary(Msg.getMsg(wsc.ctx, "ProcessNoInstance"));
      pi.setError(true);
      return null;
    }
    pi.setAD_PInstance_ID(instance.getAD_PInstance_ID());

    //	Get Parameters (Dialog)
    /**
     * ProcessParameter para = new ProcessParameter (Env.getFrame((Container)parent), WindowNo, pi);
     * if (para.initDialog()) { para.setVisible(true); if (!para.isOK()) { pi.setSummary
     * (Msg.getMsg(Env.getCtx(), "ProcessCancelled")); pi.setError (true); return null; } }
     */
    //	execute
    WProcessCtl worker = new WProcessCtl(parent, pi, trx, wsc.ctx);
    worker.start(); // 	MUST be start!
    return worker;
  } //	execute
  /**
   * Execute Process Instance and Lock UI. Calls lockUI and unlockUI if parent is a ASyncProcess
   *
   * <pre>
   * 	- Get Process Information
   *      - Call Class
   * 	- Submit SQL Procedure
   * 	- Run SQL Procedure
   * </pre>
   */
  public void run() {
    log.fine("AD_PInstance_ID=" + m_pi.getAD_PInstance_ID() + ", Record_ID=" + m_pi.getRecord_ID());

    //  Lock
    // lock();
    //	try {System.out.println(">> sleeping ..");sleep(20000);System.out.println(".. sleeping <<");}
    // catch (Exception e) {}

    //	Get Process Information: Name, Procedure Name, ClassName, IsReport, IsDirectPrint
    String ProcedureName = "";
    int AD_ReportView_ID = 0;
    int AD_Workflow_ID = 0;
    boolean IsReport = false;
    boolean IsDirectPrint = false;
    //
    String sql =
        "SELECT p.Name, p.ProcedureName,p.ClassName, p.AD_Process_ID," //	1..4
            + " p.isReport,p.IsDirectPrint,p.AD_ReportView_ID,p.AD_Workflow_ID," //	5..8
            + " CASE WHEN COALESCE(p.Statistic_Count,0)=0 THEN 0 ELSE p.Statistic_Seconds/p.Statistic_Count END CASE,"
            + " p.IsServerProcess "
            + "FROM AD_Process p"
            + " INNER JOIN AD_PInstance i ON (p.AD_Process_ID=i.AD_Process_ID) "
            + "WHERE p.IsActive='Y'"
            + " AND i.AD_PInstance_ID=?";
    if (!Env.isBaseLanguage(m_wscctx, "AD_Process"))
      sql =
          "SELECT t.Name, p.ProcedureName,p.ClassName, p.AD_Process_ID," //	1..4
              + " p.isReport, p.IsDirectPrint,p.AD_ReportView_ID,p.AD_Workflow_ID," //	5..8
              + " CASE WHEN COALESCE(p.Statistic_Count,0)=0 THEN 0 ELSE p.Statistic_Seconds/p.Statistic_Count END CASE,"
              + " p.IsServerProcess "
              + "FROM AD_Process p"
              + " INNER JOIN AD_PInstance i ON (p.AD_Process_ID=i.AD_Process_ID) "
              + " INNER JOIN AD_Process_Trl t ON (p.AD_Process_ID=t.AD_Process_ID"
              + " AND t.AD_Language='"
              + Env.getAD_Language(m_wscctx)
              + "') "
              + "WHERE p.IsActive='Y'"
              + " AND i.AD_PInstance_ID=?";
    //
    try {
      PreparedStatement pstmt =
          DB.prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, null);
      pstmt.setInt(1, m_pi.getAD_PInstance_ID());
      ResultSet rs = pstmt.executeQuery();
      if (rs.next()) {
        m_pi.setTitle(rs.getString(1));
        if (m_waiting != null) m_waiting.setTitle(m_pi.getTitle());
        ProcedureName = rs.getString(2);
        m_pi.setClassName(rs.getString(3));
        m_pi.setAD_Process_ID(rs.getInt(4));
        //	Report
        if ("Y".equals(rs.getString(5))) {
          IsReport = true;
          if ("Y".equals(rs.getString(6)) && !Ini.isPropertyBool(Ini.P_PRINTPREVIEW))
            IsDirectPrint = true;
        }
        AD_ReportView_ID = rs.getInt(7);
        AD_Workflow_ID = rs.getInt(8);
        //
        int estimate = rs.getInt(9);
        if (estimate != 0) {
          m_pi.setEstSeconds(estimate + 1); //  admin overhead
          if (m_waiting != null) m_waiting.setTimerEstimate(m_pi.getEstSeconds());
        }
        m_IsServerProcess = "Y".equals(rs.getString(10));
      } else log.log(Level.SEVERE, "No AD_PInstance_ID=" + m_pi.getAD_PInstance_ID());
      rs.close();
      pstmt.close();
    } catch (SQLException e) {
      m_pi.setSummary(
          Msg.getMsg(m_wscctx, "ProcessNoProcedure") + " " + e.getLocalizedMessage(), true);
      // unlock();
      log.log(Level.SEVERE, "run", e);
      return;
    }

    //  No PL/SQL Procedure
    if (ProcedureName == null) ProcedureName = "";

    /** ******************************************************************** Workflow */
    if (AD_Workflow_ID > 0) {
      startWorkflow(AD_Workflow_ID);
      // unlock();
      return;
    }

    /** ******************************************************************** Start Optional Class */
    if (m_pi.getClassName() != null) {
      //	Run Class
      if (!startProcess()) {
        // unlock();
        return;
      }

      //  No Optional SQL procedure ... done
      if (!IsReport && ProcedureName.length() == 0) {
        // unlock ();
        return;
      }
      //  No Optional Report ... done
      if (IsReport && AD_ReportView_ID == 0) {
        // unlock ();
        return;
      }
    }

    //  If not a report, we need a prodedure name
    if (!IsReport && ProcedureName.length() == 0) {
      m_pi.setSummary(Msg.getMsg(m_wscctx, "ProcessNoProcedure"), true);
      // unlock();
      return;
    }

    /** ******************************************************************** Report submission */
    if (IsReport) {
      //	Optional Pre-Report Process
      if (ProcedureName.length() > 0) {
        if (!startDBProcess(ProcedureName)) {
          // unlock();
          return;
        }
      } //	Pre-Report

      //	Start Report	-----------------------------------------------
      boolean ok = ReportCtl.start(m_pi, IsDirectPrint);
      m_pi.setSummary("Report", !ok);
      // unlock ();
    }
    /** ******************************************************************** Process submission */
    else {
      if (!startDBProcess(ProcedureName)) {
        // unlock();
        return;
      }
      //	Success - getResult
      ProcessInfoUtil.setSummaryFromDB(m_pi);
      // unlock();
    } //	*** Process submission ***
    //	log.fine(Log.l3_Util, "ProcessCtl.run - done");
  } //  run