/*
 * 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.general.CastHelper;
import java.io.BufferedWriter;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.HashSet;
import java.util.Set;

/**
 *
 * @author Lari Natri
 */
public class LatexExporter {

    // TODO: derive from Exporter

    private static final String R_percentifyRows =
            "# sets row items to percent value of row's total sum\n"+
            "percentifyRows <- function(x) {\n"+
            "  y <- x\n"+
            "  i <- 1\n"+
            "  while (i<=length(x[,1])) {\n"+
            "    j <- 1\n"+
            "    while (j<=length(x[i,])) {\n"+
            "      y[i,j] <- x[i,j] / sum(x[i,] ) * 100\n"+
            "      j <- j + 1\n"+
            "    }\n"+
            "    i <- i + 1\n"+
            "  }\n"+
            "  y\n"+
            "}\n";

    private static final String R_revRowOrder =
            "# reverses the order of rows in a matrix-like 2D object\n"+
            "revRowOrder <- function(x) {\n"+
            "  y <- x\n"+
            "  i <- 1\n"+
            "  while (i<=length(x[,1])) {\n"+
            "    y[i,] <- x[length(x[,1])-i+1,]\n"+
            "    i <- i + 1\n"+
            "  }\n"+
            "  rownames(y) <- rev(rownames(x))\n"+
            "  y\n"+
            "}\n";

    public static int writeResults(OutputStream stream, ReportPageModel page) throws java.io.IOException {
        return writeResults(stream, page, " & ", " \\\\", "% ",
                                 true, true);
    }

    public static int writeResults(OutputStream stream, ReportPageModel page, String separator,
                             String lineEnd, String preComment,
                             boolean writeHeader, boolean writeColNames) throws java.io.IOException
    {
        if (separator==null) separator = "";
        if (lineEnd==null) lineEnd = "";
        if (preComment==null) preComment = "";
        int linesWritten = 0;

        BufferedWriter out
               = new BufferedWriter(new OutputStreamWriter(stream));

        if (writeHeader) {
            out.write(preComment + page.getTitle() + lineEnd);
            out.newLine();
            out.write(preComment + page.getSubTitle() + lineEnd);
            out.newLine();
            linesWritten+=2;
        }

        if (writeColNames) {
            for (int c=0; c<page.getColumnCount(); ++c) {
                out.write(page.getColumnName(c));
                if (c==page.getColumnCount()-1) {
                    out.write(lineEnd);
                } else {
                    out.write(separator);
                }
            }
            out.newLine();
            ++linesWritten;
        }

        for (int r=0; r<page.getRowCount(); ++r) {
            for (int c=0; c<page.getColumnCount(); ++c) {
                out.write(page.getValueAt(r,c).toString());
                if (c==page.getColumnCount()-1) {
                    out.write(lineEnd);
                } else {
                    out.write(separator);
                }
            }
            out.newLine();
            ++linesWritten;
        }
        out.flush();
        return linesWritten;
    }

    public static void writeToR_createBarPlot(OutputStream stream, ReportPageModel page, String tableVarName,
                                       Set<Integer> skipColumns, boolean percentagePlot,
                                       boolean beside, boolean writeSubName,
                                       String colLabelName, String rowLabelName,
                                       String imageOutputFile)  throws java.io.IOException
    {

        if (colLabelName==null) colLabelName = "";
        if (rowLabelName==null) rowLabelName = "";
        if (skipColumns==null) skipColumns = new HashSet<Integer>(0);
        if (tableVarName==null || tableVarName.trim().length()<1)
            tableVarName = "x";
        tableVarName = tableVarName.trim();

        BufferedWriter out
               = new BufferedWriter(new OutputStreamWriter(stream));

        out.write("# "+page.getTitle());
        out.newLine();
        out.write("# "+page.getSubTitle());
        out.newLine();
        out.newLine();

        out.write(R_revRowOrder);
        if (percentagePlot) out.write(R_percentifyRows);
        out.newLine();
        out.flush();

        writeToR_inputData(stream,page,tableVarName,skipColumns);

        out.write("postscript(file=\"");
        out.write(imageOutputFile);
        out.write("\",horizontal=F,paper=\"special\", width=8.26, height=9*length("+tableVarName+"[,1])/28+2)");
        out.newLine();

        out.write("par(mar=c(4.9,");

        int longestRowName = 0;
        for (int r = 0; r<page.getRowCount(); ++r) {
            if (page.getValueAt(r, 0).toString().length()>longestRowName) {
                longestRowName = page.getValueAt(r, 0).toString().length();
            }
        }

        double marLeft = (longestRowName*11d/20d)+1;

        int marUp;
        if (page.getTitle().trim().length()<1 && (!writeSubName || page.getSubTitle().trim().length()<1))
            marUp = 2;
        else if (page.getTitle().trim().length()<1 || (!writeSubName || page.getSubTitle().trim().length()<1))
            marUp = 3;
        else marUp = 4;
        out.write(marLeft+","+marUp);
        out.write(",2))");
        out.newLine();

        out.write("barplot(t(as.matrix(");
        if (percentagePlot) out.write("percentifyRows(");
        out.write("revRowOrder(x)");
        if (percentagePlot) out.write(")");
        out.write(")),beside=");
        if (beside) out.write("T");
        else out.write("F");
        out.write(",horiz=T,legend.text=T,xlab=\""+rowLabelName+"\",ylab=\""+colLabelName+"\"");
        out.write(",main=\""+page.getTitle());
        if (writeSubName) out.write("\\n"+page.getSubTitle());
        out.write("\"");
        out.write(",las=1)");
        out.newLine();

        out.write("dev.off()");
        out.newLine();
        //out.write("q()"); out.newLine();

        out.flush();

    }

    public static int writeToR_inputData(OutputStream stream, ReportPageModel page,
                                  String tableVarName,
                                  Set<Integer> skipColumns)
                                  throws java.io.IOException {

        if (skipColumns==null) skipColumns = new HashSet<Integer>(0);

        if (tableVarName==null || tableVarName.trim().length()<1)
            tableVarName = "x";
        tableVarName = tableVarName.trim();

        int linesWritten = 0;

        BufferedWriter out
               = new BufferedWriter(new OutputStreamWriter(stream));

        // row labels
        out.write(tableVarName+"_rLabs <- c(");
        for (int i=0; i<page.getRowCount(); ++i) {
            if (i>0) out.write(",");
            out.write("\""+page.getValueAt(i,0)+"\"");
        }
        out.write(")");
        out.newLine(); ++linesWritten;

        // column labels
        out.write(tableVarName+"_cLabs <- c(");
        for (int i=1; i<page.getColumnCount(); ++i) {
            if (skipColumns.contains((Integer)i)==false) {
                if (i>1) out.write(",");
                String cName = page.getColumnCount()<i ? ((Integer)i).toString() : page.getColumnName(i);
                out.write("\""+cName+"\"");
            }
        }
        out.write(")");
        out.newLine(); ++linesWritten;

        // data as columns
        int cinr = 0;
        for (int c=1; c<page.getColumnCount(); ++c) {
            if (skipColumns.contains((Integer)c)==false ) {
                ++cinr;
                out.write(tableVarName+"_col"+cinr+" <- c(");
                for (int r=0; r<page.getRowCount(); ++r) {
                    if (r>0) out.write(",");
                    Object value = page.getValueAt(r, c);
                    boolean num = CastHelper.isNumerical(value);
                    if (!num) out.write("\"");
                    out.write(value.toString());
                    if (!num) out.write("\"");
                }
                out.write(")");
                out.newLine(); ++linesWritten;
            }
        }

        // put columns into table variable
        out.write(tableVarName + " <- data.frame(");
        for (int i=1; i<=cinr; ++i) {
            if (i>1) out.write(",");
            out.write(tableVarName+"_col"+i);
        }
        out.write(")");
        out.newLine(); ++linesWritten;

        // set row and column names
        out.write("colnames("+tableVarName+") <- "+tableVarName+"_cLabs");
        out.newLine(); ++linesWritten;
        out.write("rownames("+tableVarName+") <- "+tableVarName+"_rLabs");
        out.newLine(); ++linesWritten;
        out.newLine(); ++linesWritten;

        out.flush();

        return linesWritten;

    }




}
