package com.n2bb.web.util;

import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;

import javax.servlet.http.HttpServletResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * Report generator.
 *
 * @version $Id: ReportUtil.java,v 1.3 2010/09/27 20:55:16 xfranet Exp $
 */
public class ReportUtil {
    protected static Log n2bbLog = LogFactory.getLog(ReportUtil.class);
    
    private static final String DATE_FORMAT = "MMM_dd_yyyy_hh_mm_ss_aa"; 
    protected PrintWriter out;
    protected HttpServletResponse response;
    protected String outputType;
    protected String headerName;
    protected String[][] filteredBy;
    protected String sortedBy;
    protected String[] columnDisplayNames;
    protected String[] columnNames;
    protected Collection records;   
    protected String[] parameters;
    protected Class recordClass;
    /**
     * Generates a report and writes it to the servlet output stream.
     *
     * @param response
     * @param outputType
     * @param headerName
     * @param filteredBy
     * @param sortedBy
     * @param columnDisplayNames    column display names
     * @param columnNames           names of columns, used to find accessor method names
     * @param records               list of data records, all the same class
     */
    public static void generateReport(HttpServletResponse response, String outputType,
            String headerName, String filteredBy[][], String sortedBy, String columnDisplayNames[],
            String columnNames[], Collection records) {
        ReportUtil reportUtil = new ReportUtil(response, outputType, headerName,
                filteredBy, sortedBy, columnDisplayNames, columnNames, records);
        reportUtil.generate();        
    }

    /**
     * Gets a column value for display.
     * Override this method to format the column's output.
     */
    protected String formatColumnValue(String columnName, Object columnValue) {    	
        return ("" + columnValue);
    }

    /**
     * Gets the value of a record's column via reflection,
     * using the method "record.getColumnName()".
     * Override to change the way a column value is extracted.
     */
    protected Object getColumnValue(Object record, String columnName)
            throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {    	
    	recordClass = record.getClass();
        String methodName = "get" + columnName.substring(0, 1).toUpperCase() + columnName.substring(1);
        Method method = recordClass.getMethod(methodName, null);        
        return method.invoke(record, null);
    }

    /** Constructor */
    public ReportUtil(HttpServletResponse response, String outputType, String headerName,
            String[][] filteredBy, String sortedBy, String[] columnDisplayNames,
            String[] columnNames, Collection records) {    	
        try {
            this.out = response.getWriter();
        }
        catch (IOException e) {
            n2bbLog.error("", e);
        }
        this.response = response;
        this.outputType = outputType;
        this.headerName = headerName;
        this.filteredBy = filteredBy;
        this.sortedBy = sortedBy;
        this.columnDisplayNames = columnDisplayNames;
        this.columnNames = columnNames;
        this.records = records;        
    }

    protected ReportUtil() {
        // for compatibility with subclasses that use static generateReport method
    }

    public void generate() {    	
        try {
            generateHeaderInfo();
            printRecords();
            if (out != null) {
                out.close();
            }
        }
        catch (Exception e) {
            n2bbLog.error(e.getMessage(), e);
        }           
    }

    protected void generateHeaderInfo() {    	
        printHttpHeader();
        printReportHeader();
        out.println();
        printFilterInfo();
        out.println();
        printSortInfo();
        out.println();
        printColumnNames();
        out.println();
        out.println();        
    }

    protected void printRecords()
            throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {    	
        if (records == null || records.size() < 1) {
            return;
        }
        
                
        for (Iterator recordsIterator = records.iterator();recordsIterator.hasNext();) {
        	Object record = recordsIterator.next();
            for (int j = 0; j < columnNames.length; j++) {
                if (j > 0) {
                    out.print("\t");
                }
                String columnName = columnNames[j];                
                Object columnValue = getColumnValue(record, columnName);
                out.print(formatColumnValue(columnName, columnValue));
            }
            out.println();
        }        
    }

    protected void printHttpHeader() {    	  
 	   DateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT); 	 
 	   String fileName = ""; 	   
       if (outputType != null && outputType.equals("Excel")) {    	  
    	    fileName = "Report_" + dateFormat.format(new Date()).trim() + ".xls";    	  
            response.setContentType("application/microsoft.ms-excel");
            response.setHeader("Pragma", "public");
            response.setHeader("Cache-Control", "max-age=0");
            response.setHeader("Content-disposition", "attachment; filename=" +fileName);
        }
        else { // if (outputType.equals("Text")) {
            response.setContentType("text/plain");
            fileName = "Report_" + dateFormat.format(new Date()).trim() +".txt";
            response.setHeader("Pragma", "public");
            response.setHeader("Cache-Control", "max-age=0");            
            response.setHeader("Content-disposition", "attachment; filename=" + fileName);
        }        
    }

    protected void printReportHeader() {    	
        out.println("\t\t\t\t" + headerName);        
    }

    protected void printFilterInfo() {    	
        if (filteredBy == null) {        	
            return;
        }
        String filterName = "";
        String filterValue = "";
        out.println("Filtered By:");
        for (int filters = 0; (filters < filteredBy.length) && (filteredBy.length > 0); filters++) {
            filterName = filteredBy[filters][0];
            filterValue = filteredBy[filters][1];
            if (filterValue != null && !filterValue.equals("")) {
                out.println("\t" + filterName + ": " + filterValue);
            }
        }         
    }

    protected void printSortInfo() {    	
        if (sortedBy == null) {
            return;
        }
        String sortedCriteria = "";
        out.println("Sorted By:");
        sortedCriteria = sortedBy.substring(0, 1).toUpperCase() + sortedBy.substring(1);
        out.println("\t" + sortedCriteria);        
    }

    protected void printColumnNames() {    
        if (columnDisplayNames == null) {
            return;
        }
        for (int columns = 0; columns < columnDisplayNames.length; columns++) {
            if (columns == 0) {
                out.print(columnDisplayNames[columns]);
            }
            else {
                out.print("\t" + columnDisplayNames[columns]);
            }
        }        
    }    
}





