package com.chenyang.nse.bussiness.tools.excel;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.apache.poi.hssf.usermodel.DVConstraint;
import org.apache.poi.hssf.usermodel.HSSFDataValidation;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Name;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellRangeAddressList;

public class ExcelValidation {
   public static void addValidationToSheet(Workbook workbook, Sheet targetSheet, Object[] options, char column, int fromRow, int endRow) {
      String hiddenSheetName = "sheet" + workbook.getNumberOfSheets();
      Sheet optionsSheet = workbook.createSheet(hiddenSheetName);
      workbook.setSheetHidden(workbook.getSheetIndex(hiddenSheetName), true);
      String nameName = column + "_parent";
      int rowIndex = 0;

      for(Object option : options) {
         int columnIndex = 0;
         Row row = optionsSheet.createRow(rowIndex++);
         Cell cell = row.createCell(columnIndex++);
         cell.setCellValue(option.toString());
      }

      createName(workbook, nameName, hiddenSheetName + "!$A$1:$A$" + options.length);
      DVConstraint constraint = DVConstraint.createFormulaListConstraint(nameName);
      CellRangeAddressList regions = new CellRangeAddressList(fromRow, endRow, column - 65, column - 65);
      targetSheet.addValidationData(new HSSFDataValidation(regions, constraint));
   }

   public static void addValidationToSheet(Workbook workbook, Sheet targetSheet, Map<String, List<String>> options, char keyColumn, char valueColumn, int fromRow, int endRow) {
      String hiddenSheetName = "sheet" + workbook.getNumberOfSheets();
      Sheet hiddenSheet = workbook.createSheet(hiddenSheetName);
      List<String> firstLevelItems = new ArrayList();
      int rowIndex = 0;

      for(Map.Entry<String, List<String>> entry : options.entrySet()) {
         String parent = formatNameName((String)entry.getKey());
         firstLevelItems.add(parent);
         List<String> children = (List)entry.getValue();
         int columnIndex = 0;
         Row row = hiddenSheet.createRow(rowIndex++);
         Cell cell = null;

         for(String child : children) {
            cell = row.createCell(columnIndex++);
            cell.setCellValue(child);
         }

         String lastStr = "";
         if (children.size() > 26) {
            lastStr = (char)(65 + children.size() / 26 - 1) + "" + (char)(65 + children.size() % 26 - 1);
         } else {
            lastStr = (char)(65 + children.size() - 1) + "";
         }

         createName(workbook, parent, String.format(hiddenSheetName + "!$A$%s:$%s$%s", rowIndex, lastStr, rowIndex));
      }

      DVConstraint constraint = DVConstraint.createFormulaListConstraint("INDIRECT($" + keyColumn + "1)");
      CellRangeAddressList regions = new CellRangeAddressList(fromRow, endRow, valueColumn - 65, valueColumn - 65);
      targetSheet.addValidationData(new HSSFDataValidation(regions, constraint));
      addValidationToSheet(workbook, targetSheet, firstLevelItems.toArray(), keyColumn, fromRow, endRow);
   }

   public static void addValidationToSheetV1(Workbook workbook, Sheet targetSheet, Map<String, List<String>> options, char keyColumn, char valueColumn, int fromRow, int endRow) {
      String hiddenSheetName = "sheet" + workbook.getNumberOfSheets();
      Sheet hiddenSheet = workbook.createSheet(hiddenSheetName);
      workbook.setSheetHidden(workbook.getSheetIndex(workbook.getSheet(hiddenSheetName)), true);
      List<String> firstLevelItems = new ArrayList();
      int rowIndex = 0;

      for(Map.Entry<String, List<String>> entry : options.entrySet()) {
         String parent = formatNameName((String)entry.getKey());
         firstLevelItems.add(parent);
         int temp = rowIndex;

         for(String child : entry.getValue()) {
            hiddenSheet.createRow(rowIndex++).createCell(0).setCellValue(child);
         }

         createName(workbook, parent, String.format(hiddenSheetName + "!$A$%s:$A$%s", temp + 1, rowIndex));
      }

      DVConstraint constraint = DVConstraint.createFormulaListConstraint("INDIRECT($" + keyColumn + "1)");
      CellRangeAddressList regions = new CellRangeAddressList(fromRow, endRow, valueColumn - 65, valueColumn - 65);
      targetSheet.addValidationData(new HSSFDataValidation(regions, constraint));
      addValidationToSheet(workbook, targetSheet, firstLevelItems.toArray(), keyColumn, fromRow, endRow);
   }

   public static void addAutoMatchValidationToSheet(Workbook workbook, Sheet targetSheet, Map<String, String> keyValues, char keyColumn, char valueColumn, int fromRow, int endRow) {
      String hiddenSheetName = "sheet" + workbook.getNumberOfSheets();
      Sheet hiddenSheet = workbook.createSheet(hiddenSheetName);
      int rowIndex = 0;

      for(Map.Entry<String, String> kv : keyValues.entrySet()) {
         Row totalSheetRow = hiddenSheet.createRow(rowIndex++);
         Cell cell = totalSheetRow.createCell(0);
         cell.setCellValue((String)kv.getKey());
         cell = totalSheetRow.createCell(1);
         cell.setCellValue((String)kv.getValue());
      }

      for(int i = fromRow; i <= endRow; ++i) {
         Row totalSheetRow = targetSheet.getRow(i);
         if (totalSheetRow == null) {
            totalSheetRow = targetSheet.createRow(i);
         }

         Cell cell = totalSheetRow.getCell(valueColumn - 65);
         if (cell == null) {
            cell = totalSheetRow.createCell(valueColumn - 65);
         }

         String keyCell = String.valueOf(keyColumn) + (i + 1);
         String formula = String.format("IF(ISNA(VLOOKUP(%s,%s!A:B,2,0)),\"\",VLOOKUP(%s,%s!A:B,2,0))", keyCell, hiddenSheetName, keyCell, hiddenSheetName);
         cell.setCellFormula(formula);
      }

      addValidationToSheet(workbook, targetSheet, keyValues.keySet().toArray(), keyColumn, fromRow, endRow);
   }

   private static Name createName(Workbook workbook, String nameName, String formula) {
      Name name = workbook.createName();
      name.setNameName(nameName);
      name.setRefersToFormula(formula);
      return name;
   }

   private static void hideTempDataSheet(HSSFWorkbook workbook, int start) {
      for(int i = start; i < workbook.getNumberOfSheets(); ++i) {
         workbook.setSheetHidden(i, true);
      }

   }

   static String formatNameName(String name) {
      name = name.replaceAll(" ", "").replaceAll("-", "_").replaceAll(":", ".");
      if (Character.isDigit(name.charAt(0))) {
         name = "_" + name;
      }

      return name;
   }
}
