package com.qmth.boot.tools.excel;

import com.qmth.boot.tools.excel.enums.ExcelType;
import com.qmth.boot.tools.excel.filter.SheetFilter;
import com.qmth.boot.tools.excel.handler.impl.DataArrayHandler;
import com.qmth.boot.tools.excel.handler.impl.DataMapHandler;
import com.qmth.boot.tools.excel.handler.impl.ObjectHandler;
import com.qmth.boot.tools.excel.listener.ObjectCollector;
import com.qmth.boot.tools.excel.listener.ObjectListener;
import com.qmth.boot.tools.excel.model.DataMap;
import com.qmth.boot.tools.excel.parser.ExcelParser;
import com.qmth.boot.tools.excel.parser.impl.XlsParser;
import com.qmth.boot.tools.excel.parser.impl.XlsxParser;

import java.io.InputStream;
import java.util.List;

public class ExcelReader {

    private ExcelParser parser;

    private InputStream ins;

    private SheetFilter sheetFilter;

    private int columnNameRow;

    /**
     * 初始化带表头的Excel解析工具，默认只读取第一个sheet
     *
     * @param type          文件格式，XLSX或XLS
     * @param ins           文件输入流
     * @param columnNameRow 表头所在行号，0表示第一行
     * @return
     */
    public static ExcelReader create(ExcelType type, InputStream ins, int columnNameRow) {
        return new ExcelReader(type, ins, SheetFilter.first(), columnNameRow);
    }

    /**
     * 初始化带表头的Excel解析工具，读取指定的sheet
     *
     * @param type          文件格式，XLSX或XLS
     * @param ins           文件输入流
     * @param sheetFilter   sheet过滤工具
     * @param columnNameRow 表头所在行号，0表示第一行
     * @return
     */
    public static ExcelReader create(ExcelType type, InputStream ins, SheetFilter sheetFilter, int columnNameRow) {
        return new ExcelReader(type, ins, sheetFilter, columnNameRow);
    }

    private ExcelReader(ExcelType type, InputStream ins, SheetFilter sheetFilter, int columnNameRow) {
        if (ins == null) {
            throw new IllegalArgumentException("Excel InputStream is required");
        }
        if (sheetFilter == null) {
            throw new IllegalArgumentException("Excel SheetFilter is required");
        }
        if (columnNameRow < 0) {
            throw new IllegalArgumentException("Excel column name row should >= 0");
        }
        if (ExcelType.XLSX.equals(type)) {
            this.parser = new XlsxParser();
        } else if (ExcelType.XLS.equals(type)) {
            this.parser = new XlsParser();
        } else {
            throw new IllegalArgumentException("Excel type is required");
        }
        this.ins = ins;
        this.sheetFilter = sheetFilter;
        this.columnNameRow = columnNameRow;
    }

    /**
     * 解析Excel内容为指定类型的对象，只返回转换成功的对象
     *
     * @param objectType 对象类型，使用@ExcelColumn注解修饰字段
     * @return
     * @throws Exception
     */
    public <E> List<E> getObjectList(Class<E> objectType) throws Exception {
        ObjectCollector<E> collector = new ObjectCollector<>();
        readObject(objectType, collector);
        return collector.getObjectList();
    }

    /**
     * !!不推荐使用!!<br/>
     * 解析Excel内容为默认的DataMap对象，返回所有对象
     *
     * @return
     * @throws Exception
     */
    @Deprecated
    public List<DataMap> getDataMapList() throws Exception {
        ObjectCollector<DataMap> collector = new ObjectCollector<>();
        readDataMap(collector);
        return collector.getObjectList();
    }

    /**
     * 解析Excel内容为字符串数组，所有数组长度与表头保持一致
     *
     * @return
     * @throws Exception
     */
    public List<String[]> getDataArrayList() throws Exception {
        ObjectCollector<String[]> collector = new ObjectCollector<>();
        readDataArray(collector);
        return collector.getObjectList();
    }

    /**
     * 遍历Excel内容，转换为指定类型的对象，并输出给指定的监听器
     *
     * @param objectType 对象类型，使用@ExcelColumn注解修饰字段
     * @param listener   指定的对象监听器
     * @throws Exception
     */
    public <E> void readObject(Class<E> objectType, ObjectListener<E> listener) throws Exception {
        parser.parse(ins, sheetFilter, new ObjectHandler<>(objectType, columnNameRow, listener));
    }

    /**
     * !!不推荐使用!!<br/>
     * 遍历Excel内容，转换为默认的DataMap对象，并输出给指定的监听器
     *
     * @param listener 指定的对象监听器
     * @throws Exception
     */
    @Deprecated
    public void readDataMap(ObjectListener<DataMap> listener) throws Exception {
        parser.parse(ins, sheetFilter, new DataMapHandler(columnNameRow, listener));
    }

    /**
     * 遍历Excel内容，转换为字符串数组，并输出给指定的监听器
     *
     * @param listener 指定的对象监听器
     * @throws Exception
     */
    public void readDataArray(ObjectListener<String[]> listener) throws Exception {
        parser.parse(ins, sheetFilter, new DataArrayHandler(columnNameRow, listener));
    }

    /**
     * 获取列名数组，不包含列名的情况下可能返回空
     *
     * @return
     */
    public String[] getColumnNames() {
        return this.parser.getColumnNames();
    }

}
