/***********************************************************************
 * title : PagedReport.java
 * purpose: support printing a XtabReport
 * copyright 2001 (c) Avman Systems Inc.
 ***********************************************************************/

package net.avman.RRSupport;
import java.math.BigDecimal;
import java.util.Vector ;

import java.sql.*;
import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import java.util.StringTokenizer;
import java.util.ArrayList;
import java.text.NumberFormat;

import java.awt.print.PrinterJob ;
import java.awt.print.PrinterException ;


import org.xml.sax.InputSource;

import org.apache.fop.apps.Driver;
import org.apache.fop.layout.Page;
import org.apache.fop.apps.Version;
import org.apache.fop.apps.XSLTInputHandler;
import org.apache.fop.messaging.MessageHandler;

import org.apache.fop.render.awt.AWTRenderer ;

import org.apache.avalon.framework.logger.ConsoleLogger;
import org.apache.avalon.framework.logger.Logger;

public class PagedReport extends avReport implements ifReport {

    public static final int STATE_FETCH         = 1;
    public static final int STATE_INTERRUPT     = 2;
    public static final int STATE_INTERRUPTED   = 3;
    public static final int STATE_IDLE          = 0;

    public int FetchStatus = STATE_IDLE;

    
    ReportTotals RepTots = new ReportTotals(this);
    int TotalsId =0;
    int StartingRecord;
    double [][] LevelBreakTotals=null;
    int GroupRecCount[] = null;
    /**
        constructor function for the class.
        Pass all parameters as name-value pairs
     **/
    public PagedReport(String [] args, String datasrc, String sRptid)
    throws JspException {
        super(args,  datasrc,  sRptid);
    }
    
    public PagedReport(java.util.Properties prop, String datasrc, String sRptid)
    throws JspException {
        super( prop,  datasrc,  sRptid);
    }
    
    public PagedReport(java.util.Properties prop, String datasrc, String sRptid, String name)
    throws JspException {
        super( prop,  datasrc,  sRptid, name);
    }
    
    
    public PagedReport(String [] args, String datasrc, String sRptid, String RptName)
    throws JspException {
        super(args, datasrc, sRptid, RptName);
    }  // end constructor
    
    
    /********************************************************************/
    /**
method invoked to build the report info
     **/
    public int start(javax.servlet.http.HttpServletResponse response
            ,String pth
            ,javax.servlet.jsp.JspWriter  out)
            throws JspException {
        return start(response,pth,(java.io.Writer)out);
    }
    
    /********************************************************************/
    /**
method invoked to build the report info
     **/
    public int start(javax.servlet.http.HttpServletResponse response
            ,String pth
            ,java.io.Writer  out)
            throws JspException {
        setWriter(out);
        return start(response,pth);
    }
    
    /********************************************************************/
    /**
method invoked to build the report info
     **/
    public int start(String pth)
    throws JspException {
        return start(null,pth);
    }
    
    /********************************************************************/
    /**
method invoked to build the report info
     **/
    public int start(javax.servlet.http.HttpServletResponse response
            ,String pth)
            throws JspException {
        return super.start(response,pth);
    }
    
    
    public void buildQuery(String env)
    throws JspException {
        super.buildQuery(env);
    }
    
    
    /**************************************************************
     * executeQuery
     **************************************************************/
    public long executeQuery()
    throws JspException {
        avProperties props;
        
        if (PrintWhereHeader)
            setValueArray("whereHeader",whereHeader.toString());
        else
            setValueArray("whereHeader"," ");
        setValueArray("CurrentPage",Integer.toString(CurrentPage+1));
        if (moreData != 1 ) {
            if (isEmbbededQuery)
                print(avParse.expandCmd(EmbeddedReportStartDelim,varValues));
            else
                print(avParse.expandCmd(ReportStartDelim,varValues));
            
            if (TableJoins.SimpleJoin) {
                props = new avProperties(sPath, datasrc + ".prop");
                SqlResults = new tagResults(props,SqlCommand,0,aInputVar,aInputVal, tagResults.SCROLLABLE);
            } else {
                SqlResults = CreateExMultipleSQLs();
                adjustFieldInfo();
                SqlResults.AddRange(JoinWhere);
            }
        }
        
        if (!(RptStyle == EXCEL_REPORT || RptStyle == PRINT_REPORT))
            createGraphsHeader();
        
        this.PrintDebug("printing report sql="+SqlCommand);
        print(TableStartDelim);
        
        if (step > 0) {
            if (endat == 0 || endat > (startat + step))
                endat = startat + step;
        }
        
        if (endat < startat || (endat==0 ))
            endat = 999999999;
        
        
        print_report_table(startat,endat);
        
        setValueArray("CurrentRow",Integer.toString(currentRow));
        print(TableEndDelim);
        
        if (moreData == 1 ) {
            //print(getProp("NextPage",prop));
        } else if (dontPrint == 0) {
            if (isEmbbededQuery)
                print(getProp("EmbeddedEndLine",prop));
            else
                print(getProp("EndLine",prop));
        }
        
        if (moreData != 1)
            createGraphs();
        if (InDrillDown)
            print(CloseButton);
        if (isEmbbededQuery)
            print(EmbeddedReportEndDelim);
        else
            print(ReportEndDelim);
        
        if (moreData != 1 ) {
            System.out.println("closing database");
            SqlResults.close();
        }
        
        if (RealRptStyle == PRINT_REPORT && !bUseExternalStream) {
            closePrintStreams();
        } else if ((RealRptStyle == PDF_REPORT || RealRptStyle == UNF_PDF_REPORT)&& !bUseExternalStream) {
            closePdfFiles();
        }
        return currentRow;
        
    }
    
    
    
    public void setTimeout(double maxTime) {
        this.maxTime = maxTime;
    }
    
    
    /**
     * sets up the ReportTotals object to be used to build group totals
     */
    void setupReportTotalFields(tagResults tr) throws JspException {
     //   System.out.println("in setupReportTotalFields");
        for (int i=0; i < SortCount; i++) {
            if (aSort[i].printtot == 1) {
                int c = aSort[i].fldNum;
                RepTots.addReportGroupToList(c,aSort[i].PrintPageBreak);
            }
        }
        
        for (int i=0; i < FieldCount; i++) {
            if (apFieldInfo[i].Totals == 1) {
                  RepTots.addTotalsFieldToList(apFieldInfo[i].ColmnInfoInx);
            }
        }
        //System.out.println("out setupReportTotalFields");
    }
    
    int ContinueAt=0;
    public void setupReportTotals(tagResults SqlResults) throws JspException
    {

        FetchStatus = STATE_FETCH;
        SqlResults.setFieldInfo(apFieldInfo);
        setupReportTotalFields(SqlResults);
        RepTots.setLinesPerPage(iLinesPerPage);
        RepTots.setupInputString(varValues.getProperty("Input","rptid="+this.rptid));
        System.out.println("Sarting loop, startat="+startat+",endat="+endat+";linesperpage="+iLinesPerPage);
        int BreakLevel=0;
        int pg=0;
        while ( SqlResults.next(true,true) ) {
            ContinueAt++;
       //     System.out.println("setupReportTotals:ContinueAt="+ContinueAt+";value="+SqlResults.Field(1));            
           // System.out.println(">>>>>>>>>>computing breaks");
            if ((BreakLevel=RepTots.ProcessData(SqlResults)) > 0) {
                RepTots.ClearGroupTotals(SqlResults);
                RepTots.setLevelKeys(SqlResults);
            }
            for (int i=0; i < GraphCount; i++)
            {
               if (aGraph[i].SumValueFld != 1) {
                    aGraph[i].update(SqlResults);  // update xtab graph
                    addGraphValue(i,-1);
               }
            }
            if (RepTots.ReaderAtPageBreak)
            {
                pg++;
                System.out.println("Got level break at record#"+ContinueAt);
                if (pg >= 2) {
                    RepTots.setAtFirstBreak(true);
                    RepTots.saveTotals();
                    SqlResults.repositionRecordSet();
                    FetchStatus = STATE_INTERRUPTED;
                    RepTots.setReportState(FetchStatus);
                    //RepTots.ProcessInterrupt();
                    return;
                }
            }
           // System.out.println(">>>>>>>>>>>>>>end computing breaks");            
        }
        PrintDebug("Ending loop, startat="+startat+",endat="+endat+";linesperpage="+iLinesPerPage);
        RepTots.setAtFirstBreak(false);
        RepTots.ProcessEOF();
      //  RepTots.debug();        
        SqlResults.repositionRecordSet();
        FetchStatus = STATE_IDLE;
        RepTots.setReportState(FetchStatus);
    }
    

    public void interruptReport()
    {
        
    }
    public void continueReportTotals() throws JspException
    {
        if (FetchStatus == STATE_IDLE) // report has already been run
            return;
        FetchStatus = STATE_FETCH;
        RepTots.setReportState(FetchStatus);
        SqlResults.positionRecordSet(ContinueAt);
        System.out.println("continue loop, ContinueAt="+ContinueAt);
        //RepTots.restoreTotals();
        //RepTots.continueTotals();
        int BreakLevel=0;
        while ( SqlResults.next(true,true) ) {
            ContinueAt++;
     //       System.out.println("continueReportTotals:ContinueAt="+ContinueAt+";value="+SqlResults.Field(1));            
           // System.out.println(">>>>>>>>>>computing breaks");
            if ((BreakLevel=RepTots.ProcessData(SqlResults)) > 0) {
                RepTots.ClearGroupTotals(SqlResults);
                RepTots.setLevelKeys(SqlResults);
            }
            for (int i=0; i < GraphCount; i++)
            {
                    if (aGraph[i].SumValueFld != 1) {
                        aGraph[i].update(SqlResults);  // update xtab graph
                        addGraphValue(i,-1);
                    }
            }

            if (FetchStatus == STATE_INTERRUPT && RepTots.ReaderAtPageBreak)
            {
                System.out.println("Got interrupt at record#"+ContinueAt);
                RepTots.saveTotals();
                SqlResults.repositionRecordSet();
                RepTots.setAtFirstBreak(false);
                FetchStatus = STATE_INTERRUPTED;
                RepTots.setReportState(FetchStatus);
                return;
            }
          // System.out.println(">>>>>>>>>>>>>>end computing breaks");            
        }
        PrintDebug("Ending loop, startat="+startat+",endat="+endat+";linesperpage="+iLinesPerPage);
        RepTots.setAtFirstBreak(false);
        RepTots.ProcessEOF();
      //  RepTots.debug();        
        SqlResults.repositionRecordSet();
        FetchStatus = STATE_IDLE;
        RepTots.setReportState(FetchStatus);

    }
    

void printTotalsForLevel(int lvl)
throws JspException
{
	int i,j;
	int printedField;
	int FieldsToSkip=0;
//        int TotInx = (lvl == SortCount) ? 0 : lvl + 1;
        int TotInx = lvl;
        if (lvl == 0) {
            lvl = SortCount;
            TotInx = 0;
        }
        else  {
            lvl--;
        }
        System.out.println("Printing total index ="+TotInx+";lvl="+lvl);
       // if (lvl <= 0)
       //     return;
	this.PrintDebug("printing totals for level="+lvl +" sort count="+SortCount);
	if (dontPrint == 0)
	{
		if (PrintFieldLabel==0)
		{
			if (!(Summary != 0 && "".equals(aSort[lvl].totMsg)))
			{
				lineCount++;
				printColorLine("RowStartDelim",aSort[lvl].TotColor);
				printTotalSpanDelim("TotalsFieldStartDelim",FieldsToSkip,aSort[lvl].TotColor);
				print(avParse.expandCmd(aSort[lvl].totMsg,"count=" + GroupRecCount[TotInx]));
				print(FieldEndDelim);
				print(RowEndDelim);
			}
			lineCount++;
			printColorLine("RowStartDelim",aSort[lvl].TotColor);
		}
		else if (PrintFieldLabel == 2)
		{
			if (!(Summary != 0 && "".equals(aSort[lvl].totMsg)))
			{
				lineCount++;
				printColorLine("RowStartDelim",LineColor[flipShade()]);
				printColorLine("level1FieldStartDelim",aSort[lvl].TotColor);
				print(avParse.expandCmd(aSort[lvl].totMsg,"count=" + GroupRecCount[TotInx]));
				if (aSort[lvl].printMsg == 1)
				{
					print(" ");
					print(subHead[lvl]);
				}
				//this.PrintDebug("subHead[" + lvl + "]=" + subHead[lvl]);
				print(FieldEndDelim);
				print(RowEndDelim);
			}
			lineCount++;
			printColorLine("RowStartDelim",aSort[lvl].TotColor);
		}
		else if (PrintFieldLabel==1)
		{
			lineCount++;
			printColorLine("RowStartDelim",aSort[lvl].TotColor);
			print(FieldStartDelim);
			print(avParse.expandCmd(aSort[lvl].totMsg,"count=" + GroupRecCount[TotInx]));
			print(FieldEndDelim);
		}
	}

	// cycle through all the fields and either print the field if it is part
	// of the key, or print the totals for the field or print a blank field
	int writeCount=0;
        int TotFieldSeq=0;
	for (i=0;i < FieldCount; i++)
	{
		int cinx;

		printedField=0;
		if (apFieldInfo[i].colDisplay != 1)
			continue;
		cinx = apFieldInfo[i].ColmnInfoInx;

		// print the sort keys if there is a key break
		// for the last break, there are now keys
		if ( lvl < SortCount)
		{
			for (j=0; j <= lvl; j++)
			{
				if (aSort[j].rptfldid == apFieldInfo[i].rptfldid )
				{
					// it is a sort key and is less than the level hence print it
				  printField(i, SqlResults.FieldValue[cinx], 0, lvl-1);
				  printedField=1;
				  break;

				}
			}
		}

		// print the field totals if they are to be printed
		if (printedField == 0 && apFieldInfo[i].Totals != NONE_FUNCTION)
		{
			printedField=1;
			switch (apFieldInfo[i].Totals) {
			  case  SUM_FUNCTION:
					printField(i,LevelBreakTotals[TotInx][TotFieldSeq], 0, lvl-1);
					break;
			  case  MIN_FUNCTION:
					printField(i,LevelBreakTotals[TotInx][TotFieldSeq], 0, lvl-1);
					break;
			  case  MAX_FUNCTION:
					printField(i,LevelBreakTotals[TotInx][TotFieldSeq], 0, lvl-1);
					break;
			  case  AVG_FUNCTION:
					printField(i,LevelBreakTotals[TotInx][TotFieldSeq]/GroupRecCount[TotInx], 0, lvl-1);
					break;
			}
                        TotFieldSeq++;
		}

		// print other fields associated with a keybreak
		// for the last break, there are now keys
		if (printedField == 0 && lvl < SortCount)
		{
			for(j=0; keyBreakFields[lvl][j] != -1; j++)
			{
			  if (keyBreakFields[lvl][j] == apFieldInfo[i].rptfldid )
			  {
				printField(i,  SqlResults.FieldValue[cinx], 0, lvl-1);
			    printedField=1;
				break;
			  }
			}
		}
		writeCount++;
		if (printedField == 0
			&& !BlankField.equals("")
			&& dontPrint == 0
			&& writeCount >= FieldsToSkip
			)
		{
			print(BlankField);
		}

	}   // end for
	//this.PrintDebug("skip fields = " + FieldsToSkip + "written fields=" + writeCount);

	// we have printed the detailed line, now print the end line
	if (dontPrint == 0)
	{
	   print(RowEndDelim);
	}

	// save the totals values for the graphs
        /**
	for (i=0; i < GraphCount; i++)
	{
		if (aGraph[i].SumValueFld == 1 && aSort[lvl].rptfldid == aGraph[i].SortFldID)
			if (aGraph[i].ValueRptFldID[0] == -1)
				addGraphCountValue(i,lvl,GroupRecCount[TotInx]);
			else
				addGraphValue(i,lvl);
	}
         */
	InitTotalsForLevel(lvl);
}


    
void printLevelBreak(int lvl)
throws JspException
{
	int i;

        if (lvl <=0)
            return;
	this.PrintDebug("summary="+Summary+"totMsg="+aSort[lvl-1].totMsg+";sortcount="+SortCount);
	if (dontPrint == 0 && !(Summary != 0 && "".equals(aSort[lvl-1].totMsg)))
	{
		print(FullRow);
		lineCount++;
	}
        if (SortCount > 0)
            for (i=SortCount; i >= lvl ; i--)
            {
                System.out.println("aSort[i].printtot="+aSort[i-1].printtot);
                    if (aSort[i-1].printtot == 1)
                            printTotalsForLevel(i);
    //		DEBUG("*** adding graph for %d\n",aSort[i].rptfldid);
            }
	if (Summary == 0 && ( HeadersWithLevelBreaks))
		PrintedHeader = 0; // print header after breaks for details
}

    
    public void print_report_table(int startat, int endat)
    throws JspException {
        
        int i;
        long startTime=0, endTime=0;
        int firstTime = 1;
        int PrintSubHeader=-1;
        int StartTimer = 0;
        PrintedHeader = 0;
        boolean doHdrPrinting=false;
        int pg=CurrentPage;
        boolean printedPageCardStartDelim=false;
        lineCount=0;
        try {
            iLinesPerPage=Integer.parseInt(linesperpage);
        } catch (Exception e) {
        }
        setValueArray("linesperpage",linesperpage);
        if (TblType.equalsIgnoreCase("Query")) {
            for (i=0; i < FieldCount; i++) {
                for (int j=1; j <= SqlResults.numberOfColumns; j++) {
                    if (SqlResults.colName[j].equalsIgnoreCase(apFieldInfo[i].fldname)) {
                        apFieldInfo[i].ColmnInfoInx = j;
                        break;
                    }
                }
            }
        }
        
        if (TotalsId==0) {
            System.out.println("Create new report totals");
            setupReportTotals(SqlResults);
            TotalsId = Totals.saveTotals(RepTots);
        }
        else {
             System.out.println("Reusing report totals");
             if (FetchStatus == STATE_FETCH)
             {
                 FetchStatus = STATE_INTERRUPT;
                 while (FetchStatus != STATE_INTERRUPTED && FetchStatus != STATE_IDLE) {
                     System.out.println("Waiting for state to become interrupted, state="+FetchStatus);
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException ex) {
                        ex.printStackTrace();
                    }
                 }
             }
             RepTots = Totals.getTotals(TotalsId);
        }
        RepTots.setReportState(FetchStatus);
        
        //System.out.println(">>positionRecordSet="+currentRow);
        //SqlResults.positionRecordSet(currentRow);
        
        boolean ContCond;
        
        if (startat== 0 || startat == 1)
            currentRow = 0;
        else
            currentRow = startat -1;
        StartingRecord = currentRow;
        SqlResults.positionRecordSet(currentRow);
        RepTots.initReport(startat);
        
        System.out.println("***stating loop currentRow="+currentRow+";startat="+startat+";endat="+endat);
        while ( ContCond=SqlResults.next(true,true) ) {
          //  System.out.println("in loop currentRow="+currentRow);
            currentRow++;
            if (RepTots.atPageBreak(currentRow)) {
                moreData=1;
                break;
            }
            if (currentRow >= endat) {
                moreData = 1;
                break;
            }
            if (StartTimer == 1 ) {
                endTime = System.currentTimeMillis();
                if ( (endTime- startTime)  > maxTime) {
                    moreData = 1;
                    break;
                }
            }
            dontPrint = (currentRow < startat ) ? 1 : 0 ;
            doHdrPrinting=false;
            
            if (firstTime == 1)
                PrintSubHeader =0;
            
            if (dontPrint == 0) {
                if (PrintedHeader == 0)
                    doHdrPrinting=true; //printHeaderInfo();
            }
            
            boolean DoBreak=false;
            
            
            // If we have already printed PageCardStartDelim and we have to print the header
            // then we first need to print PageCardEndDelim to close the previous PageCard
            if (printedPageCardStartDelim && doHdrPrinting) {
                prop.setProperty("page",Integer.toString(pg));
                print(avParse.expandCmd(PageCardEndDelim,prop));
                printedPageCardStartDelim=false;
            }
            if (!printedPageCardStartDelim && doHdrPrinting) {
                prop.setProperty("page",Integer.toString(++pg));
                print(avParse.expandCmd(PageCardStartDelim,prop));
                printedPageCardStartDelim=true;
                lineCount=0;
            }
            if (RptStyle == PAGED_REPORT && PrintSubHeader >= 0) {
                
                if (dontPrint == 0 ) {
                    lineCount++;
                    print(FullRow);
                }
                int j=0;
                for (i= 0; i < SortCount ; i++) {
                    if (i < PrintSubHeader) {
                        if (aSort[i].printtot == 1)
                            j++;
                    } else if (aSort[i].printtot == 1) {
                        create_type1_record(i,"");
                        if (dontPrint == 0) {
                            String lc = aSort[i].TotColor; //LineColor[flipShade()];
                            lineCount++;
                            printColorLine("RowStartDelim",lc);
                            printColorLine("level1FieldStartDelim",lc);
                            print(startBold);
                            print(subHead[i]);
                            print(endBold);
                            print(FieldEndDelim);
                            print(RowEndDelim);
                        }
                        j++;
                    }
                }
            }
            PrintSubHeader = -1;
            firstTime = 0;
            //resetShade();
            
//this.PrintDebug("calling printHeaderInfo");
            if (doHdrPrinting) {
                if (PrintedHeader == 0) {
                    this.PrintDebug("Printing header");
                    printHeaderInfo();
                } else {
                    this.PrintDebug("HeadersWithLevelBreaks="+HeadersWithLevelBreaks);
                    if (HeadersWithLevelBreaks)
                        printHeaderInfo();
                }
            }
            
            //this.PrintDebug("called printHeaderInfo");
            
            int iSaveDontPrint = dontPrint;
            if (Summary != 0)
                dontPrint = 1; // suppress printing detail
            if (dontPrint ==0 && Summary == 0 ) {
                lineCount++;
                printColorLine("RowStartDelim",LineColor[flipShade()]);
            }
            
            int cinx;
            //this.PrintDebug("printing field details");
            for (i=0; i < FieldCount; i++) {
                if (apFieldInfo[i].colDisplay == 1) {
                    cinx = apFieldInfo[i].ColmnInfoInx;
//				print(apFieldInfo[i].beforetext);
                    printField(i, SqlResults.FieldValue[cinx],apFieldInfo[i].Totals,SortCount);
//				print(apFieldInfo[i].aftertext);
                }
                if (apFieldInfo[i].Totals != NONE_FUNCTION)
                    computeTotalsForField(i,dLastFieldValue);
            }
            
            if (dontPrint ==0 && Summary == 0
                    && !(RptStyle == EXCEL_REPORT  || RptStyle == CSV_REPORT)) {
                for (i=0; i < DrillCount; i++) {
                    if (apDrill[i].Explode == 0) {
                        print(FieldStartDelim+HrefStartDelim);
                        print("report.jsp?rptid="
                                + apDrill[i].DestRptId + UrlContChar
                                + "datasrc="+DatabaseName + UrlContChar
                                + "flag=runreport" + UrlContChar
                                + "PRINTREPORTYN=1"  + UrlContChar
                                + "PRINTGRAPHS=1"
                                );
                        printDrillDownDetails(apDrill[i].DD_ptr);
                        print(glbArgsToString());
                        print(HrefEndDelim);
                        print(apDrill[i].DrillDownName);
                        print(SlashA);
                        print(FieldEndDelim);
                    } else {
                        print(RowEndDelim);
                        String lc = aSort[i].TotColor; //LineColor[flipShade()];
                        printColorLine("RowStartDelim",lc);
                        printColorLine("level1FieldStartDelim",lc);
                        expodeNewReport(i);
                        print(FieldEndDelim);
                        print(RowEndDelim);
                        flipShade();
                        printColorLine("RowStartDelim",
                                lc
                                );
                    } //end else
                } // end for
                print(RowEndDelim);
                //resetShade();
            } // end if
            
            
            if (RptStyle == EXCEL_REPORT  || RptStyle == CSV_REPORT)
                print(RowEndDelim);
            
            dontPrint = iSaveDontPrint; // restore the old value of print
            
            // i have printed something so now I can start the timing process
            if (dontPrint ==0 && StartTimer == 0) {
                StartTimer = 1;
                startTime=System.currentTimeMillis();
            }

            // check&process level breaks
            int lvl=0;
            for (i=0; i < SortCount ; i++) {
                if (aSort[i].printtot == 1) {
                    int fldNum;
                    //lvl++;
                    // user wants to print totals at this level so do the checking
                    fldNum = apFieldInfo[aSort[i].fldNum].ColmnInfoInx;
                    if ((lvl =RepTots.atLevelBreak(currentRow+1)) > 0   ) {
                        LevelBreakTotals = RepTots.LevelBreakTotals;
                        GroupRecCount = RepTots.GroupRecCount;
                        this.PrintDebug("printling for element i=" + i+";lvl="+lvl);
                        // it is a level break; process it
                        printLevelBreak(lvl);
                        if (aSort[i].PrintPageBreak == 1)
                            DoBreak = true;
                        if (dontPrint == 0 && !(Summary != 0 && "".equals(aSort[i].totMsg))) {
                            lineCount++;
                            print(FullRow);
                            if (aSort[i].PrintPageBreak == 1)
                                PrintPageBreak=true;
                        }
                        
                        if (aSort[i].printMsg == 1) {
                            if (dontPrint == 0)
                                doHdrPrinting=true; //printHeaderInfo();
                        }
                        PrintSubHeader=i;
                        resetShade();
                        break;
                    }
                }
            }
            IncrementRecordCount();
        }  // end of loop

        //System.out.println("end loop");
        LevelBreakTotals = RepTots.LevelBreakTotals;
        GroupRecCount = RepTots.GroupRecCount;
        if (FetchStatus == STATE_IDLE && RepTots.atEnd(currentRow+1) ) {
            if (SortCount > 0)
                printLevelBreak(1);
            if (dontPrint == 0 && !( Summary != 0 && "".equals(aSort[SortCount].totMsg)))
                print(FullRow);
            if (SortCount > 0)
                printTotalsForLevel(0);
        }

        printPageFooter(currentRow+1);
        
        PrintDebug("end print, recs="+currentRow);
        // If we have already printed PageCardStartDelim
        // then we need to print PageCardEndDelim to close the PageCard
        if (printedPageCardStartDelim ) {
            prop.setProperty("page",Integer.toString(pg));
            print(avParse.expandCmd(PageCardEndDelim,prop));
            printedPageCardStartDelim=false;
        }
    }

        
    public void custom_report(int startat, int endat)
    throws JspException {
        
        int i;
        long startTime=0, endTime=0;
        int firstTime = 1;
        int PrintSubHeader=-1;
        int StartTimer = 0;
        PrintedHeader = 0;
        boolean doHdrPrinting=false;
        int pg=CurrentPage;
        boolean printedPageCardStartDelim=false;
        lineCount=0;
        try {
            iLinesPerPage=Integer.parseInt(linesperpage);
        } catch (Exception e) {
        }
        setValueArray("linesperpage",linesperpage);
        if (TblType.equalsIgnoreCase("Query")) {
            for (i=0; i < FieldCount; i++) {
                for (int j=1; j <= SqlResults.numberOfColumns; j++) {
                    if (SqlResults.colName[j].equalsIgnoreCase(apFieldInfo[i].fldname)) {
                        apFieldInfo[i].ColmnInfoInx = j;
                        break;
                    }
                }
            }
        }
        
        if (TotalsId==0) {
            System.out.println("Create new report totals");
            setupReportTotals(SqlResults);
            TotalsId = Totals.saveTotals(RepTots);
        }
        else {
             System.out.println("Reusing report totals");
             if (FetchStatus == STATE_FETCH)
             {
                 FetchStatus = STATE_INTERRUPT;
                 while (FetchStatus != STATE_INTERRUPTED && FetchStatus != STATE_IDLE) {
                     System.out.println("Waiting for state to become interrupted, state="+FetchStatus);
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException ex) {
                        ex.printStackTrace();
                    }
                 }
             }
             RepTots = Totals.getTotals(TotalsId);
        }
        RepTots.setReportState(FetchStatus);
        
        boolean ContCond;
        
        if (startat== 0 || startat == 1)
            currentRow = 0;
        else
            currentRow = startat -1;
        SqlResults.positionRecordSet(currentRow);
        RepTots.initReport(startat);
    }
    
    int BreakLevel=-1;
    public boolean custom_next() throws JspException
    {
        BreakLevel=-1;
        boolean ContCond = SqlResults.next(true,true);
        currentRow++;
        if (currentRow >= endat) {
            moreData = 1;
        return false;
        }
                        
        for (int i=0; i < GraphCount; i++) {
            if (aGraph[i].SumValueFld != 1) {
                aGraph[i].update(SqlResults);  // update xtab graph
                addGraphValue(i,-1);
            }
        }
        // check&process level breaks
        int lvl=0;
        boolean DoBreak=false;
        boolean doHdrPrinting=false;
        for (int i=0; i < SortCount ; i++) {
            if (aSort[i].printtot == 1) {
                int fldNum;
                //lvl++;
                // user wants to print totals at this level so do the checking
                fldNum = apFieldInfo[aSort[i].fldNum].ColmnInfoInx;
                if ((lvl =RepTots.atLevelBreak(currentRow+1)) > 0   ) {
                    BreakLevel=lvl;
                    LevelBreakTotals = RepTots.LevelBreakTotals;
                    GroupRecCount = RepTots.GroupRecCount;
                    break;
                }
            }
        }
        LevelBreakTotals = RepTots.LevelBreakTotals;
        GroupRecCount = RepTots.GroupRecCount;
        
        return ContCond;
    }

    public int getCustomBreakLevel() {
        return BreakLevel;
    }

    public boolean AtPageBreak() {
            return RepTots.atPageBreak(currentRow);
    }
    
    public tagResults getReportResult() {
        return SqlResults;
    }
    
    
    /**************************************************************
     * executeQuery
     **************************************************************/
    public long CustomExecuteQuery()
    throws JspException {
        avProperties props;
        
        if (PrintWhereHeader)
            setValueArray("whereHeader",whereHeader.toString());
        else
            setValueArray("whereHeader"," ");
        setValueArray("CurrentPage",Integer.toString(CurrentPage+1));
        if (moreData != 1 ) {
            if (TableJoins.SimpleJoin) {
                props = new avProperties(sPath, datasrc + ".prop");
                SqlResults = new tagResults(props,SqlCommand,0,aInputVar,aInputVal, tagResults.SCROLLABLE);
            } else {
                SqlResults = CreateExMultipleSQLs();
                adjustFieldInfo();
                SqlResults.AddRange(JoinWhere);
            }
        }
        
        
        if (step > 0) {
            if (endat == 0 || endat > (startat + step))
                endat = startat + step;
        }
        
        if (endat < startat || (endat==0 ))
            endat = 999999999;
        
        
        custom_report(startat,endat);
        
        setValueArray("CurrentRow",Integer.toString(currentRow));
                
        if (moreData != 1)
            createGraphs();
        
        if (moreData != 1 ) {
            System.out.println("closing database");
            SqlResults.close();
        }
        
        return currentRow;
        
    }
    
    
    
    public int getNavRef() {
        return TotalsId;
    }

    
    void printPageFooter(int rec) throws JspException {
 	// cycle through all the fields and either print the field if it is part
	// of the key, or print the totals for the field or print a blank field
	int writeCount=0;
        int printedField;
        int seq=0;
        double [] tots =RepTots.getPageTotals();
        printColorLine("RowStartDelim",aSort[0].TotColor);
        printTotalSpanDelim("TotalsFieldStartDelim",0,aSort[0].TotColor);
        print(avParse.expandCmd(PageBreakText,prop));
        print(FieldEndDelim);
        print(RowEndDelim);

        if (tots ==null)
            return;
        printColorLine("RowStartDelim",aSort[0].TotColor);
        for (int i=0;i < FieldCount; i++)
	{
		int cinx;

		printedField=0;
		if (apFieldInfo[i].colDisplay != 1)
			continue;
		cinx = apFieldInfo[i].ColmnInfoInx;


		// print the field totals if they are to be printed
		if (printedField == 0 && apFieldInfo[i].Totals != NONE_FUNCTION)
		{
			printedField=1;

			switch (apFieldInfo[i].Totals) {
			  case  SUM_FUNCTION:
					printField(i,tots[seq], 0, 0);
					break;
			  case  MIN_FUNCTION:
					printField(i,tots[seq], 0, 0);
					break;
			  case  MAX_FUNCTION:
					printField(i,tots[seq], 0, 0);
					break;
			  case  AVG_FUNCTION:
					printField(i,tots[seq], 0, 0);
					break;
			}
                        seq++;
		}

		writeCount++;
		if (printedField == 0
			&& !BlankField.equals("")
			&& dontPrint == 0
			)
		{
			print(BlankField);
		}

	}   // end for
	//this.PrintDebug("skip fields = " + FieldsToSkip + "written fields=" + writeCount);

	// we have printed the detailed line, now print the end line
	if (dontPrint == 0)
	{
	   print(RowEndDelim);
	}       
    }
    
/** override the createGraphs() to do noting. The actual function is cslled from pagednav.jsp
 */
public void createGraphs()
{
    
}    

public void buildGroupingGraphs(int pos) throws JspException {
    int level=RepTots.getFirstGroupingLevel();
    int EndRec=RepTots.getFirstGroupingEndsAt() -1;
    //System.out.println("buildGroupingGraphs at pos="+pos+";level="+level);
    SqlResults.positionRecordSet(pos);
        for (int i=0; i < GraphCount; i++) {
            if (aGraph[i].SumValueFld == 1) {
               aGraph[i]=new graphinf(aGraph[i]); // create a new graph element to reset the totals
            }
        }

    while ( SqlResults.next(true,true) ) {
        pos++;
        for (int i=0; i < GraphCount; i++) {
            if (aGraph[i].SumValueFld == 1) {
                aGraph[i].update(SqlResults);  // update xtab graph
                addGraphValue(i,-1);
            } // endif
        } // endfor
        if (pos >= EndRec)
            break;
    } // wend
}

public void createPagedGraphs()
throws JspException
{
int i;
int GrouGraphStart;
boolean GroupingGraphs=false;
for (i=0; i < GraphCount; i++)
{
	 if (aGraph[i].SumValueFld == 1)
             GroupingGraphs=true;
}

if (GroupingGraphs) {
    GrouGraphStart = this.RepTots.getFirstGroupingRecord(StartingRecord);
    if (GrouGraphStart != -1)
        buildGroupingGraphs(GrouGraphStart);
}

boolean dispAll="1".equals(get_input_field_value("PRINTGRAPHS"));
for (i=0; i < GraphCount; i++)
{
	 //if (aGraph[i].SumValueFld != 1)
	 		aGraph[i].updateUsingX();
	 //System.out.println("to string="+aGraph[i].tots);
	 GraphValue gv=null;
	 GraphValue curr=null;
	 String GraphId=String.valueOf(aGraph[i].GraphID)+"_"+String.valueOf(aGraph[i].GraphUniqQual);
   prop.setProperty("GraphId",GraphId);
   String GraphFlag="YN"+aGraph[i].GraphID;
   String PrintFlag= get_input_field_value(GraphFlag);
   if ("1".equals(PrintFlag) || isEmbbededQuery ||dispAll)
   {
			if (!SaveReport) // this query is being run right now so just pass the memory vars
			{
	   		prop.setProperty("FileName","null");
				if ((aGraph[i].GraphType).equals("Piechart"))
				{
				   prop.setProperty("Width",String.valueOf(aGraph[i].piewidth));
				   prop.setProperty("Height",String.valueOf(aGraph[i].pieheight));
				}
				else
				{
				   prop.setProperty("Width",String.valueOf(aGraph[i].graphsize));
				   prop.setProperty("Height",String.valueOf(aGraph[i].blocksize));
				}
				print(avParse.expandCmd(getProp("GraphLine",prop),prop));
				
				// now save the graph info into temp storage so that it can be picked up by ChartServlet
				graphinf.saveGraphInfo(GraphId,aGraph[i]);
				//aGraph[i]=new graphinf(aGraph[i]); // create a new graph element to reset the totals
				continue;
			}
			
			// fall here if interaction with chart is not memory resident
			String FileName;
			FileName=sPath + "RRTemp" + File.separator + "graph" + aGraph[i].GraphID +"_"+ aGraph[i].GraphUniqQual + ".dat";
			try {
   			prop.setProperty("FileName",java.net.URLEncoder.encode(FileName,"UTF-8"));
   		} catch (Exception e) {};
			PrintWriter fp=null;
			try {
				fp	= new PrintWriter(new BufferedWriter
							(new FileWriter(FileName)) );
			} catch ( IOException e)
			{
				throw new JspException("Error" + e);
			}
                        
                        java.lang.Number data;
                        java.lang.String names;
                        java.util.Enumeration keys = aGraph[i].GraphResults.keys();
                        int cnt=0;
                        while (keys.hasMoreElements() )
                        {
                            names = (String)keys.nextElement();
                            gv= (GraphValue)aGraph[i].GraphResults.get(names);
                            if (cnt != 0)
                                fp.print(",");
                            fp.print(names);
                            cnt++;
                        }
			fp.println();

                        for (int num=0; num < 2; num++)
                        {
                            keys = aGraph[i].GraphResults.keys();
                            cnt=0;
                            while (keys.hasMoreElements() )
                            {
                                names = (String)keys.nextElement();
                                gv= (GraphValue)aGraph[i].GraphResults.get(names);
                                if (cnt != 0)
                                    fp.print(",");
                                fp.print(gv.value[num]);
                                cnt++;
                            }                 
                            fp.println();
                        }

                        fp.println(aGraph[i].GraphTitle);
			fp.println(aGraph[i].GraphType);
			fp.println(aGraph[i].GraphOrient);
                        fp.println(aGraph[i].BackgroundColor);
                        fp.close();
			if ((aGraph[i].GraphType).equals("Piechart"))
			{
			   prop.setProperty("Width",String.valueOf(aGraph[i].piewidth));
			   prop.setProperty("Height",String.valueOf(aGraph[i].pieheight));
			}
			else
			{
			   prop.setProperty("Width",String.valueOf(aGraph[i].graphsize));
			   prop.setProperty("Height",String.valueOf(aGraph[i].blocksize));
			}
			print(
			       avParse.expandCmd(getProp("GraphLine",prop),prop)
			     );
   } // end if
  } //end for
}


    
} // end of PagedReport class

