001    /*
002     * Copyright 2011 The Kuali Foundation.
003     * 
004     * Licensed under the Educational Community License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     * 
008     * http://www.opensource.org/licenses/ecl2.php
009     * 
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    package org.kuali.kfs.module.endow.report.util;
017    
018    import java.awt.Color;
019    import java.io.ByteArrayOutputStream;
020    import java.math.BigDecimal;
021    import java.util.ArrayList;
022    import java.util.Iterator;
023    import java.util.List;
024    import java.util.Set;
025    import java.util.TreeMap;
026    
027    import org.kuali.kfs.module.endow.EndowConstants;
028    import org.kuali.kfs.module.endow.EndowConstants.IncomePrincipalIndicator;
029    import org.kuali.kfs.module.endow.report.util.AssetStatementReportDataHolder.ReportGroupData;
030    import org.kuali.kfs.sys.KFSConstants;
031    
032    import com.lowagie.text.Document;
033    import com.lowagie.text.Element;
034    import com.lowagie.text.Font;
035    import com.lowagie.text.Paragraph;
036    import com.lowagie.text.pdf.PdfPCell;
037    import com.lowagie.text.pdf.PdfPTable;
038    import com.lowagie.text.pdf.PdfWriter;
039    
040    public class AssetStatementReportPrint extends EndowmentReportPrintBase {
041        
042        private final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(AssetStatementReportPrint.class);
043        
044        /**
045         * Generates all reports into one PDF file
046         * 
047         * @param reportHeaderDataHolderForEndowment
048         * @param reportHeaderDataHolderForNonEndowed
049         * @param endowmentAssetStatementReportDataHolders
050         * @param nonEndowedAssetStatementReportDataHolders
051         * @param endowmentOption
052         * @param reportOption
053         * @param listKemidsOnHeader
054         * @return
055         */
056        public ByteArrayOutputStream printAssetStatementReport(
057                EndowmentReportHeaderDataHolder reportHeaderDataHolderForEndowment, 
058                EndowmentReportHeaderDataHolder reportHeaderDataHolderForNonEndowed,
059                List<AssetStatementReportDataHolder> endowmentAssetStatementReportDataHolders, 
060                List<AssetStatementReportDataHolder> nonEndowedAssetStatementReportDataHolders, 
061                String endowmentOption,
062                String reportOption, 
063                String listKemidsInHeader) {
064            
065            // prepare iText document
066            Document document = new Document();
067            document.addTitle("Endowment Asset Statement");
068            
069            // this output stream will be returned to the user in PDF  
070            ByteArrayOutputStream pdfStream = new ByteArrayOutputStream();
071    
072            try {            
073                PdfWriter.getInstance(document, pdfStream);            
074                document.open();
075    
076                // generates a PDF based on the options and data
077                if (KFSConstants.ParameterValues.YES.equalsIgnoreCase(endowmentOption) && EndowConstants.EndowmentReport.DETAIL.equalsIgnoreCase(reportOption)) {
078                    if (endowmentAssetStatementReportDataHolders != null && endowmentAssetStatementReportDataHolders.size() > 0) {
079                        // endowment detail
080                        generateEndowmentDetailReport(endowmentAssetStatementReportDataHolders, reportHeaderDataHolderForEndowment, document, listKemidsInHeader, false);
081                    }
082                }
083                else if (KFSConstants.ParameterValues.YES.equalsIgnoreCase(endowmentOption) && EndowConstants.EndowmentReport.TOTAL.equalsIgnoreCase(reportOption)) {
084                    if (endowmentAssetStatementReportDataHolders != null && endowmentAssetStatementReportDataHolders.size() > 0) {
085                        // endowment total
086                        generateEndowmentTotalReport(endowmentAssetStatementReportDataHolders, reportHeaderDataHolderForEndowment, document, listKemidsInHeader, true);
087                    }
088                }
089                else if (KFSConstants.ParameterValues.YES.equalsIgnoreCase(endowmentOption) && EndowConstants.EndowmentReport.BOTH.equalsIgnoreCase(reportOption)) {
090                    if (endowmentAssetStatementReportDataHolders != null && endowmentAssetStatementReportDataHolders.size() > 0) {
091                        // endowment detail
092                        generateEndowmentDetailReport(endowmentAssetStatementReportDataHolders, reportHeaderDataHolderForEndowment, document, listKemidsInHeader, false);                    
093                        // endowment total
094                        generateEndowmentTotalReport(endowmentAssetStatementReportDataHolders, reportHeaderDataHolderForEndowment, document, listKemidsInHeader, true);
095                    }
096                }
097                else if (KFSConstants.ParameterValues.NO.equalsIgnoreCase(endowmentOption) && EndowConstants.EndowmentReport.DETAIL.equalsIgnoreCase(reportOption)) {
098                    if (nonEndowedAssetStatementReportDataHolders != null && nonEndowedAssetStatementReportDataHolders.size() > 0) {
099                        // non-endowed detail
100                        generateNonEndowedDetailReport(nonEndowedAssetStatementReportDataHolders, reportHeaderDataHolderForNonEndowed, document, listKemidsInHeader, false);
101                    }
102                }
103                else if (KFSConstants.ParameterValues.NO.equalsIgnoreCase(endowmentOption) && EndowConstants.EndowmentReport.TOTAL.equalsIgnoreCase(reportOption)) {
104                    if (nonEndowedAssetStatementReportDataHolders != null && nonEndowedAssetStatementReportDataHolders.size() > 0) {
105                        // non-endowed total
106                        generateNonEndowedTotalReport(nonEndowedAssetStatementReportDataHolders, reportHeaderDataHolderForNonEndowed, document, listKemidsInHeader, false);
107                    }
108                }
109                else if (KFSConstants.ParameterValues.NO.equalsIgnoreCase(endowmentOption) && EndowConstants.EndowmentReport.BOTH.equalsIgnoreCase(reportOption)) {
110                    if (nonEndowedAssetStatementReportDataHolders != null && nonEndowedAssetStatementReportDataHolders.size() > 0) {
111                        // non-endowed detail
112                        generateNonEndowedDetailReport(nonEndowedAssetStatementReportDataHolders, reportHeaderDataHolderForNonEndowed, document, listKemidsInHeader, false);
113                        // non-endowed total
114                        generateNonEndowedTotalReport(nonEndowedAssetStatementReportDataHolders, reportHeaderDataHolderForNonEndowed, document, listKemidsInHeader, true);
115                    }
116                }
117                else if (EndowConstants.EndowmentReport.BOTH.equalsIgnoreCase(endowmentOption) && EndowConstants.EndowmentReport.DETAIL.equalsIgnoreCase(reportOption)) {
118                    if (endowmentAssetStatementReportDataHolders != null && endowmentAssetStatementReportDataHolders.size() > 0) {
119                        // endowment detail
120                        generateEndowmentDetailReport(endowmentAssetStatementReportDataHolders, reportHeaderDataHolderForEndowment, document, listKemidsInHeader, false);
121                    }
122                    if (nonEndowedAssetStatementReportDataHolders != null && nonEndowedAssetStatementReportDataHolders.size() > 0) {
123                        // non-endowed detail
124                        generateNonEndowedDetailReport(nonEndowedAssetStatementReportDataHolders, reportHeaderDataHolderForNonEndowed, document, listKemidsInHeader, true);
125                    }
126                }
127                else if (EndowConstants.EndowmentReport.BOTH.equalsIgnoreCase(endowmentOption) && EndowConstants.EndowmentReport.TOTAL.equalsIgnoreCase(reportOption)) {
128                    if (endowmentAssetStatementReportDataHolders != null && endowmentAssetStatementReportDataHolders.size() > 0) {
129                        // endowment total
130                        generateEndowmentTotalReport(endowmentAssetStatementReportDataHolders, reportHeaderDataHolderForEndowment, document, listKemidsInHeader, false);
131                    }
132                    if (nonEndowedAssetStatementReportDataHolders != null && nonEndowedAssetStatementReportDataHolders.size() > 0) {
133                        // non-endowed total
134                        generateNonEndowedTotalReport(nonEndowedAssetStatementReportDataHolders, reportHeaderDataHolderForNonEndowed, document, listKemidsInHeader, true);
135                    }
136                }
137                else if (EndowConstants.EndowmentReport.BOTH.equalsIgnoreCase(endowmentOption) && EndowConstants.EndowmentReport.BOTH.equalsIgnoreCase(reportOption)) {
138                    if (endowmentAssetStatementReportDataHolders != null && endowmentAssetStatementReportDataHolders.size() > 0) {
139                        // endowment detail
140                        generateEndowmentDetailReport(endowmentAssetStatementReportDataHolders, reportHeaderDataHolderForEndowment, document, listKemidsInHeader, false); 
141                        // endowment total       
142                        generateEndowmentTotalReport(endowmentAssetStatementReportDataHolders, reportHeaderDataHolderForEndowment, document, listKemidsInHeader, true);
143                    }
144                    if (nonEndowedAssetStatementReportDataHolders != null && nonEndowedAssetStatementReportDataHolders.size() > 0) {
145                        // non-endowed detail
146                        generateNonEndowedDetailReport(nonEndowedAssetStatementReportDataHolders, reportHeaderDataHolderForNonEndowed, document, listKemidsInHeader, true);
147                        // non-endowed total
148                        generateNonEndowedTotalReport(nonEndowedAssetStatementReportDataHolders, reportHeaderDataHolderForNonEndowed, document, listKemidsInHeader, true);
149                    }
150                } 
151                
152                document.close();
153    
154            } catch (Exception e) {
155                LOG.error("Error in AssetStatementReportPrint:printAssetStatementReport(): " + e.getMessage());
156                return null;
157            }
158            
159            return pdfStream;
160        }
161    
162        /**
163         * Creates an endowment detail report in PDF 
164         * 
165         * @param endowmentAssetStatementReportDataHolders
166         * @param reportHeaderDataHolderForEndowment
167         * @param listKemidsInHeader
168         * @return
169         */
170        public ByteArrayOutputStream generateEndowmentDetailReport(List<AssetStatementReportDataHolder> endowmentAssetStatementReportDataHolders, EndowmentReportHeaderDataHolder reportHeaderDataHolderForEndowment, String listKemidsInHeader) {
171            ByteArrayOutputStream pdfStream = new ByteArrayOutputStream();
172            try {
173                Document document = new Document();
174                PdfWriter.getInstance(document, pdfStream);            
175                document.open();
176                generateEndowmentDetailReport(endowmentAssetStatementReportDataHolders, reportHeaderDataHolderForEndowment, document, listKemidsInHeader, false);
177                document.close();
178                return pdfStream;
179            } catch (Exception e) {
180                LOG.error("Error in generateEndowmentDetailReport(): " + e.getMessage());
181                return null;
182            }
183        }
184    
185        /**
186         * Creates an endowment total report in PDF 
187         * 
188         * @param endowmentAssetStatementReportDataHolders
189         * @param reportHeaderDataHolderForEndowment
190         * @param listKemidsInHeader
191         * @return
192         */
193        public ByteArrayOutputStream generateEndowmentTotalReport(List<AssetStatementReportDataHolder> endowmentAssetStatementReportDataHolders, EndowmentReportHeaderDataHolder reportHeaderDataHolderForEndowment, String listKemidsInHeader) {
194            ByteArrayOutputStream pdfStream = new ByteArrayOutputStream();
195            try {
196                Document document = new Document();
197                PdfWriter.getInstance(document, pdfStream);            
198                document.open();
199                generateEndowmentTotalReport(endowmentAssetStatementReportDataHolders, reportHeaderDataHolderForEndowment, document, listKemidsInHeader, false);
200                document.close();
201                return pdfStream;
202            } catch (Exception e) {
203                LOG.error("Error in generateEndowmentDetailReport(): " + e.getMessage());
204                return null;
205            }
206        }
207        
208        /**
209         * Creates a non-endowed detail report in PDF 
210         * 
211         * @param endowmentAssetStatementReportDataHolders
212         * @param reportHeaderDataHolderForEndowment
213         * @param listKemidsInHeader
214         * @return
215         */
216        public ByteArrayOutputStream generateNonEndowedDetailReport(List<AssetStatementReportDataHolder> nonEndowedAssetStatementReportDataHolders, EndowmentReportHeaderDataHolder reportHeaderDataHolderForNonEndowed, String listKemidsInHeader) {
217            ByteArrayOutputStream pdfStream = new ByteArrayOutputStream();
218            try {
219                Document document = new Document();
220                PdfWriter.getInstance(document, pdfStream);            
221                document.open();
222                generateNonEndowedDetailReport(nonEndowedAssetStatementReportDataHolders, reportHeaderDataHolderForNonEndowed, document, listKemidsInHeader, false);
223                document.close();
224                return pdfStream;
225            } catch (Exception e) {
226                LOG.error("Error in generateEndowmentDetailReport(): " + e.getMessage());
227                return null;
228            }
229        }
230        
231        /**
232         * Creates a non-endowed total report in PDF 
233         * 
234         * @param endowmentAssetStatementReportDataHolders
235         * @param reportHeaderDataHolderForEndowment
236         * @param listKemidsInHeader
237         * @return
238         */
239        public ByteArrayOutputStream generateNonEndowedTotalReport(List<AssetStatementReportDataHolder> nonEndowedAssetStatementReportDataHolders, EndowmentReportHeaderDataHolder reportHeaderDataHolderForNonEndowed, String listKemidsInHeader) {
240            ByteArrayOutputStream pdfStream = new ByteArrayOutputStream();
241            try {
242                Document document = new Document();
243                PdfWriter.getInstance(document, pdfStream);            
244                document.open();
245                generateNonEndowedTotalReport(nonEndowedAssetStatementReportDataHolders, reportHeaderDataHolderForNonEndowed, document, listKemidsInHeader, false);
246                document.close();
247                return pdfStream;
248            } catch (Exception e) {
249                LOG.error("Error in generateEndowmentDetailReport(): " + e.getMessage());
250                return null;
251            }
252        }
253        
254        /**
255         * Creates an endowment total report
256         * 
257         * @param endowmentAssetStatementReportDataHolders
258         * @param reportHeaderDataHolderForEndowment
259         * @param document
260         * @param listKemidsInHeader
261         * @param beginWithNewpage
262         */
263        protected void generateEndowmentDetailReport(List<AssetStatementReportDataHolder> endowmentAssetStatementReportDataHolders, EndowmentReportHeaderDataHolder reportHeaderDataHolderForEndowment, Document document, String listKemidsInHeader, boolean beginWithNewpage) {
264            document.setPageSize(LETTER_PORTRAIT);    
265            if (beginWithNewpage) setNewPage(document);
266            reportHeaderDataHolderForEndowment.setEndowmentOption(EndowConstants.EndowmentReport.ENDOWMENT);
267            reportHeaderDataHolderForEndowment.setReportOption(EndowConstants.EndowmentReport.DETAIL_REPORT);
268            printReportHeaderPage(reportHeaderDataHolderForEndowment, document, listKemidsInHeader);
269            
270            document.setPageSize(LETTER_LANDSCAPE);
271            printAssetStatementReportBodyForEndowmentDetail(endowmentAssetStatementReportDataHolders, document);
272        }
273     
274        /**
275         * Creates an endowment detail report
276         * 
277         * @param endowmentAssetStatementReportDataHolders
278         * @param reportHeaderDataHolderForEndowment
279         * @param document
280         * @param listKemidsInHeader
281         * @param beginWithNewpage
282         */
283        protected void generateEndowmentTotalReport(List<AssetStatementReportDataHolder> endowmentAssetStatementReportDataHolders, EndowmentReportHeaderDataHolder reportHeaderDataHolderForEndowment, Document document, String listKemidsInHeader, boolean beginWithNewpage) {
284            document.setPageSize(LETTER_PORTRAIT);
285            if (beginWithNewpage) setNewPage(document);
286            reportHeaderDataHolderForEndowment.setEndowmentOption(EndowConstants.EndowmentReport.ENDOWMENT);
287            reportHeaderDataHolderForEndowment.setReportOption(EndowConstants.EndowmentReport.TOTAL_REPORT);                    
288            printReportHeaderPage(reportHeaderDataHolderForEndowment, document, listKemidsInHeader);
289            
290            document.setPageSize(LETTER_LANDSCAPE);
291            printAssetStatementReportBodyForEndowmentTotal(endowmentAssetStatementReportDataHolders, document);
292        }
293        
294        /**
295         * Creates a non-endowed detail report
296         * 
297         * @param nonEndowedAssetStatementReportDataHolders
298         * @param reportHeaderDataHolderForNonEndowed
299         * @param document
300         * @param listKemidsInHeader
301         * @param beginWithNewpage
302         */
303        protected void generateNonEndowedDetailReport(List<AssetStatementReportDataHolder> nonEndowedAssetStatementReportDataHolders, EndowmentReportHeaderDataHolder reportHeaderDataHolderForNonEndowed, Document document, String listKemidsInHeader, boolean beginWithNewpage) {
304            document.setPageSize(LETTER_PORTRAIT);
305            if (beginWithNewpage) setNewPage(document);
306            reportHeaderDataHolderForNonEndowed.setEndowmentOption(EndowConstants.EndowmentReport.NON_ENDOWED);
307            reportHeaderDataHolderForNonEndowed.setReportOption(EndowConstants.EndowmentReport.DETAIL_REPORT);
308            printReportHeaderPage(reportHeaderDataHolderForNonEndowed, document, listKemidsInHeader);
309            
310            document.setPageSize(LETTER_LANDSCAPE);
311            printAssetStatementReportBodyForNonEndowedDetail(nonEndowedAssetStatementReportDataHolders, document);
312        }
313        
314        /**
315         * Creates a non-endowed total report
316         * 
317         * @param nonEndowedAssetStatementReportDataHolders
318         * @param reportHeaderDataHolderForNonEndowed
319         * @param document
320         * @param listKemidsInHeader
321         * @param beginWithNewpage
322         */
323        protected void generateNonEndowedTotalReport(List<AssetStatementReportDataHolder> nonEndowedAssetStatementReportDataHolders, EndowmentReportHeaderDataHolder reportHeaderDataHolderForNonEndowed, Document document, String listKemidsInHeader, boolean beginWithNewpage) {
324            document.setPageSize(LETTER_PORTRAIT);
325            if (beginWithNewpage) setNewPage(document);
326            reportHeaderDataHolderForNonEndowed.setEndowmentOption(EndowConstants.EndowmentReport.NON_ENDOWED);
327            reportHeaderDataHolderForNonEndowed.setReportOption(EndowConstants.EndowmentReport.TOTAL_REPORT);
328            printReportHeaderPage(reportHeaderDataHolderForNonEndowed, document, listKemidsInHeader);
329                                
330            document.setPageSize(LETTER_LANDSCAPE);
331            printAssetStatementReportBodyForNonEndowedTotal(nonEndowedAssetStatementReportDataHolders, document);
332        }
333        
334        /**
335         * Sets the page break
336         * 
337         * @param document
338         */
339        protected void setNewPage(Document document) {
340            try {
341                document.newPage();
342            } catch (Exception e) {
343                LOG.error("New Page Error: " + e.getMessage());
344                return;
345            }
346        } 
347        
348        /**
349         * Prints report body for endowment detail
350         * 
351         * @param endowmentAssetStatementReportDataHolders
352         * @param document
353         * @return
354         */
355        public boolean printAssetStatementReportBodyForEndowmentTotal(List<AssetStatementReportDataHolder> endowmentAssetStatementReportDataHolders, Document document) {
356            
357            BigDecimal totalHistoryIncomeCash = BigDecimal.ZERO;
358            BigDecimal totalHistoryPrincipalCash = BigDecimal.ZERO;
359            TreeMap<Integer, TreeMap<String, List<ReportGroupData>>> reportGroupsForIncomeTotal = null;
360            TreeMap<Integer, TreeMap<String, List<ReportGroupData>>> reportGroupsForPrincipalTotal = null;
361    
362            // get the cash totals
363            for (AssetStatementReportDataHolder data : endowmentAssetStatementReportDataHolders) {
364                totalHistoryIncomeCash = totalHistoryIncomeCash.add(data.getHistoryIncomeCash());
365                totalHistoryPrincipalCash = totalHistoryPrincipalCash.add(data.getHistoryPrincipalCash());
366            }
367            
368            // for income
369            reportGroupsForIncomeTotal = createReportGroupsForTotal(endowmentAssetStatementReportDataHolders, IncomePrincipalIndicator.INCOME);
370            
371            // for principal
372            reportGroupsForPrincipalTotal = createReportGroupsForTotal(endowmentAssetStatementReportDataHolders, IncomePrincipalIndicator.PRINCIPAL);
373                    
374            // for each kemid
375            try {                               
376                Font cellFont = regularFont;
377            
378                // for the common info
379                AssetStatementReportDataHolder reportData = endowmentAssetStatementReportDataHolders.get(0);
380                
381                document.newPage();
382                
383                // header
384                StringBuffer title = new StringBuffer();
385                title.append(reportData.getInstitution()).append("\n");
386                title.append("STATEMENT OF ASSETS FOR PERIOD ENDING").append("\n");
387                title.append(reportData.getMonthEndDate()).append("\n\n");
388                Paragraph header = new Paragraph(title.toString());
389                header.setAlignment(Element.ALIGN_CENTER);                
390                document.add(header);
391    
392                // report table
393                float[] colsWidth = {15f, 17f, 17f, 17f, 17f, 17f};
394                PdfPTable table = new PdfPTable(colsWidth);
395                table.setWidthPercentage(FULL_TABLE_WIDTH);                
396                table.getDefaultCell().setPadding(5);
397                
398                // column titles
399                table.addCell("");
400                table.addCell(createCell("UNITS HELD", titleFont, Element.ALIGN_RIGHT, true));
401                table.addCell(createCell("MARKET VALUE", titleFont, Element.ALIGN_RIGHT, true));
402                table.addCell(createCell("ESTIMATED\nANNUAL INCOME", titleFont, Element.ALIGN_RIGHT, true));
403                table.addCell(createCell("FY REMAINDER ESTIMATED\nANNUAL INCOME", titleFont, Element.ALIGN_RIGHT, true));
404                table.addCell(createCell("NEXT FY ESTIMATED\nANNUAL INCOME", titleFont, Element.ALIGN_RIGHT, true));
405                              
406                // 1. Expendable funds 
407                
408                PdfPCell cellExpendableFunds = new PdfPCell(new Paragraph("EXPENDABLE FUNDS", titleFont));
409                cellExpendableFunds.setColspan(6);
410                table.addCell(cellExpendableFunds);
411                
412                PdfPCell cellCashEquivalnets = new PdfPCell(new Paragraph("CASH AND EQUIVALENTS", titleFont));
413                cellCashEquivalnets.setColspan(6);
414                table.addCell(cellCashEquivalnets);
415    
416                // report groups for income
417                printReportGroupForIncomeEndowmentTotal(reportGroupsForIncomeTotal, totalHistoryIncomeCash, document, table, cellFont);
418                
419                // 2. Endowed funds 
420                
421                PdfPCell cellEndowedFunds = new PdfPCell(new Paragraph("ENDOWED FUNDS", titleFont));
422                cellEndowedFunds.setColspan(6);
423                table.addCell(cellEndowedFunds);
424     
425                table.addCell(cellCashEquivalnets);
426                    
427                // report groups for principal
428                printReportGroupForPrincipalEndowmentTotal(reportGroupsForPrincipalTotal, totalHistoryPrincipalCash, document, table, cellFont);
429                
430                // 3. total (endowment + non-endowed)
431                PdfPCell blank = new PdfPCell(new Paragraph("", cellFont));
432                blank.setColspan(6);
433                blank.setBackgroundColor(Color.LIGHT_GRAY);
434                table.addCell(blank);
435                
436                BigDecimal totalKemidMarketValue = BigDecimal.ZERO;
437                BigDecimal totalKemidEstimatedAnnualIncome = BigDecimal.ZERO;
438                BigDecimal totalKemidFYRemainderEstimatedAnnualIncome = BigDecimal.ZERO;
439                BigDecimal totalKemidNextFYEstimayedAnnualIncome = BigDecimal.ZERO;
440                for (AssetStatementReportDataHolder data : endowmentAssetStatementReportDataHolders) {
441                    totalKemidMarketValue = totalKemidMarketValue.add(data.getTotalSumOfMarketValue(IncomePrincipalIndicator.INCOME).add(data.getTotalSumOfMarketValue(IncomePrincipalIndicator.PRINCIPAL)));
442                    totalKemidEstimatedAnnualIncome = totalKemidEstimatedAnnualIncome.add(data.getTotalSumOfEstimatedIncome(IncomePrincipalIndicator.INCOME).add(data.getTotalSumOfEstimatedIncome(IncomePrincipalIndicator.PRINCIPAL)));
443                    totalKemidFYRemainderEstimatedAnnualIncome = totalKemidFYRemainderEstimatedAnnualIncome.add(data.getTotalSumOfRemainderOfFYEstimated(IncomePrincipalIndicator.INCOME).add(data.getTotalSumOfRemainderOfFYEstimated(IncomePrincipalIndicator.PRINCIPAL)));
444                    totalKemidNextFYEstimayedAnnualIncome = totalKemidNextFYEstimayedAnnualIncome.add(data.getTotalSumOfNextFYEstimatedIncome(IncomePrincipalIndicator.INCOME).add(data.getTotalSumOfNextFYEstimatedIncome(IncomePrincipalIndicator.PRINCIPAL)));
445                }
446                
447                table.addCell(new Paragraph("TOTAL KEMID VALUE", titleFont));
448                table.addCell("");
449                table.addCell(getAmountCell(totalKemidMarketValue.add(totalHistoryIncomeCash).add(totalHistoryPrincipalCash), titleFont));
450                table.addCell(getAmountCell(totalKemidEstimatedAnnualIncome, titleFont));
451                table.addCell(getAmountCell(totalKemidFYRemainderEstimatedAnnualIncome, titleFont));
452                table.addCell(getAmountCell(totalKemidNextFYEstimayedAnnualIncome, titleFont));
453                
454                document.add(table);
455                
456            } catch (Exception e) {
457                LOG.error(e.getMessage());
458                return false;
459            }
460            
461            return true;
462    
463        }
464     
465        /**
466         * Generates the Asset Statement report for Non-Endowed total 
467         * 
468         * @param transactionStatementReports
469         * @param document
470         * @return
471         */
472        public boolean printAssetStatementReportBodyForNonEndowedTotal(List<AssetStatementReportDataHolder> nonEndowedAssetStatementReportDataHolders, Document document) {
473            
474            BigDecimal totalHistoryIncomeCash = BigDecimal.ZERO;
475            BigDecimal totalHistoryPrincipalCash = BigDecimal.ZERO;
476            TreeMap<Integer, TreeMap<String, List<ReportGroupData>>> reportGroupsForTotal = null;
477    
478            // get the cash totals
479            for (AssetStatementReportDataHolder data : nonEndowedAssetStatementReportDataHolders) {
480                totalHistoryIncomeCash = totalHistoryIncomeCash.add(data.getHistoryIncomeCash());
481                totalHistoryPrincipalCash = totalHistoryPrincipalCash.add(data.getHistoryPrincipalCash());
482            }
483            
484            reportGroupsForTotal = createReportGroupsForTotal(nonEndowedAssetStatementReportDataHolders, IncomePrincipalIndicator.INCOME);
485    
486            // for each kemid
487            try {                               
488                Font cellFont = regularFont;
489            
490                // for the common info
491                AssetStatementReportDataHolder reportData = nonEndowedAssetStatementReportDataHolders.get(0);
492                
493                document.newPage();
494                
495                // header
496                StringBuffer title = new StringBuffer();
497                title.append(reportData.getInstitution()).append("\n");
498                title.append("STATEMENT OF ASSETS FOR PERIOD ENDING").append("\n");
499                title.append(reportData.getMonthEndDate()).append("\n\n");
500                Paragraph header = new Paragraph(title.toString());
501                header.setAlignment(Element.ALIGN_CENTER);                
502                document.add(header);
503    
504                // report table
505                float[] colsWidth = {15f, 17f, 17f, 17f, 17f, 17f};
506                PdfPTable table = new PdfPTable(colsWidth);
507                table.setWidthPercentage(FULL_TABLE_WIDTH);                
508                table.getDefaultCell().setPadding(5);
509                
510                // column titles
511                table.addCell("");
512                table.addCell(createCell("UNITS HELD", titleFont, Element.ALIGN_RIGHT, true));
513                table.addCell(createCell("MARKET VALUE", titleFont, Element.ALIGN_RIGHT, true));
514                table.addCell(createCell("ESTIMATED\nANNUAL INCOME", titleFont, Element.ALIGN_RIGHT, true));
515                table.addCell(createCell("FY REMAINDER ESTIMATED\nANNUAL INCOME", titleFont, Element.ALIGN_RIGHT, true));
516                table.addCell(createCell("NEXT FY ESTIMATED\nANNUAL INCOME", titleFont, Element.ALIGN_RIGHT, true));
517                
518                PdfPCell cellCashEquivalnets = new PdfPCell(new Paragraph("CASH AND EQUIVALENTS", titleFont));
519                cellCashEquivalnets.setColspan(6);
520                table.addCell(cellCashEquivalnets);
521    
522                // report groups
523                printReportGroupForNonEndowedTotal(reportGroupsForTotal, totalHistoryIncomeCash, totalHistoryPrincipalCash, document, table, cellFont);
524                                     
525                // total
526                PdfPCell blank = new PdfPCell(new Paragraph("", cellFont));
527                blank.setColspan(6);
528                blank.setBackgroundColor(Color.LIGHT_GRAY);
529                table.addCell(blank);
530                
531                BigDecimal totalKemidMarketValue = BigDecimal.ZERO;
532                BigDecimal totalKemidEstimatedAnnualIncome = BigDecimal.ZERO;
533                BigDecimal totalKemidFYRemainderEstimatedAnnualIncome = BigDecimal.ZERO;
534                BigDecimal totalKemidNextFYEstimayedAnnualIncome = BigDecimal.ZERO;
535                for (AssetStatementReportDataHolder data : nonEndowedAssetStatementReportDataHolders) {
536                    totalKemidMarketValue = totalKemidMarketValue.add(data.getTotalSumOfMarketValue(IncomePrincipalIndicator.INCOME));
537                    totalKemidEstimatedAnnualIncome = totalKemidEstimatedAnnualIncome.add(data.getTotalSumOfEstimatedIncome(IncomePrincipalIndicator.INCOME));
538                    totalKemidFYRemainderEstimatedAnnualIncome = totalKemidFYRemainderEstimatedAnnualIncome.add(totalKemidFYRemainderEstimatedAnnualIncome.add(data.getTotalSumOfRemainderOfFYEstimated(IncomePrincipalIndicator.INCOME)));
539                    totalKemidNextFYEstimayedAnnualIncome = totalKemidNextFYEstimayedAnnualIncome.add(data.getTotalSumOfNextFYEstimatedIncome(IncomePrincipalIndicator.INCOME));
540                }
541                
542                table.addCell(new Paragraph("TOTAL KEMID VALUE", titleFont));
543                table.addCell("");
544                table.addCell(getAmountCell(totalKemidMarketValue.add(totalHistoryIncomeCash).add(totalHistoryPrincipalCash), titleFont));
545                table.addCell(getAmountCell(totalKemidEstimatedAnnualIncome, titleFont));
546                table.addCell(getAmountCell(totalKemidFYRemainderEstimatedAnnualIncome, titleFont));
547                table.addCell(getAmountCell(totalKemidNextFYEstimayedAnnualIncome, titleFont));
548                
549                document.add(table);
550                
551            } catch (Exception e) {
552                LOG.error(e.getMessage());
553                return false;
554            }
555            
556            return true;
557        }
558        
559        /**
560         * Generates the Asset Statement report for Endowment detail  
561         * 
562         * @param transactionStatementReports
563         * @param document
564         * @return
565         */
566        public boolean printAssetStatementReportBodyForEndowmentDetail(List<AssetStatementReportDataHolder> endowmentAssetStatementReportDataHolders, Document document) {
567    
568            // for each kemid
569            try {                               
570                Font cellFont = regularFont;
571                for (AssetStatementReportDataHolder reportData : endowmentAssetStatementReportDataHolders) {
572                                    
573                    document.newPage();
574                    
575                    // header
576                    StringBuffer title = new StringBuffer();
577                    title.append(reportData.getInstitution()).append("\n");
578                    title.append("STATEMENT OF ASSETS FOR PERIOD ENDING").append("\n");
579                    title.append(reportData.getMonthEndDate()).append("\n");
580                    title.append(reportData.getKemid()).append("     ").append(reportData.getKemidLongTitle()).append("\n\n");
581                    Paragraph header = new Paragraph(title.toString());
582                    header.setAlignment(Element.ALIGN_CENTER);                
583                    document.add(header);
584    
585                    // report table
586                    float[] colsWidth = {15f, 17f, 17f, 17f, 17f, 17f};
587                    PdfPTable table = new PdfPTable(colsWidth);
588                    table.setWidthPercentage(FULL_TABLE_WIDTH);                
589                    table.getDefaultCell().setPadding(5);
590                    
591                    // column titles
592                    table.addCell("");
593                    table.addCell(createCell("UNITS HELD", titleFont, Element.ALIGN_RIGHT, true));
594                    table.addCell(createCell("MARKET VALUE", titleFont, Element.ALIGN_RIGHT, true));
595                    table.addCell(createCell("ESTIMATED\nANNUAL INCOME", titleFont, Element.ALIGN_RIGHT, true));
596                    table.addCell(createCell("FY REMAINDER ESTIMATED\nANNUAL INCOME", titleFont, Element.ALIGN_RIGHT, true));
597                    table.addCell(createCell("NEXT FY ESTIMATED\nANNUAL INCOME", titleFont, Element.ALIGN_RIGHT, true));
598                                  
599                    // 1. Expendable funds 
600                    
601                    PdfPCell cellExpendableFunds = new PdfPCell(new Paragraph("EXPENDABLE FUNDS", titleFont));
602                    cellExpendableFunds.setColspan(6);
603                    //cellExpendableFunds.setBackgroundColor(Color.LIGHT_GRAY);
604                    table.addCell(cellExpendableFunds);
605                    
606                    PdfPCell cellCashEquivalnets = new PdfPCell(new Paragraph("CASH AND EQUIVALENTS", cellFont));
607                    cellCashEquivalnets.setColspan(6);
608                    table.addCell(cellCashEquivalnets);
609    
610                    // report groups 
611                    printReportGroupForIncomeEndowmentDetail(reportData, document, table, cellFont);
612                    
613                    // 2. Endowed funds 
614                    
615                    PdfPCell cellEndowedFunds = new PdfPCell(new Paragraph("ENDOWED FUNDS", titleFont));
616                    cellEndowedFunds.setColspan(6);
617                    //cellEndowedFunds.setBackgroundColor(Color.LIGHT_GRAY);
618                    table.addCell(cellEndowedFunds);
619     
620                    table.addCell(cellCashEquivalnets);
621                    
622                    printReportGroupForPrincipalEndowmentDetail(reportData, document, table, cellFont);
623                    
624                    // 3. total (endowment + non-endowed)
625                    PdfPCell blank = new PdfPCell(new Paragraph("", cellFont));
626                    blank.setColspan(6);
627                    blank.setBackgroundColor(Color.LIGHT_GRAY);
628                    table.addCell(blank);
629                    
630                    BigDecimal totalKemidMarketValue = reportData.getTotalSumOfMarketValue(IncomePrincipalIndicator.INCOME).add(reportData.getHistoryIncomeCash())
631                            .add(reportData.getTotalSumOfMarketValue(IncomePrincipalIndicator.PRINCIPAL).add(reportData.getHistoryPrincipalCash()));
632                    BigDecimal totalKemidEstimatedAnnualIncome = reportData.getTotalSumOfEstimatedIncome(IncomePrincipalIndicator.INCOME).add(reportData.getTotalSumOfEstimatedIncome(IncomePrincipalIndicator.PRINCIPAL));
633                    BigDecimal totalKemidFYRemainderEstimatedAnnualIncome = reportData.getTotalSumOfRemainderOfFYEstimated(IncomePrincipalIndicator.INCOME).add(reportData.getTotalSumOfRemainderOfFYEstimated(IncomePrincipalIndicator.PRINCIPAL));
634                    BigDecimal totalKemidNextFYEstimayedAnnualIncome = reportData.getTotalSumOfNextFYEstimatedIncome(IncomePrincipalIndicator.INCOME).add(reportData.getTotalSumOfNextFYEstimatedIncome(IncomePrincipalIndicator.PRINCIPAL));
635                    
636                    table.addCell(new Paragraph("TOTAL KEMID VALUE", titleFont));
637                    table.addCell("");
638                    table.addCell(getAmountCell(totalKemidMarketValue, titleFont));
639                    table.addCell(getAmountCell(totalKemidEstimatedAnnualIncome, titleFont));
640                    table.addCell(getAmountCell(totalKemidFYRemainderEstimatedAnnualIncome, titleFont));
641                    table.addCell(getAmountCell(totalKemidNextFYEstimayedAnnualIncome, titleFont));
642                    
643                    document.add(table);
644                    
645                    // footer
646                    printFooter(reportData.getFooter(), document);
647                }
648            } catch (Exception e) {
649                LOG.error(e.getMessage());
650                return false;
651            }
652            
653            return true;
654        }
655     
656        /**
657         * Generates the Asset Statement report for Non-Endowed    
658         * 
659         * @param transactionStatementReports
660         * @param document
661         * @return
662         */
663        public boolean printAssetStatementReportBodyForNonEndowedDetail(List<AssetStatementReportDataHolder> nonEndowedAssetStatementReportDataHolders, Document document) {
664            
665            // for each kemid
666            try {                               
667                Font cellFont = regularFont;
668                for (AssetStatementReportDataHolder reportData : nonEndowedAssetStatementReportDataHolders) {
669                    
670                    document.newPage();
671                    
672                    // header
673                    StringBuffer title = new StringBuffer();
674                    title.append(reportData.getInstitution()).append("\n");
675                    title.append("STATEMENT OF ASSETS FOR PERIOD ENDING").append("\n");
676                    title.append(reportData.getMonthEndDate()).append("\n");
677                    title.append(reportData.getKemid()).append("     ").append(reportData.getKemidLongTitle()).append("\n\n");
678                    Paragraph header = new Paragraph(title.toString());
679                    header.setAlignment(Element.ALIGN_CENTER);                
680                    document.add(header);
681    
682                    // report table
683                    float[] colsWidth = {15f, 17f, 17f, 17f, 17f, 17f};
684                    PdfPTable table = new PdfPTable(colsWidth);
685                    table.setWidthPercentage(FULL_TABLE_WIDTH);                
686                    table.getDefaultCell().setPadding(5);
687                    
688                    // column titles
689                    table.addCell("");
690                    table.addCell(createCell("UNITS HELD", titleFont, Element.ALIGN_RIGHT, true));
691                    table.addCell(createCell("MARKET VALUE", titleFont, Element.ALIGN_RIGHT, true));
692                    table.addCell(createCell("ESTIMATED\nANNUAL INCOME", titleFont, Element.ALIGN_RIGHT, true));
693                    table.addCell(createCell("FY REMAINDER ESTIMATED\nANNUAL INCOME", titleFont, Element.ALIGN_RIGHT, true));
694                    table.addCell(createCell("NEXT FY ESTIMATED\nANNUAL INCOME", titleFont, Element.ALIGN_RIGHT, true));
695                                  
696                    PdfPCell cellCashEquivalnets = new PdfPCell(new Paragraph("CASH AND EQUIVALENTS", cellFont));
697                    cellCashEquivalnets.setColspan(6);
698                    table.addCell(cellCashEquivalnets);
699    
700                    // report groups 
701                    printReportGroupForNonEndowedDetail(reportData, document, table, cellFont);
702                    
703                    // total
704                    PdfPCell blank = new PdfPCell(new Paragraph("", cellFont));
705                    blank.setColspan(6);
706                    blank.setBackgroundColor(Color.LIGHT_GRAY);
707                    table.addCell(blank);
708                    
709                    BigDecimal totalKemidMarketValue = reportData.getTotalSumOfMarketValue(IncomePrincipalIndicator.INCOME).add(reportData.getHistoryIncomeCash()).add(reportData.getHistoryPrincipalCash());
710                    BigDecimal totalKemidEstimatedAnnualIncome = reportData.getTotalSumOfEstimatedIncome(IncomePrincipalIndicator.INCOME).add(reportData.getTotalSumOfEstimatedIncome(IncomePrincipalIndicator.PRINCIPAL));
711                    BigDecimal totalKemidFYRemainderEstimatedAnnualIncome = reportData.getTotalSumOfRemainderOfFYEstimated(IncomePrincipalIndicator.INCOME).add(reportData.getTotalSumOfRemainderOfFYEstimated(IncomePrincipalIndicator.PRINCIPAL));
712                    BigDecimal totalKemidNextFYEstimayedAnnualIncome = reportData.getTotalSumOfNextFYEstimatedIncome(IncomePrincipalIndicator.INCOME).add(reportData.getTotalSumOfNextFYEstimatedIncome(IncomePrincipalIndicator.PRINCIPAL));
713                    
714                    table.addCell(new Paragraph("TOTAL KEMID VALUE", titleFont));
715                    table.addCell("");
716                    table.addCell(getAmountCell(totalKemidMarketValue, titleFont));
717                    table.addCell(getAmountCell(totalKemidEstimatedAnnualIncome, titleFont));
718                    table.addCell(getAmountCell(totalKemidFYRemainderEstimatedAnnualIncome, titleFont));
719                    table.addCell(getAmountCell(totalKemidNextFYEstimayedAnnualIncome, titleFont));
720                    
721                    document.add(table);
722                    
723                    // footer
724                    printFooter(reportData.getFooter(), document);
725                }
726            } catch (Exception e) {
727                LOG.error(e.getMessage());
728                return false;
729            }
730            
731            return true;
732        }
733        
734        /**
735         * Generates report group for income endowment detail
736         * 
737         * @param reportData
738         * @param docuement
739         * @param table
740         * @param cellFont
741         * @throws Exception
742         */
743        protected void printReportGroupForIncomeEndowmentDetail(AssetStatementReportDataHolder reportData, Document docuement, PdfPTable table, Font cellFont) throws Exception {
744                    
745            table.addCell(new Paragraph("Income Cash", cellFont));
746            table.addCell("");
747            table.addCell(getAmountCell(reportData.getHistoryIncomeCash(), cellFont));
748            table.addCell("");
749            table.addCell("");
750            table.addCell("");
751            
752            TreeMap<Integer, TreeMap<String, ReportGroupData>> reportGroups = reportData.getReportGroupsForIncome();
753            
754            if (reportGroups == null || reportGroups.isEmpty()) {
755                table.addCell(new Paragraph("TOTAL CASH AND\nEQUIVALENTS", cellFont));
756                table.addCell("");
757                table.addCell(getAmountCell(reportData.getHistoryIncomeCash(), cellFont));
758                table.addCell("");
759                table.addCell("");
760                table.addCell("");
761                return;
762            }
763            
764            // Cash and equivalents first
765            TreeMap<String, ReportGroupData> cashEquivalentsData = reportData.getReportGroupsForIncome().get(1);
766            if (cashEquivalentsData != null && !cashEquivalentsData.isEmpty()) {
767                Iterator<String> secirutyIdSet = cashEquivalentsData.keySet().iterator();        
768                while (secirutyIdSet.hasNext()) {
769                    // get securityId
770                    String securityId = secirutyIdSet.next();
771                    ReportGroupData data = cashEquivalentsData.get(securityId);
772                    table.addCell(new Paragraph(data.getSecurityDesc(), cellFont));
773                    table.addCell(getAmountCell(data.getSumOfUnits(), cellFont, FORMAT164));
774                    table.addCell(getAmountCell(data.getSumOfMarketValue(), cellFont));
775                    table.addCell(getAmountCell(data.getSumOfEstimatedIncome(), cellFont));
776                    table.addCell(getAmountCell(data.getSumOfRemainderOfFYEstimated(), cellFont));
777                    table.addCell(getAmountCell(data.getSumOfNextFYEstimatedIncome(), cellFont));
778                }
779            }    
780            table.addCell(new Paragraph("TOTAL CASH AND\nEQUIVALENTS", cellFont));
781            table.addCell("");
782            table.addCell(getAmountCell(reportData.getTotalMarketValueForCashEquivalents(IncomePrincipalIndicator.INCOME).add(reportData.getHistoryIncomeCash()), cellFont));
783            table.addCell("");
784            table.addCell("");
785            table.addCell("");            
786            
787            // Other report group
788            Iterator<Integer> reportGroupOrderSet = reportGroups.keySet().iterator();
789            while (reportGroupOrderSet.hasNext()) {                    
790                
791                Integer reportGroupOrder = reportGroupOrderSet.next();
792                if (reportGroupOrder.intValue() > 1) {                  
793                    TreeMap<String, ReportGroupData> reportGroupData = reportData.getReportGroupsForIncome().get(reportGroupOrder);
794                    if (reportGroupData == null || reportGroupData.isEmpty()) {
795                        continue;
796                    }
797                    // print report group description
798                    String reportGroupDesc = reportGroupData.firstEntry().getValue().getReportGroupDesc();
799                    PdfPCell groupDescCell = new PdfPCell(new Paragraph(reportGroupDesc, cellFont));
800                    groupDescCell.setColspan(6);
801                    table.addCell(groupDescCell); 
802                    
803                    // print info per security  
804                    Iterator<String> secirutyIdSet = reportGroupData.keySet().iterator();
805                    while (secirutyIdSet.hasNext()) {
806                        String securityId = secirutyIdSet.next();
807                        ReportGroupData data = reportGroupData.get(securityId); 
808                        table.addCell(new Paragraph(data.getSecurityDesc(), cellFont));
809                        table.addCell(getAmountCell(data.getSumOfUnits(), cellFont, FORMAT164));
810                        table.addCell(getAmountCell(data.getSumOfMarketValue(), cellFont));
811                        table.addCell(getAmountCell(data.getSumOfEstimatedIncome(), cellFont));
812                        table.addCell(getAmountCell(data.getSumOfRemainderOfFYEstimated(), cellFont));
813                        table.addCell(getAmountCell(data.getSumOfNextFYEstimatedIncome(), cellFont));
814                    }
815                    
816                    // report group totals
817                    table.addCell(new Paragraph("TOTAL " + convertToUpperCase(reportGroupDesc), cellFont));
818                    table.addCell("");
819                    table.addCell(getAmountCell(reportData.getTotalSumOfMarketValue(IncomePrincipalIndicator.INCOME, reportGroupOrder), cellFont));
820                    table.addCell("");
821                    table.addCell("");
822                    table.addCell("");
823                }
824            }
825    
826            // total expendable funds
827            table.addCell(new Paragraph("TOTAL EXPENDABLE FUNDS", titleFont));
828            table.addCell("");
829            table.addCell(getAmountCell(reportData.getTotalSumOfMarketValue(IncomePrincipalIndicator.INCOME).add(reportData.getHistoryIncomeCash()), cellFont));
830            table.addCell(getAmountCell(reportData.getTotalSumOfEstimatedIncome(IncomePrincipalIndicator.INCOME), cellFont));
831            table.addCell(getAmountCell(reportData.getTotalSumOfRemainderOfFYEstimated(IncomePrincipalIndicator.INCOME), cellFont));
832            table.addCell(getAmountCell(reportData.getTotalSumOfNextFYEstimatedIncome(IncomePrincipalIndicator.INCOME), cellFont));                  
833        }
834    
835        /**
836         * Generates report group for principal endowment detail
837         * 
838         * @param reportData
839         * @param docuement
840         * @param table
841         * @param cellFont
842         */
843        protected void printReportGroupForPrincipalEndowmentDetail(AssetStatementReportDataHolder reportData, Document docuement, PdfPTable table, Font cellFont) {
844           
845            table.addCell(new Paragraph("Principal Cash", cellFont));
846            table.addCell("");
847            table.addCell(getAmountCell(reportData.getHistoryPrincipalCash(), cellFont));
848            table.addCell("");
849            table.addCell("");
850            table.addCell("");
851                                                        
852            TreeMap<Integer, TreeMap<String, ReportGroupData>> reportGroups = reportData.getReportGroupsForPrincipal();
853            if (reportGroups == null || reportGroups.isEmpty()) {
854                table.addCell(new Paragraph("TOTAL CASH AND\nEQUIVALENTS", cellFont));
855                table.addCell("");
856                table.addCell(getAmountCell(reportData.getHistoryPrincipalCash(), cellFont));
857                table.addCell("");
858                table.addCell("");
859                table.addCell("");
860                return;
861            }
862            
863            // Cash and equivalents first
864            TreeMap<String, ReportGroupData> cashEquivalentsData = reportData.getReportGroupsForPrincipal().get(1);
865            if (cashEquivalentsData != null && !cashEquivalentsData.isEmpty()) {
866                Iterator<String> secirutyIdSet = cashEquivalentsData.keySet().iterator();
867                while (secirutyIdSet.hasNext()) {
868                    // get securityId
869                    String securityId = secirutyIdSet.next();
870                    ReportGroupData data = cashEquivalentsData.get(securityId);
871                    table.addCell(new Paragraph(data.getSecurityDesc(), cellFont));
872                    table.addCell(getAmountCell(data.getSumOfUnits(), cellFont, FORMAT164));
873                    table.addCell(getAmountCell(data.getSumOfMarketValue(), cellFont));
874                    table.addCell(getAmountCell(data.getSumOfEstimatedIncome(), cellFont));
875                    table.addCell(getAmountCell(data.getSumOfRemainderOfFYEstimated(), cellFont));
876                    table.addCell(getAmountCell(data.getSumOfNextFYEstimatedIncome(), cellFont));
877                }
878            }
879            table.addCell(new Paragraph("TOTAL CASH AND\nEQUIVALENTS", cellFont));
880            table.addCell("");
881            table.addCell(getAmountCell(reportData.getTotalMarketValueForCashEquivalents(IncomePrincipalIndicator.PRINCIPAL).add(reportData.getHistoryPrincipalCash()), cellFont));
882            table.addCell("");
883            table.addCell("");
884            table.addCell("");
885            
886            // other report groups
887            Iterator<Integer> reportGroupOrderSet = reportGroups.keySet().iterator();
888            while (reportGroupOrderSet.hasNext()) {                    
889                
890                Integer reportGroupOrder = reportGroupOrderSet.next();
891                if (reportGroupOrder.intValue() > 1) {   
892                    TreeMap<String, ReportGroupData> reportGroupData = reportData.getReportGroupsForPrincipal().get(reportGroupOrder);
893                    if (reportGroupData == null || reportGroupData.isEmpty()) {
894                        continue;
895                    }
896                    // print report group description
897                    String reportGroupDesc = reportGroupData.firstEntry().getValue().getReportGroupDesc();
898                    PdfPCell groupDescCell = new PdfPCell(new Paragraph(reportGroupDesc, cellFont));
899                    groupDescCell.setColspan(6);
900                    table.addCell(groupDescCell); 
901                    
902                    // print info per security
903                    Iterator<String> secirutyIdSet = reportGroupData.keySet().iterator();
904                    while (secirutyIdSet.hasNext()) {
905                        String securityId = secirutyIdSet.next();
906                        ReportGroupData data = reportGroupData.get(securityId);
907                        table.addCell(new Paragraph(data.getSecurityDesc(), cellFont));
908                        table.addCell(getAmountCell(data.getSumOfUnits(), cellFont, FORMAT164));
909                        table.addCell(getAmountCell(data.getSumOfMarketValue(), cellFont));
910                        table.addCell(getAmountCell(data.getSumOfEstimatedIncome(), cellFont));
911                        table.addCell(getAmountCell(data.getSumOfRemainderOfFYEstimated(), cellFont));
912                        table.addCell(getAmountCell(data.getSumOfNextFYEstimatedIncome(), cellFont));
913                    }
914                    
915                    // report group totals
916                    table.addCell(new Paragraph("TOTAL " + convertToUpperCase(reportGroupDesc), cellFont));
917                    table.addCell("");
918                    table.addCell(getAmountCell(reportData.getTotalSumOfMarketValue(IncomePrincipalIndicator.PRINCIPAL, reportGroupOrder), cellFont));
919                    table.addCell("");
920                    table.addCell("");
921                    table.addCell("");
922                }
923            }
924    
925            // total expendable funds
926            table.addCell(new Paragraph("TOTAL ENDOWED FUNDS", titleFont));
927            table.addCell("");
928            table.addCell(getAmountCell(reportData.getTotalSumOfMarketValue(IncomePrincipalIndicator.PRINCIPAL).add(reportData.getHistoryPrincipalCash()), cellFont));
929            table.addCell(getAmountCell(reportData.getTotalSumOfEstimatedIncome(IncomePrincipalIndicator.PRINCIPAL), cellFont));
930            table.addCell(getAmountCell(reportData.getTotalSumOfRemainderOfFYEstimated(IncomePrincipalIndicator.PRINCIPAL), cellFont));
931            table.addCell(getAmountCell(reportData.getTotalSumOfNextFYEstimatedIncome(IncomePrincipalIndicator.PRINCIPAL), cellFont));                  
932        }
933      
934        /**
935         * Generates report group non-endowed detail
936         * 
937         * @param reportData
938         * @param docuement
939         * @param table
940         * @param cellFont
941         * @throws Exception
942         */
943        protected void printReportGroupForNonEndowedDetail(AssetStatementReportDataHolder reportData, Document docuement, PdfPTable table, Font cellFont) throws Exception {
944            
945            table.addCell(new Paragraph("Income Cash", cellFont));
946            table.addCell("");
947            table.addCell(getAmountCell(reportData.getHistoryIncomeCash(), cellFont));
948            table.addCell("");
949            table.addCell("");
950            table.addCell("");
951            
952            table.addCell(new Paragraph("Principal Cash", cellFont));
953            table.addCell("");
954            table.addCell(getAmountCell(reportData.getHistoryPrincipalCash(), cellFont));
955            table.addCell("");
956            table.addCell("");
957            table.addCell("");
958            
959            TreeMap<Integer, TreeMap<String, ReportGroupData>> reportGroups = reportData.getReportGroupsForIncome();
960            if (reportGroups == null || reportGroups.isEmpty()) {
961                table.addCell(new Paragraph("TOTAL CASH AND\nEQUIVALENTS", cellFont));
962                table.addCell("");
963                table.addCell(getAmountCell(reportData.getHistoryIncomeCash().add(reportData.getHistoryPrincipalCash()), cellFont));
964                table.addCell("");
965                table.addCell("");
966                table.addCell("");
967                return;
968            }
969            
970            // print cash equivalents 
971            TreeMap<String, ReportGroupData> cashEquivalentsData = reportData.getReportGroupsForIncome().get(1);
972            if (cashEquivalentsData != null && !cashEquivalentsData.isEmpty()) {
973                Iterator<String> secirutyIdSet = cashEquivalentsData.keySet().iterator();              
974                while (secirutyIdSet.hasNext()) {
975                    // get securityId
976                    String securityId = secirutyIdSet.next();
977                    ReportGroupData data = cashEquivalentsData.get(securityId);
978                    table.addCell(new Paragraph(data.getSecurityDesc(), cellFont));
979                    table.addCell(getAmountCell(data.getSumOfUnits(), cellFont, FORMAT164));
980                    table.addCell(getAmountCell(data.getSumOfMarketValue(), cellFont));
981                    table.addCell(getAmountCell(data.getSumOfEstimatedIncome(), cellFont));
982                    table.addCell(getAmountCell(data.getSumOfRemainderOfFYEstimated(), cellFont));
983                    table.addCell(getAmountCell(data.getSumOfNextFYEstimatedIncome(), cellFont));
984                }
985            }   
986            BigDecimal totalCashEquivalents = reportData.getTotalMarketValueForCashEquivalents(IncomePrincipalIndicator.INCOME).add(reportData.getTotalMarketValueForCashEquivalents(IncomePrincipalIndicator.PRINCIPAL)).add(reportData.getHistoryIncomeCash()).add(reportData.getHistoryPrincipalCash());
987            table.addCell(new Paragraph("TOTAL CASH AND\nEQUIVALENTS", cellFont));
988            table.addCell("");
989            table.addCell(getAmountCell(totalCashEquivalents, cellFont));
990            table.addCell("");
991            table.addCell("");
992            table.addCell("");     
993            
994            // print other report groups
995            Iterator<Integer> reportGroupOrderSet = reportGroups.keySet().iterator();
996            while (reportGroupOrderSet.hasNext()) {                    
997                
998                Integer reportGroupOrder = reportGroupOrderSet.next();
999                if (reportGroupOrder.intValue() > 1) { 
1000                    TreeMap<String, ReportGroupData> reportGroupData = reportData.getReportGroupsForIncome().get(reportGroupOrder);
1001                    if (reportGroupData == null || reportGroupData.isEmpty()) {
1002                        continue;
1003                    }
1004                    // print report group description
1005                    String reportGroupDesc = reportGroupData.firstEntry().getValue().getReportGroupDesc();
1006                    PdfPCell groupDescCell = new PdfPCell(new Paragraph(reportGroupDesc, cellFont));
1007                    groupDescCell.setColspan(6);
1008                    table.addCell(groupDescCell);             
1009                    
1010                    // print info per security
1011                    Iterator<String> secirutyIdSet = reportGroupData.keySet().iterator();
1012                    while (secirutyIdSet.hasNext()) {
1013                        String securityId = secirutyIdSet.next();
1014                        if (reportGroupOrder.intValue() > 1) {
1015                            ReportGroupData data = reportGroupData.get(securityId);
1016         
1017                            table.addCell(new Paragraph(data.getSecurityDesc(), cellFont));
1018                            table.addCell(getAmountCell(data.getSumOfUnits(), cellFont, FORMAT164));
1019                            table.addCell(getAmountCell(data.getSumOfMarketValue(), cellFont));
1020                            table.addCell(getAmountCell(data.getSumOfEstimatedIncome(), cellFont));
1021                            table.addCell(getAmountCell(data.getSumOfRemainderOfFYEstimated(), cellFont));
1022                            table.addCell(getAmountCell(data.getSumOfNextFYEstimatedIncome(), cellFont));
1023                        }
1024                    }
1025                    
1026                    // report group total
1027                    table.addCell(new Paragraph("TOTAL " + convertToUpperCase(reportGroupDesc), cellFont));
1028                    table.addCell("");
1029                    table.addCell(getAmountCell(reportData.getTotalSumOfMarketValue(IncomePrincipalIndicator.INCOME, reportGroupOrder), cellFont));
1030                    table.addCell("");
1031                    table.addCell("");
1032                    table.addCell("");
1033                }
1034            }             
1035        }
1036        
1037        /**
1038         * Generates report group income non-endowed total
1039         * 
1040         * @param reportGroupsForIncomeTotal
1041         * @param totalHistoryIncomeCash
1042         * @param docuement
1043         * @param table
1044         * @param cellFont
1045         * @throws Exception
1046         */
1047        protected void printReportGroupForIncomeEndowmentTotal(TreeMap<Integer, TreeMap<String, List<ReportGroupData>>> reportGroupsForIncomeTotal, BigDecimal totalHistoryIncomeCash, Document docuement, PdfPTable table, Font cellFont) throws Exception {
1048            
1049            table.addCell(new Paragraph("Income Cash", cellFont));
1050            table.addCell("");
1051            table.addCell(getAmountCell(totalHistoryIncomeCash, cellFont));
1052            table.addCell("");
1053            table.addCell("");
1054            table.addCell("");
1055            
1056            if (reportGroupsForIncomeTotal == null || reportGroupsForIncomeTotal.isEmpty()) {
1057                table.addCell(new Paragraph("TOTAL CASH AND\nEQUIVALENTS", titleFont));
1058                table.addCell("");
1059                table.addCell(getAmountCell(totalHistoryIncomeCash, cellFont));
1060                table.addCell("");
1061                table.addCell("");
1062                table.addCell("");
1063                return;
1064            }
1065    
1066            // Cash and equivalents         
1067            BigDecimal grandTotalMarketValue1 = BigDecimal.ZERO;
1068            BigDecimal grandTotalEstimatedAnnualIncome1 = BigDecimal.ZERO;
1069            BigDecimal grandTotalFyRemainderEAI1 = BigDecimal.ZERO;
1070            BigDecimal grandTotalNextFyEAI1 = BigDecimal.ZERO;
1071            
1072            TreeMap<String, List<ReportGroupData>> cashEquivalentsData = reportGroupsForIncomeTotal.get(1);
1073            if (cashEquivalentsData != null && !cashEquivalentsData.isEmpty()) {
1074                Iterator<String> secirutyIdSet = cashEquivalentsData.keySet().iterator();                 
1075                while (secirutyIdSet.hasNext()) {
1076                    // get securityId
1077                    String securityId = secirutyIdSet.next();
1078                    List<ReportGroupData> dataList = cashEquivalentsData.get(securityId);
1079                    BigDecimal totalUnits = BigDecimal.ZERO;
1080                    BigDecimal totalMarketValue = BigDecimal.ZERO;
1081                    BigDecimal totalEstimatedAnnualIncome = BigDecimal.ZERO;
1082                    BigDecimal totalFyRemainderEAI = BigDecimal.ZERO;
1083                    BigDecimal totalNextFyEAI = BigDecimal.ZERO;
1084     
1085                    for (ReportGroupData data : dataList) {
1086                        totalUnits = totalUnits.add(data.getSumOfUnits());
1087                        totalMarketValue = totalMarketValue.add(data.getSumOfMarketValue());
1088                        totalEstimatedAnnualIncome = totalEstimatedAnnualIncome.add(data.getSumOfEstimatedIncome());
1089                        totalFyRemainderEAI = totalFyRemainderEAI.add(data.getSumOfRemainderOfFYEstimated());
1090                        totalNextFyEAI = totalNextFyEAI.add(data.getSumOfNextFYEstimatedIncome());
1091                    }
1092                    
1093                    table.addCell(new Paragraph(dataList.get(0).getSecurityDesc(), cellFont));
1094                    table.addCell(getAmountCell(totalUnits, cellFont, FORMAT164));
1095                    table.addCell(getAmountCell(totalMarketValue, cellFont));
1096                    table.addCell(getAmountCell(totalEstimatedAnnualIncome, cellFont));
1097                    table.addCell(getAmountCell(totalFyRemainderEAI, cellFont));
1098                    table.addCell(getAmountCell(totalNextFyEAI, cellFont));
1099                    
1100                    grandTotalMarketValue1 = grandTotalMarketValue1.add(totalMarketValue);
1101                    grandTotalEstimatedAnnualIncome1 = grandTotalEstimatedAnnualIncome1.add(totalEstimatedAnnualIncome);
1102                    grandTotalFyRemainderEAI1 = grandTotalFyRemainderEAI1.add(totalFyRemainderEAI);
1103                    grandTotalNextFyEAI1 = grandTotalNextFyEAI1.add(totalNextFyEAI);
1104                }
1105            }    
1106            table.addCell(new Paragraph("TOTAL CASH AND\nEQUIVALENTS", titleFont));
1107            table.addCell("");
1108            table.addCell(getAmountCell(grandTotalMarketValue1.add(totalHistoryIncomeCash), cellFont));
1109            table.addCell("");
1110            table.addCell("");
1111            table.addCell("");            
1112            
1113            // Other report groups
1114            BigDecimal grandTotalMarketValueN = BigDecimal.ZERO;
1115            BigDecimal grandTotalEstimatedAnnualIncomeN = BigDecimal.ZERO;
1116            BigDecimal grandTotalFyRemainderEAIN = BigDecimal.ZERO;
1117            BigDecimal grandTotalNextFyEAIN = BigDecimal.ZERO;
1118            
1119            Iterator<Integer> reportGroupOrderSet = reportGroupsForIncomeTotal.keySet().iterator();
1120            while (reportGroupOrderSet.hasNext()) {                    
1121                
1122                Integer reportGroupOrder = reportGroupOrderSet.next();
1123                if (reportGroupOrder.intValue() > 1) {                  
1124                    TreeMap<String, List<ReportGroupData>> reportGroupDataBySecurity = reportGroupsForIncomeTotal.get(reportGroupOrder);                
1125                    
1126                    // print report group description
1127                    String reportGroupDesc = reportGroupDataBySecurity.firstEntry().getValue().get(0).getReportGroupDesc();
1128                    PdfPCell groupDescCell = new PdfPCell(new Paragraph(reportGroupDesc, titleFont));
1129                    groupDescCell.setColspan(6);
1130                    table.addCell(groupDescCell);
1131                    
1132                    // print totals per security id         
1133                    BigDecimal totalGroupMarketValue = BigDecimal.ZERO;
1134                    Iterator<String> securityIdSet = reportGroupDataBySecurity.keySet().iterator();                    
1135                    while (securityIdSet.hasNext()) {
1136                        String securityId = securityIdSet.next();
1137                        List<ReportGroupData> dataList = reportGroupDataBySecurity.get(securityId);
1138                        BigDecimal totalUnits = BigDecimal.ZERO;
1139                        BigDecimal totalMarketValue = BigDecimal.ZERO;
1140                        BigDecimal totalEstimatedAnnualIncome = BigDecimal.ZERO;
1141                        BigDecimal totalFyRemainderEAI = BigDecimal.ZERO;
1142                        BigDecimal totalNextFyEAI = BigDecimal.ZERO;
1143    
1144                        for (ReportGroupData data : dataList) {
1145                            totalUnits = totalUnits.add(data.getSumOfUnits());
1146                            totalMarketValue = totalMarketValue.add(data.getSumOfMarketValue());
1147                            totalGroupMarketValue = totalGroupMarketValue.add(data.getSumOfMarketValue());
1148                            totalEstimatedAnnualIncome = totalEstimatedAnnualIncome.add(data.getSumOfEstimatedIncome());
1149                            totalFyRemainderEAI = totalFyRemainderEAI.add(data.getSumOfRemainderOfFYEstimated());
1150                            totalNextFyEAI = totalNextFyEAI.add(data.getSumOfNextFYEstimatedIncome());
1151                        }
1152                        
1153                        table.addCell(new Paragraph(dataList.get(0).getSecurityDesc(), cellFont));
1154                        table.addCell(getAmountCell(totalUnits, cellFont, FORMAT164));
1155                        table.addCell(getAmountCell(totalMarketValue, cellFont));
1156                        table.addCell(getAmountCell(totalEstimatedAnnualIncome, cellFont));
1157                        table.addCell(getAmountCell(totalFyRemainderEAI, cellFont));
1158                        table.addCell(getAmountCell(totalNextFyEAI, cellFont));
1159                        
1160                        grandTotalMarketValueN = grandTotalMarketValueN.add(totalMarketValue);
1161                        grandTotalEstimatedAnnualIncomeN = grandTotalEstimatedAnnualIncomeN.add(totalEstimatedAnnualIncome);
1162                        grandTotalFyRemainderEAIN = grandTotalFyRemainderEAIN.add(totalFyRemainderEAI);
1163                        grandTotalNextFyEAIN = grandTotalNextFyEAIN.add(totalNextFyEAI);
1164                    }
1165                    // totals
1166                    table.addCell(new Paragraph("TOTAL " + convertToUpperCase(reportGroupDesc), cellFont));
1167                    table.addCell("");
1168                    table.addCell(getAmountCell(totalGroupMarketValue, cellFont));
1169                    table.addCell("");
1170                    table.addCell("");
1171                    table.addCell("");
1172                }
1173            }
1174    
1175            // total expendable funds
1176            table.addCell(new Paragraph("TOTAL EXPENDABLE FUNDS", titleFont));
1177            table.addCell("");
1178            table.addCell(getAmountCell(grandTotalMarketValue1.add(grandTotalMarketValueN).add(totalHistoryIncomeCash), cellFont));
1179            table.addCell(getAmountCell(grandTotalEstimatedAnnualIncome1.add(grandTotalEstimatedAnnualIncomeN), cellFont));
1180            table.addCell(getAmountCell(grandTotalFyRemainderEAI1.add(grandTotalFyRemainderEAIN), cellFont));
1181            table.addCell(getAmountCell(grandTotalNextFyEAI1.add(grandTotalNextFyEAIN), cellFont));                  
1182        }
1183    
1184        /**
1185         * Generates report group principal non-endowed total
1186         * 
1187         * @param reportGroupsForPrincipalTotal
1188         * @param totalHistoryPrincipalCash
1189         * @param docuement
1190         * @param table
1191         * @param cellFont
1192         */
1193        protected void printReportGroupForPrincipalEndowmentTotal(TreeMap<Integer, TreeMap<String, List<ReportGroupData>>> reportGroupsForPrincipalTotal, BigDecimal totalHistoryPrincipalCash, Document docuement, PdfPTable table, Font cellFont) {
1194           
1195            table.addCell(new Paragraph("Principal Cash", cellFont));
1196            table.addCell("");
1197            table.addCell(getAmountCell(totalHistoryPrincipalCash, cellFont));
1198            table.addCell("");
1199            table.addCell("");
1200            table.addCell("");
1201            
1202            if (reportGroupsForPrincipalTotal == null || reportGroupsForPrincipalTotal.isEmpty()) {
1203                table.addCell(new Paragraph("TOTAL CASH AND\nEQUIVALENTS", titleFont));
1204                table.addCell("");
1205                table.addCell(getAmountCell(totalHistoryPrincipalCash, cellFont));
1206                table.addCell("");
1207                table.addCell("");
1208                table.addCell("");
1209                return;
1210            }
1211    
1212            // Cash and equivalents         
1213            BigDecimal grandTotalMarketValue1 = BigDecimal.ZERO;
1214            BigDecimal grandTotalEstimatedAnnualIncome1 = BigDecimal.ZERO;
1215            BigDecimal grandTotalFyRemainderEAI1 = BigDecimal.ZERO;
1216            BigDecimal grandTotalNextFyEAI1 = BigDecimal.ZERO;
1217            
1218            TreeMap<String, List<ReportGroupData>> cashEquivalentsData = reportGroupsForPrincipalTotal.get(1);
1219            if (cashEquivalentsData != null && !cashEquivalentsData.isEmpty()) {
1220                Iterator<String> secirutyIdSet = cashEquivalentsData.keySet().iterator();                 
1221                while (secirutyIdSet.hasNext()) {
1222                    // get securityId
1223                    String securityId = secirutyIdSet.next();
1224                    List<ReportGroupData> dataList = cashEquivalentsData.get(securityId);
1225                    BigDecimal totalUnits = BigDecimal.ZERO;
1226                    BigDecimal totalMarketValue = BigDecimal.ZERO;
1227                    BigDecimal totalEstimatedAnnualIncome = BigDecimal.ZERO;
1228                    BigDecimal totalFyRemainderEAI = BigDecimal.ZERO;
1229                    BigDecimal totalNextFyEAI = BigDecimal.ZERO;
1230                    //getTotals(dataList, totalUnits, totalMarketValue, totalEstimatedAnnualIncome, totalFyRemainderEAI, totalNextFyEAI);
1231                    for (ReportGroupData data : dataList) {
1232                        totalUnits = totalUnits.add(data.getSumOfUnits());
1233                        totalMarketValue = totalMarketValue.add(data.getSumOfMarketValue());
1234                        totalEstimatedAnnualIncome = totalEstimatedAnnualIncome.add(data.getSumOfEstimatedIncome());
1235                        totalFyRemainderEAI = totalFyRemainderEAI.add(data.getSumOfRemainderOfFYEstimated());
1236                        totalNextFyEAI = totalNextFyEAI.add(data.getSumOfNextFYEstimatedIncome());
1237                    }
1238                    
1239                    table.addCell(new Paragraph(dataList.get(0).getSecurityDesc(), cellFont));
1240                    table.addCell(getAmountCell(totalUnits, cellFont, FORMAT164));
1241                    table.addCell(getAmountCell(totalMarketValue, cellFont));
1242                    table.addCell(getAmountCell(totalEstimatedAnnualIncome, cellFont));
1243                    table.addCell(getAmountCell(totalFyRemainderEAI, cellFont));
1244                    table.addCell(getAmountCell(totalNextFyEAI, cellFont));
1245                    
1246                    grandTotalMarketValue1 = grandTotalMarketValue1.add(totalMarketValue);
1247                    grandTotalEstimatedAnnualIncome1 = grandTotalEstimatedAnnualIncome1.add(totalEstimatedAnnualIncome);
1248                    grandTotalFyRemainderEAI1 = grandTotalFyRemainderEAI1.add(totalFyRemainderEAI);
1249                    grandTotalNextFyEAI1 = grandTotalNextFyEAI1.add(totalNextFyEAI);
1250                }
1251            }    
1252            table.addCell(new Paragraph("TOTAL CASH AND\nEQUIVALENTS", titleFont));
1253            table.addCell("");
1254            table.addCell(getAmountCell(grandTotalMarketValue1.add(totalHistoryPrincipalCash), cellFont));
1255            table.addCell("");
1256            table.addCell("");
1257            table.addCell("");            
1258            
1259            // Other report groups
1260            BigDecimal grandTotalMarketValueN = BigDecimal.ZERO;
1261            BigDecimal grandTotalEstimatedAnnualIncomeN = BigDecimal.ZERO;
1262            BigDecimal grandTotalFyRemainderEAIN = BigDecimal.ZERO;
1263            BigDecimal grandTotalNextFyEAIN = BigDecimal.ZERO;
1264            
1265            Iterator<Integer> reportGroupOrderSet = reportGroupsForPrincipalTotal.keySet().iterator();
1266            while (reportGroupOrderSet.hasNext()) {                    
1267                
1268                Integer reportGroupOrder = reportGroupOrderSet.next();
1269                if (reportGroupOrder.intValue() > 1) {                  
1270                    TreeMap<String, List<ReportGroupData>> reportGroupDataBySecurity = reportGroupsForPrincipalTotal.get(reportGroupOrder);                
1271                    
1272                    // print report group description
1273                    String reportGroupDesc = reportGroupDataBySecurity.firstEntry().getValue().get(0).getReportGroupDesc();
1274                    PdfPCell groupDescCell = new PdfPCell(new Paragraph(reportGroupDesc, titleFont));
1275                    groupDescCell.setColspan(6);
1276                    table.addCell(groupDescCell);
1277                    
1278                    // print totals per security id
1279                    BigDecimal totalGroupMarketValue = BigDecimal.ZERO;
1280                    Iterator<String> securityIdSet = reportGroupDataBySecurity.keySet().iterator();                    
1281                    while (securityIdSet.hasNext()) {
1282                        String securityId = securityIdSet.next();
1283                        List<ReportGroupData> dataList = reportGroupDataBySecurity.get(securityId);
1284                        BigDecimal totalUnits = BigDecimal.ZERO;
1285                        BigDecimal totalMarketValue = BigDecimal.ZERO;
1286                        BigDecimal totalEstimatedAnnualIncome = BigDecimal.ZERO;
1287                        BigDecimal totalFyRemainderEAI = BigDecimal.ZERO;
1288                        BigDecimal totalNextFyEAI = BigDecimal.ZERO;
1289                        //getTotals(dataList, totalUnits, totalMarketValue, totalEstimatedAnnualIncome, totalFyRemainderEAI, totalNextFyEAI);
1290                        for (ReportGroupData data : dataList) {
1291                            totalUnits = totalUnits.add(data.getSumOfUnits());
1292                            totalMarketValue = totalMarketValue.add(data.getSumOfMarketValue());
1293                            totalGroupMarketValue = totalGroupMarketValue.add(data.getSumOfMarketValue());
1294                            totalEstimatedAnnualIncome = totalEstimatedAnnualIncome.add(data.getSumOfEstimatedIncome());
1295                            totalFyRemainderEAI = totalFyRemainderEAI.add(data.getSumOfRemainderOfFYEstimated());
1296                            totalNextFyEAI = totalNextFyEAI.add(data.getSumOfNextFYEstimatedIncome());
1297                        }
1298                        
1299                        table.addCell(new Paragraph(dataList.get(0).getSecurityDesc(), cellFont));
1300                        table.addCell(getAmountCell(totalUnits, cellFont, FORMAT164));
1301                        table.addCell(getAmountCell(totalMarketValue, cellFont));
1302                        table.addCell(getAmountCell(totalEstimatedAnnualIncome, cellFont));
1303                        table.addCell(getAmountCell(totalFyRemainderEAI, cellFont));
1304                        table.addCell(getAmountCell(totalNextFyEAI, cellFont));
1305                        
1306                        grandTotalMarketValueN = grandTotalMarketValueN.add(totalMarketValue);
1307                        grandTotalEstimatedAnnualIncomeN = grandTotalEstimatedAnnualIncomeN.add(totalEstimatedAnnualIncome);
1308                        grandTotalFyRemainderEAIN = grandTotalFyRemainderEAIN.add(totalFyRemainderEAI);
1309                        grandTotalNextFyEAIN = grandTotalNextFyEAIN.add(totalNextFyEAI);
1310                    }
1311    
1312                    // report group total
1313                    table.addCell(new Paragraph("TOTAL " + convertToUpperCase(reportGroupDesc), cellFont));
1314                    table.addCell("");
1315                    table.addCell(getAmountCell(totalGroupMarketValue, cellFont));
1316                    table.addCell("");
1317                    table.addCell("");
1318                    table.addCell("");
1319    
1320                }
1321            }
1322            
1323            // total expendable funds
1324            table.addCell(new Paragraph("TOTAL ENDOWED FUNDS", titleFont));
1325            table.addCell("");
1326            table.addCell(getAmountCell(grandTotalMarketValue1.add(grandTotalMarketValueN).add(totalHistoryPrincipalCash), cellFont));
1327            table.addCell(getAmountCell(grandTotalEstimatedAnnualIncome1.add(grandTotalEstimatedAnnualIncomeN), cellFont));
1328            table.addCell(getAmountCell(grandTotalFyRemainderEAI1.add(grandTotalFyRemainderEAIN), cellFont));
1329            table.addCell(getAmountCell(grandTotalNextFyEAI1.add(grandTotalNextFyEAIN), cellFont));   
1330                       
1331        }
1332      
1333        /**
1334         * Generates report group non-endowed total
1335         * 
1336         * @param reportGroupsForTotal
1337         * @param totalHistoryIncomeCash
1338         * @param totalHistoryPrincipalCash
1339         * @param docuement
1340         * @param table
1341         * @param cellFont
1342         * @throws Exception
1343         */
1344        protected void printReportGroupForNonEndowedTotal(TreeMap<Integer, TreeMap<String, List<ReportGroupData>>> reportGroupsForTotal, BigDecimal totalHistoryIncomeCash, BigDecimal totalHistoryPrincipalCash, Document docuement, PdfPTable table, Font cellFont) throws Exception {
1345            
1346            table.addCell(new Paragraph("Income Cash", cellFont));
1347            table.addCell("");
1348            table.addCell(getAmountCell(totalHistoryIncomeCash, cellFont));
1349            table.addCell("");
1350            table.addCell("");
1351            table.addCell("");
1352            
1353            table.addCell(new Paragraph("Principal Cash", cellFont));
1354            table.addCell("");
1355            table.addCell(getAmountCell(totalHistoryPrincipalCash, cellFont));
1356            table.addCell("");
1357            table.addCell("");
1358            table.addCell("");
1359            
1360            if (reportGroupsForTotal == null || reportGroupsForTotal.isEmpty()) {
1361                table.addCell(new Paragraph("TOTAL CASH AND\nEQUIVALENTS", titleFont));
1362                table.addCell("");
1363                table.addCell(getAmountCell(totalHistoryIncomeCash, cellFont));
1364                table.addCell("");
1365                table.addCell("");
1366                table.addCell("");
1367                return;
1368            }
1369            
1370            // Cash and equivalents         
1371            BigDecimal grandTotalMarketValue1 = BigDecimal.ZERO;
1372            BigDecimal grandTotalEstimatedAnnualIncome1 = BigDecimal.ZERO;
1373            BigDecimal grandTotalFyRemainderEAI1 = BigDecimal.ZERO;
1374            BigDecimal grandTotalNextFyEAI1 = BigDecimal.ZERO;
1375            
1376            // get the cash equivalents group
1377            TreeMap<String, List<ReportGroupData>> cashEquivalentsData = reportGroupsForTotal.get(1);
1378            if (cashEquivalentsData != null && !cashEquivalentsData.isEmpty()) {
1379                Iterator<String> secirutyIdSet = cashEquivalentsData.keySet().iterator();                 
1380                while (secirutyIdSet.hasNext()) {
1381                    // get securityId
1382                    String securityId = secirutyIdSet.next();
1383                    List<ReportGroupData> dataList = cashEquivalentsData.get(securityId);
1384                    BigDecimal totalUnits = BigDecimal.ZERO;
1385                    BigDecimal totalMarketValue = BigDecimal.ZERO;
1386                    BigDecimal totalEstimatedAnnualIncome = BigDecimal.ZERO;
1387                    BigDecimal totalFyRemainderEAI = BigDecimal.ZERO;
1388                    BigDecimal totalNextFyEAI = BigDecimal.ZERO;
1389                    //getTotals(dataList, totalUnits, totalMarketValue, totalEstimatedAnnualIncome, totalFyRemainderEAI, totalNextFyEAI);
1390                    for (ReportGroupData data : dataList) {
1391                        totalUnits = totalUnits.add(data.getSumOfUnits());
1392                        totalMarketValue = totalMarketValue.add(data.getSumOfMarketValue());
1393                        totalEstimatedAnnualIncome = totalEstimatedAnnualIncome.add(data.getSumOfEstimatedIncome());
1394                        totalFyRemainderEAI = totalFyRemainderEAI.add(data.getSumOfRemainderOfFYEstimated());
1395                        totalNextFyEAI = totalNextFyEAI.add(data.getSumOfNextFYEstimatedIncome());
1396                    }
1397                    table.addCell(new Paragraph(dataList.get(0).getSecurityDesc(), cellFont));
1398                    table.addCell(getAmountCell(totalUnits, cellFont, FORMAT164));
1399                    table.addCell(getAmountCell(totalMarketValue, cellFont));
1400                    table.addCell(getAmountCell(totalEstimatedAnnualIncome, cellFont));
1401                    table.addCell(getAmountCell(totalFyRemainderEAI, cellFont));
1402                    table.addCell(getAmountCell(totalNextFyEAI, cellFont));
1403                    
1404                    grandTotalMarketValue1 = grandTotalMarketValue1.add(totalMarketValue);
1405                    grandTotalEstimatedAnnualIncome1 = grandTotalEstimatedAnnualIncome1.add(totalEstimatedAnnualIncome);
1406                    grandTotalFyRemainderEAI1 = grandTotalFyRemainderEAI1.add(totalFyRemainderEAI);
1407                    grandTotalNextFyEAI1 = grandTotalNextFyEAI1.add(totalNextFyEAI);
1408                }
1409            }    
1410            table.addCell(new Paragraph("TOTAL CASH AND\nEQUIVALENTS", titleFont));
1411            table.addCell("");
1412            table.addCell(getAmountCell(grandTotalMarketValue1.add(totalHistoryIncomeCash).add(totalHistoryPrincipalCash), cellFont));
1413            table.addCell("");
1414            table.addCell("");
1415            table.addCell("");            
1416            
1417            // print other report groups
1418            BigDecimal grandTotalMarketValueN = BigDecimal.ZERO;
1419            BigDecimal grandTotalEstimatedAnnualIncomeN = BigDecimal.ZERO;
1420            BigDecimal grandTotalFyRemainderEAIN = BigDecimal.ZERO;
1421            BigDecimal grandTotalNextFyEAIN = BigDecimal.ZERO;
1422            
1423            Iterator<Integer> reportGroupOrderSet = reportGroupsForTotal.keySet().iterator();
1424            while (reportGroupOrderSet.hasNext()) {                    
1425                
1426                Integer reportGroupOrder = reportGroupOrderSet.next();
1427                if (reportGroupOrder.intValue() > 1) {                  
1428                    TreeMap<String, List<ReportGroupData>> reportGroupDataBySecurity = reportGroupsForTotal.get(reportGroupOrder);
1429                    
1430                    // print report group description
1431                    String reportGroupDesc = reportGroupDataBySecurity.firstEntry().getValue().get(0).getReportGroupDesc();
1432                    PdfPCell groupDescCell = new PdfPCell(new Paragraph(reportGroupDesc, titleFont));
1433                    groupDescCell.setColspan(6);
1434                    table.addCell(groupDescCell);
1435                    
1436                    // print totals per security id  
1437                    BigDecimal totalGroupMarketValue = BigDecimal.ZERO;
1438                    Iterator<String> securityIdSet = reportGroupDataBySecurity.keySet().iterator();                
1439                    while (securityIdSet.hasNext()) {
1440                        String securityId = securityIdSet.next();
1441                        List<ReportGroupData> dataList = reportGroupDataBySecurity.get(securityId);
1442                        BigDecimal totalUnits = BigDecimal.ZERO;
1443                        BigDecimal totalMarketValue = BigDecimal.ZERO;
1444                        BigDecimal totalEstimatedAnnualIncome = BigDecimal.ZERO;
1445                        BigDecimal totalFyRemainderEAI = BigDecimal.ZERO;
1446                        BigDecimal totalNextFyEAI = BigDecimal.ZERO;
1447                        for (ReportGroupData data : dataList) {
1448                            totalUnits = totalUnits.add(data.getSumOfUnits());
1449                            totalMarketValue = totalMarketValue.add(data.getSumOfMarketValue());
1450                            totalGroupMarketValue = totalGroupMarketValue.add(data.getSumOfMarketValue());
1451                            totalEstimatedAnnualIncome = totalEstimatedAnnualIncome.add(data.getSumOfEstimatedIncome());
1452                            totalFyRemainderEAI = totalFyRemainderEAI.add(data.getSumOfRemainderOfFYEstimated());
1453                            totalNextFyEAI = totalNextFyEAI.add(data.getSumOfNextFYEstimatedIncome());
1454                        }
1455                        
1456                        table.addCell(new Paragraph(dataList.get(0).getSecurityDesc(), cellFont));
1457                        table.addCell(getAmountCell(totalUnits, cellFont, FORMAT164));
1458                        table.addCell(getAmountCell(totalMarketValue, cellFont));
1459                        table.addCell(getAmountCell(totalEstimatedAnnualIncome, cellFont));
1460                        table.addCell(getAmountCell(totalFyRemainderEAI, cellFont));
1461                        table.addCell(getAmountCell(totalNextFyEAI, cellFont));
1462                        
1463                        grandTotalMarketValueN = grandTotalMarketValueN.add(totalMarketValue);
1464                        grandTotalEstimatedAnnualIncomeN = grandTotalEstimatedAnnualIncomeN.add(totalEstimatedAnnualIncome);
1465                        grandTotalFyRemainderEAIN = grandTotalFyRemainderEAIN.add(totalFyRemainderEAI);
1466                        grandTotalNextFyEAIN = grandTotalNextFyEAIN.add(totalNextFyEAI);
1467                    }
1468                    
1469                    // report group total
1470                    table.addCell(new Paragraph("TOTAL " + convertToUpperCase(reportGroupDesc), cellFont));
1471                    table.addCell("");
1472                    table.addCell(getAmountCell(totalGroupMarketValue, cellFont));
1473                    table.addCell("");
1474                    table.addCell("");
1475                    table.addCell("");
1476                }
1477            }
1478        }
1479        
1480        /**
1481         * Constructs the report group data for grouping by security  
1482         * 
1483         * @param endowmentAssetStatementReportDataHolders
1484         * @param ipInd
1485         * @return
1486         */
1487        protected TreeMap<Integer, TreeMap<String, List<ReportGroupData>>> createReportGroupsForTotal(List<AssetStatementReportDataHolder> endowmentAssetStatementReportDataHolders, String ipInd) {
1488            
1489            TreeMap<Integer, TreeMap<String, List<ReportGroupData>>> reportGroupsForTotal = new TreeMap<Integer, TreeMap<String, List<ReportGroupData>>>();
1490            for (AssetStatementReportDataHolder reportDataHolder : endowmentAssetStatementReportDataHolders) {
1491    
1492                TreeMap<Integer, TreeMap<String, ReportGroupData>> reportGroupsData = IncomePrincipalIndicator.INCOME.equalsIgnoreCase(ipInd) ? reportDataHolder.getReportGroupsForIncome() : reportDataHolder.getReportGroupsForPrincipal();
1493                
1494                if (reportGroupsData != null) {
1495                    
1496                    Set<Integer> reportGroupOrders = reportGroupsData.keySet();
1497                    // per report group order
1498                    for (Integer reportGroupOrder : reportGroupOrders) {
1499                        // ReportGroupData with securityId
1500                        TreeMap<String,ReportGroupData> reportGroupOrderData = reportGroupsData.get(reportGroupOrder);
1501                        Set<String> securityIds = reportGroupOrderData.keySet();
1502                        // per security Id
1503                        for (String securityId : securityIds) {
1504                            ReportGroupData reportGroupDataBySecurityId = reportGroupOrderData.get(securityId);
1505                            // add the ReportGroupData to reportGroupsForAllIncomes
1506                            if (reportGroupsForTotal.containsKey(reportGroupOrder)) {
1507                                // the report group order exists
1508                                if (reportGroupsForTotal.get(reportGroupOrder).containsKey(securityId)) {
1509                                    // the security id exists
1510                                    reportGroupsForTotal.get(reportGroupOrder).get(securityId).add(reportGroupDataBySecurityId);
1511                                } else {
1512                                    List<ReportGroupData> reportGroupDataList = new ArrayList<ReportGroupData>();
1513                                    reportGroupDataList.add(reportGroupDataBySecurityId);
1514                                    reportGroupsForTotal.get(reportGroupOrder).put(securityId, reportGroupDataList);
1515                                }
1516                            } else {
1517                                TreeMap<String, List<ReportGroupData>> newReportGroupOrderData = new TreeMap<String,List<ReportGroupData>>();
1518                                List<ReportGroupData> reportGroupDataList = new ArrayList<ReportGroupData>();
1519                                reportGroupDataList.add(reportGroupDataBySecurityId);
1520                                newReportGroupOrderData.put(securityId, reportGroupDataList);
1521                                reportGroupsForTotal.put(reportGroupOrder, newReportGroupOrderData);
1522                            }                    
1523                        }
1524                    }
1525                }
1526            }
1527            
1528            return reportGroupsForTotal;
1529        }
1530    
1531    }