/*
 * Copyright 2009 Lari Natri <lari.natri@gmail.com>
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 * 
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 * 
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */


package compid.report.exporters;

import compid.report.ReportPageModel;
import net.aavalla.utils.jobpool.JobPriority;
import net.aavalla.utils.jobpool.parameters.FieldAnnotations;
import net.aavalla.utils.jobpool.parameters.OutputFile;
import net.aavalla.utils.jobpool.parameters.validators.OutputFileValidator;
import net.aavalla.utils.general.CastHelper;
import net.aavalla.utils.gui.twovenn.VennCreator;
import net.aavalla.utils.gui.twovenn.VennDrawData;
import net.aavalla.utils.gui.twovenn.VennParameters;
import compid.report.VennReportPageModel;
import java.awt.image.BufferedImage;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import javax.imageio.ImageIO;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFFont;
import org.apache.poi.hssf.usermodel.HSSFRichTextString;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.ClientAnchor;
import org.apache.poi.ss.usermodel.CreationHelper;
import org.apache.poi.ss.usermodel.Drawing;
import org.apache.poi.ss.usermodel.Picture;

/**
 *
 * @author Lari Natri
 */
public class ExcelExporter extends Exporter {

    //public static String REGEXP_EXCELSURECOMPATSTRING
    //        = "[a-zA-Z0-9 _-+.,:;\\!\\@\\(\\)\\[\\]\\{\\}\\#\\%\\*]*";


    public class ExcelExporterParams extends ExporterParams {
        @FieldAnnotations(name="Output file",
            description="File in Excel (.xls) format",
            validator=OutputFileValidator.class)
        private OutputFile outputFile = null;

        public ExcelExporterParams() {
            this.setDescription("Exports report to an Excel workbook. <br/>" +
                    "Each page will appear as a sheet.");
        }

        @Override
        public synchronized String validateFieldRelations() {
            if (!this.outputFile.getName().toLowerCase().endsWith(".xls")) {
                return "File name extension must be .xls";
            }
            return super.validateFieldRelations();
        }


    }

    public ExcelExporter() {
        super();
        this.setName("Report exporter (Excel)");
        this.setPriority(JobPriority.IMMEDIATE);
    }

    @Override
    protected ExcelExporterParams getNonfinalEditableParameters() {
        return new ExcelExporterParams();
    }



    @Override
    protected Object work(ExporterParams params) {
        try {
            ExcelExporterParams p = (ExcelExporterParams) params;
            HSSFWorkbook wb = new HSSFWorkbook();
            int sno = 1;

            for (ReportPageModel rep : p.getReportModel()) {
                if ((rep.getColumnCount()>0 && rep.getRowCount()>0) || rep instanceof VennReportPageModel) {

                    addSheetIfNotEmpty(wb, rep, rep.getTitle());
                    ++sno;
                }
            }
            if (p.getIncludeParameters()) {
                addSheetIfNotEmpty(wb,p.getReportModel().getParametersAsPage(),"Parameters");
                ++sno;
            }


            BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(p.outputFile));
            wb.write(out);
            out.close();
            return "Report exported successfully.";
        } catch (Exception ex) {
            ex.printStackTrace();
            throw new RuntimeException(ex);
        }
    }


    private void addSheetIfNotEmpty(HSSFWorkbook wb, ReportPageModel rep, String sheetName) {
        HSSFSheet s = wb.createSheet(sheetName);

        System.out.println("DEBUG: Excel Export: creating sheet "+sheetName);
        HSSFRow r = null;
        int rowNum = 0;
        int cellNum = 0;
        HSSFCell c = null;
        // create cell styles
        HSSFCellStyle csBold = wb.createCellStyle();
        HSSFCellStyle csNormal = wb.createCellStyle();
        HSSFFont fontBold = wb.createFont();
        HSSFFont fontNormal = wb.createFont();
        fontBold.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
        csBold.setFont(fontBold);
        csNormal.setFont(fontNormal);
        r = s.createRow(rowNum++);
        c = r.createCell(cellNum);
        c.setCellValue(new HSSFRichTextString(rep.getTitle()));
        c.setCellStyle(csBold);
        r = s.createRow(rowNum++);
        c = r.createCell(cellNum);
        c.setCellValue(new HSSFRichTextString(rep.getSubTitle()));
        c.setCellStyle(csBold);
        r = s.createRow(rowNum++);
        cellNum = 0;
        r = s.createRow(rowNum++);
        for (int i = 0; i<rep.getColumnCount(); ++i) {
            String colName = rep.getColumnName(i);
            c = r.createCell(cellNum++);
            c.setCellValue(new HSSFRichTextString(colName));
            c.setCellStyle(csBold);
        }
        for (int dataRow=0; dataRow<rep.getRowCount() && rowNum<65536; ++dataRow) {
            // TODO: if too many rows, create more sheets
            r = s.createRow(rowNum++);
            cellNum = 0;

            for (int dataCell=0; dataCell<rep.getColumnCount(); ++dataCell) {
                c = r.createCell(cellNum++);
                String str;
                if (rep.getValueAt(dataRow, dataCell)==null) {
                    str = "";
                } else {
                    str = rep.getValueAt(dataRow,dataCell).toString();
                    if (str.length()>16000) str = str.substring(0,15997)+"...";
                }
                if (CastHelper.isNumerical(str)) {
                    if (CastHelper.isInteger(str)) {
                        c.setCellValue(Integer.parseInt(str));
                    } else {
                        c.setCellValue(Double.parseDouble(str));
                    }
                } else {
                    c.setCellValue(new HSSFRichTextString(str));
                }
                c.setCellStyle(csNormal);

            }
        }

        if (rep instanceof VennReportPageModel) {
            VennReportPageModel vRep = (VennReportPageModel) rep;
            try {
                VennParameters vp = vRep.getVennParameters().clone();
                VennDrawData dData = VennCreator.calculateVennDrawData(vp,400,600);
                BufferedImage im = VennCreator.createVennImage(vp, dData, true);
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                ImageIO.write(im, "png", baos); //NOI18N
                int picIdx = wb.addPicture(baos.toByteArray(), HSSFWorkbook.PICTURE_TYPE_PNG);
                baos.close();

                CreationHelper helper = wb.getCreationHelper();

                // Create the drawing patriarch.  This is the top level container for all shapes.
                Drawing drawing = s.createDrawingPatriarch();

                //add a picture shape
                ClientAnchor anchor = helper.createClientAnchor();
                //set top-left corner of the picture,
                //subsequent call of Picture#resize() will operate relative to it
                anchor.setCol1(1);
                anchor.setRow1(rowNum+2);
                Picture pict = drawing.createPicture(anchor, picIdx);
                //auto-size picture relative to its top-left corner
                pict.resize();
            } catch (IOException ex) {}
        }


    }


}
