/**
   * This method is going to get the first optionSetId number for the last gouop of produtcs and
   * accessories records
   *
   * @param inputDto
   * @param endTemplateStartPage
   * @return
   */
  private static int getLastFirstOptionSetId(
      LoadEndTemplatePatternInputDto inputDto, String endTemplateStartPage) {
    Integer firstEndProdAccOptionSetId = Integer.valueOf(0);

    for (Map.Entry<String, NavigationPointerDto> entry : inputDto.getMapProdAccRows().entrySet()) {
      String[] arrayNextPage = entry.getValue().getNextPage().split("\\.");
      if (arrayNextPage != null
          && arrayNextPage.length > 0
          && arrayNextPage[0].equals(endTemplateStartPage)) {
        firstEndProdAccOptionSetId = Integer.valueOf(entry.getValue().getPageOptionSetID());
        break;
      }
    }

    return firstEndProdAccOptionSetId;
    /*
    for (Map.Entry<String, OptionSetIdNumber> optionIdIterEntry : inputDto.getMapOptionSetIdNumber().entrySet()) {
        OptionSetIdNumber optionIdDto = optionIdIterEntry.getValue();

        if(optionIdDto != null && optionIdDto.isFirstEndTemplateRow()) {
            firstEndProdAccOptionSetId = optionIdDto.getOptionSetId();
        }
    }
    return firstEndProdAccOptionSetId;
    */
  }
 /**
  * This methos is going to return a String with the page number of the page that belong of the
  * first set of records from the end template option set ids records
  *
  * @param inputDto
  * @return
  */
 private static String getFirstEndTemplatePageNumber(LoadEndTemplatePatternInputDto inputDto) {
   String endTemplateStartPage = "";
   for (Map.Entry<String, OptionSetIdNumber> entry :
       inputDto.getMapOptionSetIdNumber().entrySet()) {
     if (entry.getValue().isFirstEndTemplateRow()) {
       endTemplateStartPage = String.valueOf(entry.getValue().getPageNumber());
       break;
     }
   }
   return endTemplateStartPage;
 }
 /**
  * This method only validate if the most important input properties are not null
  *
  * @param inputDto
  */
 private static void validateInputDto(LoadEndTemplatePatternInputDto inputDto) {
   if (inputDto == null || inputDto.getStatusMessagingList() == null) {
     throw new IllegalArgumentException(
         "UtilityNavigationPointerEnd loadEndTemplatePattern() invalid input object");
   } else if (inputDto.getEndTemplateList() == null
       || inputDto.getLinkToModel() == null
       || inputDto.getSystemDefinitionsParsed() == null
       || inputDto.getMapOptionSetIdNumber() == null
       || inputDto.getMapProdAccRows() == null) {
     UtilityStatusMessage.logNullObjDescription(inputDto);
     throw new IllegalArgumentException(
         "UtilityNavigationPointerEnd loadEndTemplatePattern() invalid input object has some required properties null");
   }
 }
  /**
   * This method is going to take the optionSetIdNumbers objects with the page number is equals or
   * higher that the endTemplateStartPage parameter
   *
   * @param inputDto
   * @param endTemplateStartPage
   * @return
   */
  private static NavigableMap<String, OptionSetIdNumber> getGroupEndOptionSetNumbers(
      LoadEndTemplatePatternInputDto inputDto, String endTemplateStartPage) {
    NavigableMap<String, OptionSetIdNumber> groupEndOptionSetNumbers =
        new TreeMap<String, OptionSetIdNumber>();
    for (Map.Entry<String, OptionSetIdNumber> entry :
        inputDto.getMapOptionSetIdNumber().entrySet()) {
      int comparatorResult =
          entry.getValue().getPageNumber().compareTo(Integer.valueOf(endTemplateStartPage));
      if (comparatorResult >= 0) {
        groupEndOptionSetNumbers.put(entry.getKey(), entry.getValue());
      }
    }

    if (LOG.isDebugEnabled()) {
      LOG.debug(
          "UtilityNavigationPointerEnd loadEndTemplatePattern() groupEndOptionSetNumbers : "
              + groupEndOptionSetNumbers);
    }
    return groupEndOptionSetNumbers;
  }
  /**
   * This method is going to validate the input data on the inputDto object based on the minimal
   * data requirements to run the logic on this class
   *
   * @param inputDto
   * @return
   */
  private static boolean validateInputDtoData(LoadEndTemplatePatternInputDto inputDto) {
    boolean res = true;

    if (!inputDto.getEndTemplateList().isEmpty()) {
      if (!inputDto.getLinkToModel().isEmpty()) {
        String printerType =
            UtilityNavigationPointerEnd.getPrinterType(
                inputDto.getLinkToModel(),
                inputDto.getSystemDefinitionsParsed(),
                inputDto.getStatusMessagingList());
        if (!printerType.isEmpty()) {
          inputDto.setPrinterType(printerType);
          if (inputDto.getEndTemplateList().containsKey(printerType)) {
            if (!inputDto.getEndTemplateList().get(printerType).isEmpty()) {
              if (!inputDto.getMapProdAccRows().isEmpty()) {
                if (LOG.isDebugEnabled()) {
                  LOG.debug(
                      "UtilityNavigationPointerEnd validateInputDtoData() valid inptDto data");
                }
              } else {
                StatusMessage statusMessage =
                    new StatusMessage(
                        Rp3Constants.CODES_MSG.STATUS_MSG_LEVEL_METHOD,
                        MsgConstants.UNPE.STATUS_MSG_WARNING_MAP_PRODUCTS_ACCESORIES_EMPTY,
                        new ArrayList<String>(),
                        Rp3Constants.CODES_MSG.STATUS_MSG_LEVEL_WARNING);
                inputDto.getStatusMessagingList().add(statusMessage);
                res = false;
              }
            } else {
              StatusMessage statusMessage =
                  new StatusMessage(
                      Rp3Constants.CODES_MSG.STATUS_MSG_LEVEL_METHOD,
                      MsgConstants.UNPE.STATUS_MSG_WARNING_ENDTEMPLATE_RECORDS_EMPTY,
                      new ArrayList<String>(),
                      Rp3Constants.CODES_MSG.STATUS_MSG_LEVEL_WARNING);
              inputDto.getStatusMessagingList().add(statusMessage);
              res = false;
            }
          } else {
            StatusMessage statusMessage =
                new StatusMessage(
                    Rp3Constants.CODES_MSG.STATUS_MSG_LEVEL_METHOD,
                    MsgConstants.UAIR.STATUS_MSG_WARNING_TEMPLATE_LIST_NOT_FOND,
                    new String[] {printerType},
                    Rp3Constants.CODES_MSG.STATUS_MSG_LEVEL_WARNING);
            inputDto.getStatusMessagingList().add(statusMessage);
            res = false;
          }
        } else {
          StatusMessage statusMessage =
              new StatusMessage(
                  Rp3Constants.CODES_MSG.STATUS_MSG_LEVEL_METHOD,
                  MsgConstants.UNPE.STATUS_MSG_WARNING_PRINTERTYPE_EMPTY,
                  new ArrayList<String>(),
                  Rp3Constants.CODES_MSG.STATUS_MSG_LEVEL_WARNING);
          inputDto.getStatusMessagingList().add(statusMessage);
          res = false;
        }
      } else {
        StatusMessage statusMessage =
            new StatusMessage(
                Rp3Constants.CODES_MSG.STATUS_MSG_LEVEL_METHOD,
                MsgConstants.UNPE.STATUS_MSG_WARNING_LINKTOMODEL_EMPTY,
                new ArrayList<String>(),
                Rp3Constants.CODES_MSG.STATUS_MSG_LEVEL_WARNING);
        inputDto.getStatusMessagingList().add(statusMessage);
        res = false;
      }
    } else {
      StatusMessage statusMessage =
          new StatusMessage(
              Rp3Constants.CODES_MSG.STATUS_MSG_LEVEL_METHOD,
              MsgConstants.UNPE.STATUS_MSG_WARNING_ENDTEMPLATE_RECORDS_EMPTY,
              new ArrayList<String>(),
              Rp3Constants.CODES_MSG.STATUS_MSG_LEVEL_WARNING);
      inputDto.getStatusMessagingList().add(statusMessage);
      res = false;
    }

    return res;
  }
  /**
   * This method is going to return a Map with the End template records loaded from the external
   * BaseData xml file
   *
   * @param inputDto
   * @return
   */
  public static Map<String, NavigationPointerDto> loadEndTemplatePattern(
      LoadEndTemplatePatternInputDto inputDto) {
    Map<String, NavigationPointerDto> Navigation_BaseDataDto =
        new LinkedHashMap<String, NavigationPointerDto>();

    if (LOG.isDebugEnabled()) {
      LOG.debug(
          "UtilityNavigationPointerEnd loadEndTemplatePattern() inputDto.getMapOptionSetIdNumber() : "
              + inputDto.getMapOptionSetIdNumber());
    }

    UtilityNavigationPointerEnd.validateInputDto(inputDto);

    if (UtilityNavigationPointerEnd.validateInputDtoData(inputDto)) {
      try {
        Map<String, BaseDataDto> listBaseData =
            inputDto.getEndTemplateList().get(inputDto.getPrinterType());

        /**
         * We are going to group all the end BaseData Records on the map of navigateEndDataMap,
         * using the page xml node data as a key and as a value the list of baseData records
         */
        Map<String, Map<String, BaseDataDto>> navigateEndDataMap =
            UtilityNavigationPointerEnd.groupLastRecords(listBaseData);

        String endTemplateStartPage =
            UtilityNavigationPointerEnd.getFirstEndTemplatePageNumber(inputDto);
        int countInitOptionSetId =
            UtilityNavigationPointerEnd.getLastFirstOptionSetId(inputDto, endTemplateStartPage);
        int lastEndProdAccOptionSetId =
            inputDto.getMapOptionSetIdNumber().get(endTemplateStartPage).getOptionSetId();

        /*
                        if (LOG.isDebugEnabled()) {
                            LOG.debug("UtilityNavigationPointerEnd loadEndTemplatePattern() endTemplateStartPage : " + endTemplateStartPage);
                            LOG.debug("UtilityNavigationPointerEnd loadEndTemplatePattern() countInitOptionSetId : " + countInitOptionSetId);
                            LOG.debug("UtilityNavigationPointerEnd loadEndTemplatePattern() navigateEndDataMap.size : " + navigateEndDataMap.size());
                            LOG.debug("UtilityNavigationPointerEnd loadEndTemplatePattern() lastEndProdAccOptionSetId : " + lastEndProdAccOptionSetId);
                        }
        */
        NavigableMap<String, OptionSetIdNumber> groupEndOptionSetNumbers =
            UtilityNavigationPointerEnd.getGroupEndOptionSetNumbers(inputDto, endTemplateStartPage);

        int procOptionSetIdProcInit =
            inputDto.getMapOptionSetIdNumber().get("proc").getOptionSetId();

        while (countInitOptionSetId <= lastEndProdAccOptionSetId) {

          for (Map.Entry<String, OptionSetIdNumber> entryOptionSetId :
              groupEndOptionSetNumbers.entrySet()) {

            Map<String, String> mapOptionSetIdToUpdate = new LinkedHashMap<String, String>();
            boolean panelCreated = false;

            if (LOG.isDebugEnabled()) {
              LOG.debug(
                  "UtilityNavigationPointerEnd loadEndTemplatePattern() entryOptionSetId.getKey() : "
                      + entryOptionSetId.getKey());
              LOG.debug(
                  "UtilityNavigationPointerEnd loadEndTemplatePattern() navigateEndDataMap : "
                      + navigateEndDataMap);
            }

            for (Map.Entry<String, BaseDataDto> baseDataDto :
                navigateEndDataMap.get(entryOptionSetId.getKey()).entrySet()) {
              String nextPageValue = "";

              NavigationPointerDto navigationPointerDto = new NavigationPointerDto();
              navigationPointerDto.setDatasource("" + Rp3Constants.CODES.END_TEMPLATE_DATA_SOURCE);
              navigationPointerDto.setDataSourceRefId(baseDataDto.getKey());
              navigationPointerDto.setPage(String.valueOf(entryOptionSetId.getKey()));
              navigationPointerDto.setStreamId(inputDto.getStreamId());

              if (!"proc".equalsIgnoreCase(entryOptionSetId.getKey())) {

                Map.Entry<String, OptionSetIdNumber> nextOptionSetIdPanelEntry =
                    groupEndOptionSetNumbers.higherEntry(entryOptionSetId.getKey());
                if (nextOptionSetIdPanelEntry != null
                    && !"proc".equalsIgnoreCase(nextOptionSetIdPanelEntry.getKey())) {
                  if (nextOptionSetIdPanelEntry != null && panelCreated == false) {
                    nextOptionSetIdPanelEntry.getValue().incrementOptionSetIdByOne();
                    nextPageValue =
                        nextOptionSetIdPanelEntry.getKey()
                            + "."
                            + nextOptionSetIdPanelEntry.getValue().getOptionSetId();
                    panelCreated = true;
                  } else if (nextOptionSetIdPanelEntry == null) {
                    nextPageValue = baseDataDto.getValue().getNextPanel();
                  } else if (panelCreated) {
                    nextPageValue =
                        nextOptionSetIdPanelEntry.getKey()
                            + "."
                            + nextOptionSetIdPanelEntry.getValue().getOptionSetId();
                  }
                } else if (nextOptionSetIdPanelEntry != null
                    && "proc".equalsIgnoreCase(nextOptionSetIdPanelEntry.getKey())) {
                  // We need to increment by one each proc number
                  nextOptionSetIdPanelEntry.getValue().incrementOptionSetIdByOne();
                  nextPageValue =
                      nextOptionSetIdPanelEntry.getKey()
                          + "."
                          + nextOptionSetIdPanelEntry.getValue().getOptionSetId();
                }

                navigationPointerDto.setPageOptionSetID(String.valueOf(countInitOptionSetId));
              } else {
                String pageToCheck =
                    baseDataDto.getValue().getPage()
                        + "."
                        + baseDataDto.getValue().getPageOptionSetID();
                if (!mapOptionSetIdToUpdate.containsKey(pageToCheck)) {
                  mapOptionSetIdToUpdate.put(
                      pageToCheck, String.valueOf(++procOptionSetIdProcInit));
                }

                navigationPointerDto.setPageOptionSetID(mapOptionSetIdToUpdate.get(pageToCheck));
                nextPageValue = baseDataDto.getValue().getNextPanel();
              }

              navigationPointerDto.setNextPage(nextPageValue);
              navigationPointerDto.setPrinterType(inputDto.getPrinterType());

              navigationPointerDto.inputType = baseDataDto.getValue().getHtmlInputType();
              navigationPointerDto.webFriendlyName = baseDataDto.getValue().getLabel();
              Navigation_BaseDataDto.put(UtilityRefIdGenerator.buildRefId(), navigationPointerDto);
            }
          }
          countInitOptionSetId++;
        }
      } catch (RuntimeException re) {
        LOG.error("Error UtilityTemplateEndPattern getEndTemplateMap() " + re.getMessage(), re);
        StatusMessage statusMessage =
            new StatusMessage(
                Rp3Constants.CODES_MSG.STATUS_MSG_LEVEL_METHOD.toString(),
                MsgConstants.UNPE.STATUS_MSG_ERROR.toString(),
                Arrays.asList(re.getMessage()),
                Integer.valueOf(Rp3Constants.CODES_MSG.STATUS_MSG_LEVEL_EXCEPTION.toString()));
        inputDto.getStatusMessagingList().add(statusMessage);
      }
    }

    return Navigation_BaseDataDto;
  }