@Override
  public void onQuery(Query query) throws DeadlineExceededException {
    JSONObject parameters = query.getParameters();
    Object monthId = parameters.opt("monthid");
    Object yearId = parameters.opt("yearid");
    if (monthId == null || yearId == null) {
      throw new RuntimeException("Please Select Month Year.");
    }

    String yearName =
        EmployeeSalaryGenerationServlet.getYearName((long) Translator.integerValue(yearId));
    String fromDateString = yearName + "-" + monthId + "-1";
    Date fromDate = Translator.dateValue(fromDateString);
    Date toDate = DataTypeUtilities.getMonthLastDate(fromDate);
    String toDateString = EmployeeSalaryGenerationServlet.getDateInString(toDate);
    String filter = "date>='" + fromDateString + "' AND date<='" + toDateString + "'";
    query.addFilter(filter);

    JSONArray filters = query.getFilters();
    LogUtility.writeLog("parameters >> " + parameters + " << filters >> " + filters);
  }
  public JSONArray populateEmployeeBalanceLeavesDARCL(Object employeeid, Object requestdate) {

    String applicationVersionId =
        ApiProxy.getCurrentEnvironment()
            .getVersionId()
            .substring(0, ApiProxy.getCurrentEnvironment().getVersionId().indexOf("."));
    if (applicationVersionId.equalsIgnoreCase("testviews")) {
      JSONArray balanceLeaveArray =
          com.applane.resourceoriented.hris.BalanceLeaves.employeeBalanceLeave(
              employeeid, requestdate);
      return balanceLeaveArray;
    } else {
      try {
        // GET EMPLOYEEID FROM KEY
        if ((employeeid instanceof JSONArray)) {
          employeeid = ((JSONArray) employeeid).getJSONObject(0).get(Data.Query.KEY);
        }

        if ((employeeid instanceof JSONObject)) {
          employeeid = ((JSONObject) employeeid).get(Data.Query.KEY);
        }

        JSONArray employeeLeavePolicyArray = getEmployeeLeavePolicyId(employeeid);
        if (employeeLeavePolicyArray != null && employeeLeavePolicyArray.length() > 0) {
          Object leavePolicyId = employeeLeavePolicyArray.getJSONObject(0).opt("leavepolicyid");
          Object leavePolicyFromDate =
              employeeLeavePolicyArray.getJSONObject(0).opt("leavepolicyid.fromdate");
          Object leavePolicyToDate =
              employeeLeavePolicyArray.getJSONObject(0).opt("leavepolicyid.todate");
          JSONArray employeeLeaveRuleArray = getEmployeeLeaveRule(employeeid, leavePolicyId);
          if (employeeLeaveRuleArray != null && employeeLeaveRuleArray.length() > 0) {
            JSONArray categoryTypeArray = new JSONArray();
            for (int counter = 0; counter < employeeLeaveRuleArray.length(); counter++) {
              Object leaveTypeId = employeeLeaveRuleArray.getJSONObject(counter).opt("leavetypeid");
              Object leaveTypeName =
                  employeeLeaveRuleArray.getJSONObject(counter).opt("leavetypeid.name");
              Object openingBalance =
                  employeeLeaveRuleArray.getJSONObject(counter).opt("openingbalance");
              Object assignedLeave =
                  employeeLeaveRuleArray.getJSONObject(counter).opt("assignedleaves");
              double totalMonthBetweenFromDateAneToDate =
                  getTotalMonthBetweenFromDateAneToDate(
                      Translator.dateValue(leavePolicyFromDate),
                      Translator.dateValue(leavePolicyToDate));
              double takenLeaves =
                  calculateLeaveTaken(
                      employeeid, leaveTypeId, leavePolicyFromDate, leavePolicyToDate);
              double totalAssignedLeaves =
                  Translator.doubleValue(openingBalance)
                      + (Translator.doubleValue(assignedLeave)
                          / totalMonthBetweenFromDateAneToDate);
              double balance = totalAssignedLeaves - takenLeaves;

              JSONObject leaveTypeObject = new JSONObject();
              JSONObject typeobject = new JSONObject();

              leaveTypeObject.put("__key__", leaveTypeId);
              leaveTypeObject.put("name", leaveTypeName);

              typeobject.put("leavetypeid", leaveTypeObject);
              typeobject.put("totalleaves", totalAssignedLeaves);
              typeobject.put("takenleaves", takenLeaves);
              String balanceMessage = "";
              if (balance >= 0) {
                balanceMessage = new DecimalFormat("0.#").format(balance) + " leaves pending";
              } else {
                balanceMessage =
                    new DecimalFormat("0.#").format((balance * (-1.0))) + " leaves overdue";
              }
              typeobject.put("balanceleaves", balanceMessage);
              categoryTypeArray.put(counter, typeobject);
            }
            return categoryTypeArray;
          }
        }

      } catch (Exception e) {
        LogUtility.writeLog(
            "BalanceLeaves >> populateEmployeeBalanceLeavesDARCL Exception  >> : ["
                + ExceptionUtils.getExceptionTraceMessage(getClass().getName(), e)
                + "]");
        throw new RuntimeException("Some Error Occured while Generating Leave Balance");
      }
    }
    return null;
  }
  @Override
  public void onResult(Result result) throws DeadlineExceededException {
    try {
      JSONArray records = result.getRecords();
      JSONObject parameters = result.getQuery().getParameters();

      Object monthId = parameters.opt("monthid");
      Object yearId = parameters.opt("yearid");

      LogUtility.writeLog("records >> " + records);
      Map<Integer, Double> resourceRevenewDetails = new HashMap<Integer, Double>();
      Map<Integer, String[]> resourceNameMap = new HashMap<Integer, String[]>();
      List<Integer> list = new ArrayList<Integer>();
      if (records != null) {
        for (int counter = 0; counter < records.length(); counter++) {
          JSONObject engagementDetailsObject;
          engagementDetailsObject = records.getJSONObject(counter);
          int resourceId = Translator.integerValue(engagementDetailsObject.opt("resourceid"));
          String resourceName =
              Translator.stringValue(engagementDetailsObject.opt("resourceid.name"));
          String employeeCode =
              Translator.stringValue(engagementDetailsObject.opt("resourceid.employeecode"));
          double rate = Translator.doubleValue(engagementDetailsObject.opt("deliveryid.rate"));
          double billableEfforts =
              Translator.doubleValue(engagementDetailsObject.opt("billableefforts"));
          double amount = rate * billableEfforts;
          if (!resourceNameMap.containsKey(resourceId)) {
            resourceNameMap.put(resourceId, new String[] {resourceName, employeeCode});
          }
          if (resourceRevenewDetails.containsKey(resourceId)) {
            amount += resourceRevenewDetails.get(resourceId);
          }
          resourceRevenewDetails.put(resourceId, amount);
          if (!list.contains(resourceId)) {
            list.add(resourceId);
          }
        }
        String listString = list.toString();
        if (listString.length() > 0) {
          listString = listString.substring(1, listString.length() - 1);
          HashMap<Integer, Double> employeeSalaryPaidDetsils =
              getEmployeeSalaryPaidDetsils(listString, monthId, yearId);
          JSONArray array = new JSONArray();
          for (Integer resourceId : resourceNameMap.keySet()) {
            String[] employeeDetails = resourceNameMap.get(resourceId);
            double paidSalary =
                employeeSalaryPaidDetsils.get(resourceId) == null
                    ? 0.0
                    : employeeSalaryPaidDetsils.get(resourceId);
            double revenew = resourceRevenewDetails.get(resourceId);
            JSONObject details = new JSONObject();
            details.put("resourceName", employeeDetails[0]);
            details.put("resourceCode", employeeDetails[1]);
            details.put("paidSalary", new DecimalFormat("#.##").format(paidSalary));
            details.put("revenew", new DecimalFormat("#.##").format(revenew));
            if (paidSalary < revenew) {
              details.put("profit", new DecimalFormat("#.##").format(revenew - paidSalary));
            } else {
              details.put("loss", new DecimalFormat("#.##").format(paidSalary - revenew));
            }
            array.put(details);
          }
          records.put(new JSONObject().put("revenewReport", array));
        }
      }
    } catch (JSONException e) {
      String trace = ExceptionUtils.getExceptionTraceMessage(getClass().getName(), e);
      LogUtility.writeLog("RevenewLossBusinessLogic >>  Exception >> Trace >> " + trace);
      throw new BusinessLogicException("Some Unknown Error Occured Please Contact To Admin.");
    }
  }
  private void generateEmployeePerformanceReport(WritableWorkbook workbook, String key)
      throws Exception {
    if (key.length() > 2) {
      WritableFont headerfont = new WritableFont(WritableFont.ARIAL, 12, WritableFont.NO_BOLD);
      WritableCellFormat headerFormat = new WritableCellFormat(headerfont);
      headerFormat.setAlignment(Alignment.CENTRE);

      WritableFont feemergefont = new WritableFont(WritableFont.ARIAL, 13, WritableFont.BOLD);
      WritableCellFormat feemergeFormat = new WritableCellFormat(feemergefont);
      feemergeFormat.setAlignment(Alignment.CENTRE);
      feemergeFormat.setBackground(Colour.GRAY_25);
      feemergeFormat.setBorder(Border.ALL, BorderLineStyle.THIN);

      WritableFont font = new WritableFont(WritableFont.ARIAL, 10, WritableFont.BOLD);
      WritableCellFormat numbercellformat = new WritableCellFormat(NumberFormats.FLOAT);
      numbercellformat.setFont(font);
      numbercellformat.setBorder(Border.ALL, BorderLineStyle.THIN);

      key = key.substring(1, key.length() - 1);

      WritableSheet sheet = workbook.createSheet("Report For Selected Employees", 0);

      JSONArray employeeTourRecords = getEmployeeTourRecords(key);

      HashMap<Integer, HashMap<Integer, Object[]>> employeeTourDetailsMap =
          new HashMap<Integer, HashMap<Integer, Object[]>>();
      HashMap<Integer, HashMap<Integer, Object[]>> employeeTourRequestAndDetailsMap =
          new HashMap<Integer, HashMap<Integer, Object[]>>();
      putRecordsIntoMap(
          employeeTourDetailsMap, employeeTourRecords, employeeTourRequestAndDetailsMap);
      int row = 5;
      int column = 0;
      sheet.mergeCells(column + 2, row - 4, column + 8, row - 4);

      putHeaderDefault(
          feemergeFormat,
          sheet,
          "Employee Tour Expense Sheet For Selected Employees",
          row - 4,
          column + 2);

      putHeaderDefault(feemergeFormat, sheet, "S. No.", row, column++);
      putHeaderDefault(feemergeFormat, sheet, "Employee Code", row, column++);
      putHeaderDefault(feemergeFormat, sheet, "Employee Name", row, column++);
      putHeaderDefault(feemergeFormat, sheet, "Tour Code", row, column++);
      putHeaderDefault(feemergeFormat, sheet, "Advance", row, column++);
      putHeaderDefault(feemergeFormat, sheet, "City", row, column++);
      putHeaderDefault(feemergeFormat, sheet, "From Date", row, column++);
      putHeaderDefault(feemergeFormat, sheet, "To Date", row, column++);
      putHeaderDefault(feemergeFormat, sheet, "Expected Amount", row, column++);
      putHeaderDefault(feemergeFormat, sheet, "Actual Amount", row, column++);

      int serNo = 0;
      for (Integer employeeId : employeeTourRequestAndDetailsMap.keySet()) {
        HashMap<Integer, Object[]> tourRequestDetailsMap =
            employeeTourRequestAndDetailsMap.get(employeeId);
        for (Integer tourId : tourRequestDetailsMap.keySet()) {
          Object[] details = tourRequestDetailsMap.get(tourId);
          if (details != null) {
            column = 0;
            serNo++;
            row++;
            // int tourId = Translator.integerValue(details[0]);
            Object employeeName = details[1];
            Object employeeCode = details[2];
            Object advance = details[3];
            Object departOn = details[4];
            Object ariveOn = details[5];
            Object tourCode = details[6];
            Object totalEstimatedAmount = details[7];
            Object totalActualAmount = details[8];
            putHeaderDefault(headerFormat, sheet, serNo, row, column++);
            putHeaderDefault(headerFormat, sheet, employeeCode, row, column++);
            putHeaderDefault(headerFormat, sheet, employeeName, row, column++);
            putHeaderDefault(headerFormat, sheet, tourCode, row, column++);
            putHeader(numbercellformat, sheet, Translator.doubleValue(advance), row, column++);
            putHeaderDefault(headerFormat, sheet, "", row, column++);
            putHeaderDefault(headerFormat, sheet, departOn, row, column++);
            putHeaderDefault(headerFormat, sheet, ariveOn, row, column++);
            putHeaderDefault(headerFormat, sheet, "", row, column++);
            putHeaderDefault(headerFormat, sheet, "", row, column++);

            HashMap<Integer, Object[]> tourDetailsMap = employeeTourDetailsMap.get(tourId);
            if (tourDetailsMap != null) {
              for (Integer tourDetailKeys : tourDetailsMap.keySet()) {
                details = tourDetailsMap.get(tourDetailKeys);
                // details[0] = fromDate;
                // details[1] = toDate;
                // details[2] = estmateAmount;
                // details[3] = actualAmount;
                // details[4] = cityName;
                column = 5;
                row++;
                putHeaderDefault(headerFormat, sheet, details[4], row, column++);
                putHeaderDefault(headerFormat, sheet, details[0], row, column++);
                putHeaderDefault(headerFormat, sheet, details[1], row, column++);
                putHeader(
                    numbercellformat, sheet, Translator.doubleValue(details[2]), row, column++);
                putHeader(
                    numbercellformat, sheet, Translator.doubleValue(details[3]), row, column++);
              }
              column = 7;
              row++;
              putHeaderDefault(headerFormat, sheet, "Total", row, column++);
              putHeader(
                  numbercellformat,
                  sheet,
                  Translator.doubleValue(totalEstimatedAmount),
                  row,
                  column++);
              putHeader(
                  numbercellformat,
                  sheet,
                  Translator.doubleValue(totalActualAmount),
                  row,
                  column++);
            }
          }
        }
      }
      workbook.write();
      workbook.close();
    }
  }
  private void putRecordsIntoMap(
      HashMap<Integer, HashMap<Integer, Object[]>> employeeTourDetailsMap,
      JSONArray employeeTourRequestRecords,
      HashMap<Integer, HashMap<Integer, Object[]>> employeeTourRequestAndDetailsMap)
      throws JSONException {
    for (int counter = 0; counter < employeeTourRequestRecords.length(); counter++) {
      int tourId =
          Translator.integerValue(
              employeeTourRequestRecords.getJSONObject(counter).opt(Updates.KEY));
      int employeeId =
          Translator.integerValue(
              employeeTourRequestRecords.getJSONObject(counter).opt("employeeid"));
      String employeeCode =
          Translator.stringValue(
              employeeTourRequestRecords.getJSONObject(counter).opt("employeeid.employeecode"));
      String employeeName =
          Translator.stringValue(
              employeeTourRequestRecords.getJSONObject(counter).opt("employeeid.name"));

      Object departOn = employeeTourRequestRecords.getJSONObject(counter).opt("startdate");
      Object ariveOn = employeeTourRequestRecords.getJSONObject(counter).opt("enddate");

      Object advance =
          employeeTourRequestRecords.getJSONObject(counter).opt("advanceamount_amount");
      Object tourCode = employeeTourRequestRecords.getJSONObject(counter).opt("tourcode");

      Object employeeDetailsObject =
          employeeTourRequestRecords.getJSONObject(counter).opt("hris_tourdetails");

      if (departOn != null) {
        String fromDateString = "" + departOn;
        if (fromDateString.contains(" ")) {
          departOn = fromDateString.split(" ")[0];
        }
      }
      if (ariveOn != null) {
        String toDateString = "" + ariveOn;
        if (toDateString.contains(" ")) {
          ariveOn = toDateString.split(" ")[0];
        }
      }

      if (employeeId != 0) {
        Object[] details = new Object[9];
        details[0] = tourId;
        details[1] = employeeName;
        details[2] = employeeCode;
        details[3] = advance;
        details[4] = departOn;
        details[5] = ariveOn;
        details[6] = tourCode;
        HashMap<Integer, Object[]> tourRequestDetails = new HashMap<Integer, Object[]>();
        if (employeeTourRequestAndDetailsMap.containsKey(employeeId)) {
          tourRequestDetails = employeeTourRequestAndDetailsMap.get(employeeId);
        }
        tourRequestDetails.put(tourId, details);
        employeeTourRequestAndDetailsMap.put(employeeId, tourRequestDetails);

        HashMap<Integer, Object[]> tourDetails = new HashMap<Integer, Object[]>();
        JSONArray employeeRecords = new JSONArray();
        if (employeeDetailsObject != null && employeeDetailsObject instanceof JSONArray) {
          employeeRecords = (JSONArray) employeeDetailsObject;
        } else if (employeeDetailsObject != null && employeeDetailsObject instanceof JSONObject) {
          employeeRecords = new JSONArray().put(employeeDetailsObject);
        }
        if (employeeRecords != null && employeeRecords.length() > 0) {
          double totalEstimatedAmount = 0.0;
          double totalActualAmount = 0.0;
          for (int tourDetailCounter = 0;
              tourDetailCounter < employeeRecords.length();
              tourDetailCounter++) {
            Object[] nestedTourDetails = new Object[5];
            int tourDatailId =
                Translator.integerValue(
                    employeeRecords.getJSONObject(tourDetailCounter).opt(Updates.KEY));
            Object fromDate = employeeRecords.getJSONObject(tourDetailCounter).opt("fromdate");
            Object toDate = employeeRecords.getJSONObject(tourDetailCounter).opt("todate");

            double estmateAmount =
                Translator.doubleValue(
                    employeeRecords.getJSONObject(tourDetailCounter).opt("expectedamount_amount"));
            double actualAmount =
                Translator.doubleValue(
                    employeeRecords.getJSONObject(tourDetailCounter).opt("actual_amount_amount"));
            Object cityName = employeeRecords.getJSONObject(tourDetailCounter).opt("cityid.name");
            totalEstimatedAmount += estmateAmount;
            totalActualAmount += actualAmount;
            if (fromDate != null) {
              String fromDateString = "" + fromDate;
              if (fromDateString.contains(" ")) {
                fromDate = fromDateString.split(" ")[0];
              }
            }
            if (toDate != null) {
              String toDateString = "" + toDate;
              if (toDateString.contains(" ")) {
                toDate = toDateString.split(" ")[0];
              }
            }
            nestedTourDetails[0] = fromDate;
            nestedTourDetails[1] = toDate;
            nestedTourDetails[2] = estmateAmount;
            nestedTourDetails[3] = actualAmount;
            nestedTourDetails[4] = cityName;
            tourDetails.put(tourDatailId, nestedTourDetails);
          }
          details[7] = totalEstimatedAmount;
          details[8] = totalActualAmount;
        }
        employeeTourDetailsMap.put(tourId, tourDetails);
      }
    }
  }