package cn.com.qmth.examcloud.core.questions.base.excel;

import cn.com.qmth.examcloud.commons.exception.StatusException;
import org.apache.commons.io.IOUtils;
import org.apache.poi.ss.usermodel.*;

import java.io.InputStream;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @author ting.yin
 * @Description: 读取excel
 * @date 2016年8月19日
 */
public class ExcelReader extends ExcelUtils {

    private DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    public ExcelReader(Class<?> dataClass) {
        super(dataClass, true);
    }

    /**
     * @param inputStream 输入流
     * @param handle      单个对象处理器
     * @return 错误信息集合
     */
    public List<ExcelError> reader(InputStream inputStream, ExcelReaderHandle handle) {
        List<ExcelError> excelErrors = new ArrayList<>();
        Workbook wb = null;
        try {
            wb = WorkbookFactory.create(inputStream);
            Sheet sheet = wb.getSheetAt(0);
            for (int i = 1; i <= sheet.getLastRowNum(); i++) {
                Row row = sheet.getRow(i);
                if (row == null) {
                    return excelErrors;
                }
                Object dto = getDataClass().newInstance();
                for (int j = 0; j < this.getColumnSettings().size(); j++) {
                    ColumnSetting columnSetting = this.getColumnSettings().get(j);
                    Cell cell = row.getCell(columnSetting.getIndex());
                    Field field = getDataClass().getDeclaredField(columnSetting.getFieldName());
                    Object obj = convert(cell, field);
                    field.setAccessible(true);
                    field.set(dto, obj);
                }
                ExcelError error = handle.handle(dto);
                if (error != null) {
                    error.setRow(i + 1);
                    excelErrors.add(error);
                }
            }
        } catch (StatusException e) {
            throw e;
        } catch (Exception e) {
            throw new StatusException("580", "EXCEL导入失败", e);
        } finally {
            IOUtils.closeQuietly(wb);
            IOUtils.closeQuietly(inputStream);
        }
        return excelErrors;
    }

    @SuppressWarnings("deprecation")
    private Object convert(Cell cell, Field field) {
        if (cell != null) {
            switch (cell.getCellType()) {
                case Cell.CELL_TYPE_STRING:
                    return cell.getStringCellValue().toString();
                case Cell.CELL_TYPE_BOOLEAN:
                    return String.valueOf(cell.getBooleanCellValue());
                case Cell.CELL_TYPE_NUMERIC:
                    return processNumeric(cell, field);
            }
        }

        return null;
    }

    private Object processNumeric(Cell cell, Field field) {

        if (DateUtil.isCellDateFormatted(cell)) {

            if (field.getType().isAssignableFrom(Date.class)) {
                return cell.getDateCellValue();
            } else {
                return dateFormat.format(cell.getDateCellValue());
            }

        } else {

            if (field.getType().isAssignableFrom(Integer.class)) {

                return (int) cell.getNumericCellValue();

            } else if (field.getType().isAssignableFrom(int.class)) {

                return (int) cell.getNumericCellValue();

            } else if (field.getType().isAssignableFrom(Long.class)) {

                return (long) cell.getNumericCellValue();

            } else if (field.getType().isAssignableFrom(long.class)) {

                return (long) cell.getNumericCellValue();

            } else if (field.getType().isAssignableFrom(Short.class)) {

                return (short) cell.getNumericCellValue();

            } else if (field.getType().isAssignableFrom(short.class)) {

                return (short) cell.getNumericCellValue();

            } else if (field.getType().isAssignableFrom(Float.class)) {

                return (float) cell.getNumericCellValue();

            } else if (field.getType().isAssignableFrom(float.class)) {

                return (float) cell.getNumericCellValue();

            } else if (field.getType().isAssignableFrom(Byte.class)) {

                return (byte) cell.getNumericCellValue();

            } else if (field.getType().isAssignableFrom(byte.class)) {

                return (byte) cell.getNumericCellValue();

            } else if (field.getType().isAssignableFrom(Double.class)) {

                return cell.getNumericCellValue();

            } else if (field.getType().isAssignableFrom(double.class)) {

                return cell.getNumericCellValue();

            } else if (field.getType().isAssignableFrom(String.class)) {

                String numStr = String.valueOf(cell.getNumericCellValue());
                if (numStr.contains("E")) {
                    numStr = new BigDecimal(numStr.trim()).toPlainString();
                }

                if (numStr.endsWith(".0")) {
                    numStr = numStr.substring(0, numStr.indexOf(".0"));
                }

                return numStr;
            } else {
                return cell.getNumericCellValue();
            }
        }
    }

}