package itn.let.utl.user.service;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.List;

import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFDataFormat;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Component
public class ExcelUtil {
    private static final Logger log = LoggerFactory.getLogger(ExcelUtil.class);

    /**
     * 엑셀 파일을 방출합니다.
     *
     * @param voList 엑셀에 넣고 싶은 vo 리스트 형태로 넣습니다.
     * @param header 엑셀 해더
     * @param order 헤더에 해당하는 내용의 vo 필드 이름을 작성합니다. 예를 들어 String userName; 필드의 1번째 해더이름을 "사용자 이름" 으로 정했으면
     *        순서를 맞추어 1번째 order 배열에 "UserName" 이라는 글짜를 입력해줍니다(*주의:첫 문자는 대문자, 낙타체). 첫번째 컬럼에는 "줄번호"가
     *        들어가는데, 이것에 대한 내용은 order에 값을 입력하지 않습니다.
     * @param width 컬럼 너비를 설정합니다. length가 해더의 length와 일치할 필요는 없습니다.
     * @param title
     * @throws Exception
     * @return SXSSFSheet
     *
     *         특징 : 해더보다 내용의 컬럼수가 많을 때 해당 줄의 컬럼은 cut, 해더 이름이 vo와 다르게 되면 해당 컬럼 출력 안됨 require : 날짜 포멧은
     *         지원하지 않습니다.
     *
     *
     *         ***********************************************************************************************
     *         EX String title = "게시판 리스트";
     *         int[] width = {1500, 1500, 1500, 3000, 30000, 3000 };
     *         String[] header = {"번호", "게시판번호", "작성자", "제목", "내용", "작성일" }; 
     *         String[] order = { "Seq", "UserId", "Title", "Content", "RegDt" }; 
     *         => 첫번째 "번호"에 대한 order 이름이 비어있습니다.
     *
     *         ***********************************************************************************************
     */
    public static SXSSFWorkbook makeSimpleFruitExcelWorkbook(List<Object> voList, String[] header, String[] order, int[] width, String title) throws Exception {
    	// 시트 생성
    	SXSSFWorkbook workbook = new SXSSFWorkbook();
    	SXSSFSheet sheet = workbook.createSheet(title);
		for (int i = 0; i < width.length; i++) {
			// JSP 2022.02.24 => width 변경
			//sheet.setColumnWidth(0, width[width.length - (i + 1)]);
			sheet.setColumnWidth(i, width[i]);
		}

		int r = 2;// 줄부터 찍기
		
		CellStyle headerstyle = workbook.createCellStyle();
		headerstyle.setAlignment(HorizontalAlignment.CENTER);
		headerstyle.setVerticalAlignment(VerticalAlignment.CENTER);
		headerstyle.setBorderBottom(HSSFCellStyle.BORDER_THIN);
        // 헤더 행 생
        Row headerRow = sheet.createRow(r);
        // 해더 값 채움 (우측 방향으로)
        Cell headerCell = null;
        for (int i = 0; i < header.length; i++) {
        	headerRow.setHeight((short)512);
        	
            headerCell = headerRow.createCell(i);
            headerCell.setCellStyle(headerstyle);
            headerCell.setCellValue(header[i]);
        }

        // 내용 행 및 셀 생성
		Row bodyRow = null;
		Cell bodyCell = null;

        bodyRow = sheet.createRow(0);
        bodyCell = bodyRow.createCell(0);
        bodyCell.setCellValue(title);// 읽어온 데이터 표시

        //System.out.println("voList.size()");
        //System.out.println(voList.size());
        //System.out.println(voList.size());
        
        int c = 0;// 컬럼
        for (Object vo : voList) {
            bodyRow = sheet.createRow(r + 1);
            bodyCell = bodyRow.createCell(0);
            //bodyCell.setCellValue(r + 1); // 첫 컬럼은 줄 번호

            PropertyDescriptor pd; // 클래스의 필드 메소드를 찾아줌. 이름을 기존에 vo.setUserId() 란 메소드를 통해서만 호출이 가능 했다면, PropertyDescriptor는 이름만으로 메소드
                                   // 호출이 가능함. 클래스가 변경 되어도 동일한 작동으로 getter&setter 호출이 가능하도록 도와줌
            Method[] methods = vo.getClass().getDeclaredMethods(); // 메소드들 호출함
            // 배열로 준 이름 과 같으면 해당 열 데이터 쓰기
            for (int i = 0; i < order.length; i++) {
                for (Method method : methods) { // vo 내부 메소드 반복

//                	System.out.println("i :: "+ i + "methods : "+ methods);
                	/*System.out.println("voList.method()");
                    System.out.println(method.getName());*/
                    
                    if (method.getName().equals("get" + (order[i] == null ? "" : order[i]))) { // vo메소드 이름과 order의 이름 비교
                        // getter 호출 준비
                        String getMethodName = method.getName().substring(3); // getter의 이름 가져옴
                        pd = new PropertyDescriptor(getMethodName, vo.getClass());
                        // vo의 데이터 세팅
                        String cellData = (pd.getReadMethod().invoke(vo) != null ? pd.getReadMethod().invoke(vo) : "").toString();
                        bodyCell = bodyRow.createCell(c++); // 데이터 순서
                        if(getMethodName.equals("InstrFee") || getMethodName.equals("SpecialWorkAllow") || getMethodName.equals("DistanceAllow")
                        	|| getMethodName.equals("TrafficFee") || getMethodName.equals("AcmdtFee")
                        	|| getMethodName.equals("Amt") || getMethodName.equals("Cash")
                        	){
                        	
                        	// JSP 2022.02.22 => null 에러 try~catch 문 추가
                        	try {
                            	double num = Double.parseDouble(cellData);
                            	CellStyle bodyStyle = workbook.createCellStyle();
                            	bodyCell.setCellValue(num);// 읽어온 데이터 표시
                            	bodyStyle.setDataFormat(HSSFDataFormat.getBuiltinFormat("#,##0"));
                            	bodyCell.setCellStyle(bodyStyle);
                        	}
                        	catch (Exception ex) {
                        		bodyCell.setCellValue(cellData);
                        	}                        	
                        }else {
                        	bodyCell.setCellValue(cellData);// 읽어온 데이터 표시	
                        }
                        //System.out.println("@@  :  "+getMethodName  +"       ---           " + cellData);
                    }
                }
            }
            c = 0;
            r++;
        }
        return workbook;
    }

}
