/**
  * @param property
  * @param method
  * @param positions
  * @throws Exception used for dynamic grouping, we collect the field/s
  */
 protected void potensialFieldProcessing(
     Property property, Method method, List<Integer> positions, List<String> potentialFields)
     throws KismissException {
   try {
     if (property.innerProperty().length > 0) {
       String[] innerProperties = property.innerProperty();
       String[] divideProperty;
       if (property.position().length != innerProperties.length) {
         String[] errors = new String[2];
         errors[0] = method.getName() + "' '" + String.valueOf(property.position().length);
         errors[1] = String.valueOf(innerProperties.length);
         throw new KismissException(
             ErrorHandler.getInstance()
                 .errorNotValid(errors, ErrorCode.INVALID_NUMBER_OF_POSITION));
       }
       for (int i = 0; i < innerProperties.length; i++) {
         boolean include; // , showDetail;
         try {
           include = property.isInclude()[i];
         } catch (Exception e1) {
           include = property.isInclude()[0];
         }
         //					try {
         //						showDetail = property.isShowInDetail()[i];
         //					} catch (Exception e1) {
         //						showDetail = property.isShowInDetail()[0];
         //					}
         if (include) { // && showDetail){
           String innerProperty = innerProperties[i];
           divideProperty = StringUtils.split(innerProperty, ":");
           if (divideProperty.length != 2) {
             throw new KismissException(
                 ErrorHandler.getInstance()
                     .errorNotValid(innerProperty, ErrorCode.INVALID_INNER_PROPERTY));
           }
           //					try {
           //						Integer.parseInt(divideProperty[2].trim());
           //					} catch (Exception e) {
           //						throw new KismissException(ErrorHandler.getInstance()
           //								.errorNotValid(innerProperty, ErrorCode.INVALID_INNER_PROPERTY_WIDTH));
           //					}
           potentialFields.add(
               MethodUtils.getFieldName(method.getName()) + "." + divideProperty[1]);
           positions.add(property.position()[i]);
         }
       }
     } else {
       if (property.isInclude()[0]) { // && property.isShowInDetail()[0]){
         potentialFields.add(MethodUtils.getFieldName(method.getName()));
         positions.add(property.position()[0]);
       }
     }
   } catch (Exception e) {
     logger.error("[Kismiss:potensialFieldProcessing] Error happended => {}", e.getMessage());
     throw new KismissException(e);
   }
 }
 /**
  * @param calculations
  * @param infos setting calculation position, based on the column that declared to be calculated
  * @throws KismissException
  */
 protected void calculationProcessing(List<CalculationInfo> calculations, List<PropertyInfo> infos)
     throws KismissException {
   try {
     for (CalculationInfo calculation : calculations) {
       boolean notExist = true;
       for (PropertyInfo info : infos) {
         if (calculation.getAttribute().equals(info.getAttributeName())) {
           calculation.setXValue(info.getX());
           calculation.setYValue(info.getY());
           calculation.setWidth(info.getWidth());
           calculation.setHeight(info.getHeight());
           notExist = false;
           break;
         }
       }
       if (notExist) {
         throw new KismissException(
             ErrorHandler.getInstance()
                 .invalid(calculation.getAttribute(), ErrorCode.INVALID_CALCULATION_PROPERTY));
       }
     }
     Collections.sort(calculations, new XComparator());
   } catch (Exception e) {
     logger.error("[Kismiss:calculationProcessing] Error happended => {}", e.getMessage());
     throw new KismissException(e);
   }
 }
  /**
   * @param infos
   * @param columnHeaders this method used for handling column header with multiple rows
   * @throws ReportDataAccessException
   */
  protected void multiRowHeaderHandler(
      List<PropertyInfo> infos, List<PropertyInfo> columnHeaders, Header header)
      throws ReportDataAccessException {
    try {
      // mapParty used for collect the same dependy row
      Map<String, PropertyInfo> mapParty = new HashMap<String, PropertyInfo>();
      // collect the all x position then use the smallest
      Map<String, List<Integer>> xCollection = new HashMap<String, List<Integer>>();

      for (PropertyInfo attributeInfo : infos) {
        if (attributeInfo.isShowInDetail()) {
          PropertyInfo att = (PropertyInfo) attributeInfo.clone();
          att.setFontSize(header.columnHeaderFontSize());
          att.setHeight(header.columnHeaderHeight());
          att.setVerticalAlignment(VerticalAlignment.Middle);
          att.setBgColor(header.columnHeaderColor());
          att.setColorMode(
              StringUtils.isEmpty(header.columnHeaderColor())
                  ? ColorMode.Transparent
                  : ColorMode.Opaque);
          att.setLineWidth(header.lineWidth() > 0 ? header.lineWidth() : att.getLineWidth());
          att.setWhenHeaderHAlignment(
              attributeInfo.equals(HorizontalAlignment.None)
                  ? header.textAlignment()
                  : attributeInfo.getWhenHeaderHAlignment());

          if (!ArrayUtils.isEmpty(attributeInfo.getColumnHierarchy())) {
            String[] multiRow = attributeInfo.getColumnHierarchy();
            // the real field(attribute) position Y changed
            int[] heights = attributeInfo.getHeightPortion();

            if (multiRow.length != heights.length || heights[0] == 0) {
              throw new ReportDataAccessException(
                  ErrorHandler.getInstance()
                      .inconsistenceHierarchy(
                          attributeInfo.getAttributeName(),
                          multiRow.length,
                          heights[0] == 0 ? 0 : heights.length));
            }

            att.setY(ArrayUtilz.sumArray(heights));
            att.setHeight(att.getHeight() - ArrayUtilz.sumArray(attributeInfo.getHeightPortion()));

            int index = 0;
            for (String headerName : multiRow) {
              String bareName = headerName.trim();
              PropertyInfo info =
                  new PropertyInfo(
                      bareName,
                      attributeInfo.getX(),
                      index == 0 ? 0 : ArrayUtilz.sumArray(heights, index - 1),
                      attributeInfo.getWidth(),
                      attributeInfo.getHeightPortion()[index],
                      "key-" + index,
                      bareName,
                      attributeInfo.getColumn(),
                      attributeInfo.isOverFlow(),
                      attributeInfo.isBlankWhenNull(),
                      attributeInfo.getEvaluationTime(),
                      attributeInfo.getHyperlinkType(),
                      attributeInfo.getHyperlinkTarget(),
                      header.columnHeaderFontSize(),
                      attributeInfo.getFont(),
                      header.columnHeaderColor(),
                      StringUtils.isEmpty(header.columnHeaderColor())
                          ? ColorMode.Transparent
                          : ColorMode.Opaque,
                      attributeInfo.getLeftPadding(),
                      attributeInfo.getRightPadding(),
                      attributeInfo.getTopPadding(),
                      attributeInfo.getBottomPadding(),
                      attributeInfo.getLineWidth() > 0
                          ? attributeInfo.getLineWidth()
                          : header.lineWidth(),
                      attributeInfo.getLineStyle(),
                      HorizontalAlignment.Center,
                      VerticalAlignment.Middle,
                      multiRow,
                      attributeInfo.getWidthPortion(),
                      attributeInfo.getHeightPortion(),
                      attributeInfo.getPattern(),
                      attributeInfo.getType(),
                      attributeInfo.isRecordNumber(),
                      attributeInfo.getBorder(),
                      attributeInfo.getBorderColor(),
                      attributeInfo.getPadding(),
                      attributeInfo.getTopBorder(),
                      attributeInfo.getTopBorderColor(),
                      attributeInfo.getLeftBorder(),
                      attributeInfo.getLeftBorderColor(),
                      attributeInfo.getRightBorder(),
                      attributeInfo.getRightBorderColor(),
                      attributeInfo.getBottomBorder(),
                      attributeInfo.getBottomBorderColor(),
                      attributeInfo.getWhenHeaderHAlignment());

              List<Integer> listOfX = xCollection.get(bareName);
              if (listOfX == null) {
                listOfX = new ArrayList<Integer>(); // initial first x value
              }

              listOfX.add(info.getX());

              xCollection.put(bareName, listOfX);

              PropertyInfo compare = mapParty.get(bareName);

              if (compare != null) {
                compare.setWidth(compare.getWidth() + info.getWidth());
                compare.setX(Collections.min(listOfX));
              } else {
                mapParty.put(bareName, info);
              }
              index++;
            }
          }
          columnHeaders.add(att);
        }
      } // mapParty is additional columns hierarchy when multi row/s are defined

      for (Map.Entry<String, PropertyInfo> entry : mapParty.entrySet()) {
        columnHeaders.add(entry.getValue());
      }
    } catch (ReportDataAccessException e) {
      logger.error("[Kismiss:multiRowHeaderHandler] Error happended => {}", e.getMessage());
      throw new ReportDataAccessException(e);
    }
  }