Reports.LeaveDataReader.java Source code

Java tutorial

Introduction

Here is the source code for Reports.LeaveDataReader.java

Source

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package Reports;

import java.awt.geom.AffineTransform;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintStream;
import static java.lang.System.exit;
import java.util.ArrayList;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Scanner;
import java.util.TreeMap;
import javax.swing.JOptionPane;
import org.apache.pdfbox.exceptions.COSVisitorException;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import static org.apache.pdfbox.pdmodel.PDPage.PAGE_SIZE_A4;
import org.apache.pdfbox.pdmodel.edit.PDPageContentStream;
import org.apache.pdfbox.pdmodel.font.PDType1Font;
import org.apache.pdfbox.util.Matrix;
import Utilities.GlobalVar;
import java.util.Set;
import java.util.TreeSet;

/**
 *
 * @author SPC Cui,
 *  this class generates leave reports given the text files 
 */
public class LeaveDataReader {
    // Status   SSN   Member Name             Transaction   
    // Description   Cycle   Seq#            Input Source   
    // Input Clerk   Input Service Station   Memo   
    // Memo Text   Post Date               Update Number   
    // Julian Date   Error Code              Error Description   
    // Error Code 2   Error Code 3            Card Data

    private final int XLSX_STATUS_INDEX = 0;
    private final int XLSX_SSN_INDEX = 1;
    private final int XLSX_MEMBER_NAME_INDEX = 2;
    private final int XLSX_TRANS_INDEX = 3;
    private final int XLSX_DESCRIPTION_INDEX = 4;
    private final int XLSX_CYCLE_INDEX = 5;
    private final int XLSX_SEQ_NUM_INDEX = 6;
    private final int XLSX_INPUT_SOURCE_INDEX = 7;
    private final int XLSX_INPUT_CLERK_INDEX = 8;
    private final int XLSX_INPUT_SERVICE_STATION_INDEX = 9;
    private final int XLSX_MEMO_INDEX = 10; // 6 No Action Required; 7 Freedom
    private final int XLSX_MEMO_TEXT_INDEX = 11;
    private final int XLSX_POST_DT_INDEX = 12;
    private final int XLSX_UPDATE_NUM_INDEX = 13;
    private final int XLSX_JULIAN_DT_INDEX = 14;
    private final int XLSX_ERR_CODE1_INDEX = 15;
    private final int XLSX_ERR_CODE1_DESCRIPTION_INDEX = 16;
    private final int XLSX_ERR_CODE2_INDEX = 17;
    private final int XLSX_ERR_CODE3_INDEX = 18;
    private final int XLSX_CARD_DATA_INDEX = 19;
    private final int XLSX_CTRL_NUM_INDEX = 19; // share the same index
    private final int XLSX_START_DT_INDEX = 20;
    private final int XLSX_STOP_DT_INDEX = 21;
    private final int XLSX_LV_TYPE_INDEX = 22;
    private final int XLSX_LV_DAYS_INDEX = 23;

    private final String LEAVE_WHITE_SPACE = "   "; //white space between columns

    public static final int ADD_MODIFIED_DAYS = 2; // add additional 2 days if date is modified
    public static final int SSN_LEN = 9;
    public static final int LEN_SEQ_NUM = 3;
    public static final int NAME_LENGTH = 5;
    public static final int FONT_SIZE = 10;
    public static final int BIG_FONT_SIZE = 32;
    public static final int MAX_CARD_DATA_CHAR_NUM = 55;

    public static final int ORIG_X = 0; //x coordinate of text origin
    public static final int ORIG_Y = 0; //x coordinate of text origin
    public static final int TRANS_X = 30; // Starting point
    public static final int TRANS_Y = 30; // Starting point
    public static final int FOOTNOTE_TRANS_X = 8 * 72; // page num point  x coordinate 8 inch position
    public static final int FOOTNOTE_TRANS_Y = 330; //  y coordinate, bottom middle of the page
    public static final int INVERVAL_X = 15;
    public static final int INTERVAL_Y = 15; // line space ()
    public static final int BIG_FONT_UPDT_X = 1 * 72; // 2 inch from the top
    public static final int BIG_FONT_UPDT_Y = 1 * 72; // 2 inch from the left
    public static final int BIG_FONT_CYCLE_X = 1 * 72; // 2 inch from the top
    public static final int BIG_FONT_CYCLE_Y = 9 * 72; // 9 inch from the left

    public static final int MAX_NUM_TRANS_FIRST_PAGE = 15;
    public static final int MAX_NUM_TRANS = 35;
    public static final String MEMO_PARSE = " ";
    public static final int LEN_DESCRIPTION = 5;

    private static Map<String, Map<String, List<String>>> LEAVE_DATA;
    //private boolean IS_LANDSCAPE;
    private int PAGE_ROT_DEGREE;
    private double TEXT_ROT_RAD;
    //private static final String TITLE = "Stat   SSN    Name  Trans Seq# IS  PostDt Update     ErrCode                  Card Data";
    private static final String TITLE = "Status     SSN       Name    Tran    Desc Cycle   Seq    Src  SvcSta  PTDate   Update     LvCntr#   LvStart LvStop LvType LvDays";
    private Set<String> SOURCE_CONTAIN_LEAVE;

    public LeaveDataReader(String txtfileName, String PROCESS_YEAR, Boolean isLandScape)
            throws FileNotFoundException {
        LEAVE_DATA = new TreeMap<>();
        SOURCE_CONTAIN_LEAVE = new TreeSet<>();
        if (isLandScape) {
            PAGE_ROT_DEGREE = 90;
            TEXT_ROT_RAD = 3.14 / 2;
        } else {
            PAGE_ROT_DEGREE = 0;
            TEXT_ROT_RAD = 3.14 / 2;
        }
        //        String outputFileName = "DTL.csv";
        //        String whiteSpace = "   ";
        Scanner input = new Scanner(new File(txtfileName));
        input.nextLine(); //Skip title
        // int count = 0;

        while (input.hasNextLine()) {
            String line = input.nextLine();
            //line = line.replaceAll("\\s+", ",");
            line = line.replaceAll("\t", "@@");
            line = line.replaceAll("\"", ""); // delimit in txt is "\t", remove all the "
            String[] info = line.split("@@");

            if (info.length == XLSX_CARD_DATA_INDEX + 1) { // all data
                putAllDatainStorage(info, PROCESS_YEAR);
            } else if (info.length > XLSX_CARD_DATA_INDEX + 1) { //leave data, XLSX_LV_DAYS_INDEX + 1
                putLeaveDatainStorage(info, PROCESS_YEAR);
            }
        }
        input.close();
    }

    // work for raw data exported from dtl and all tabs
    private void putAllDatainStorage(String[] info, String PROCESS_YEAR) {
        String status = readStatus(info[XLSX_STATUS_INDEX]);
        String updateNum = readUpdateNum(info[XLSX_UPDATE_NUM_INDEX]);
        String trans = info[XLSX_TRANS_INDEX]; //SB03

        if ((updateNum.contains("[WEB]") && status != null) && // ditch 10-10[OTH/Sys] and By Others
                (trans.substring(0, 2).equalsIgnoreCase("SB"))) {
            //   if(updateNum.contains("[WEB]") && status != null){     // ditch 10-10[OTH/Sys] and By Others
            String ssn = fullSSNgenerator(info[XLSX_SSN_INDEX]);
            String name = readName(info[XLSX_MEMBER_NAME_INDEX]);

            String desc = descriptionGenerator(info[XLSX_DESCRIPTION_INDEX]);
            String seqNum = seqNumGenerator(info[XLSX_SEQ_NUM_INDEX]);
            String inputSource = info[XLSX_INPUT_SOURCE_INDEX];
            String postDT = readPostDT(info[XLSX_POST_DT_INDEX]);

            String updateNumKey = updateNum.substring(0, 5);
            String errCode1 = errCodeGenerator(info[XLSX_ERR_CODE1_INDEX]);
            String errCode2 = errCodeGenerator(info[XLSX_ERR_CODE2_INDEX]);
            String errCode3 = errCodeGenerator(info[XLSX_ERR_CODE3_INDEX]);
            String errorCode = errCode1 + " " + errCode2 + " " + errCode3;
            String cardData = info[XLSX_CARD_DATA_INDEX];
            //String cardData = readDataCard(info[XLSX_CARD_DATA_INDEX]);
            String lvCtrlNum = cardData.substring(GlobalVar.CTRL_NUM_START_INDEX, GlobalVar.CTRL_NUM_STOP_INDEX);
            String lvStartDate = cardData.substring(GlobalVar.SO_START_INDEX, GlobalVar.SO_STOP_INDEX);
            String lvStopDate = cardData.substring(GlobalVar.SI_START_INDEX, GlobalVar.SI_STOP_INDEX);
            String lvType = cardData.substring(GlobalVar.LV_TYPE_START_INDEX, GlobalVar.LV_TYPE_STOP_INDEX);
            String lvDays = cardData.substring(GlobalVar.LV_DAYS_START_INDEX, GlobalVar.LV_DAYS_STOP_INDEX);

            String ADSN = info[XLSX_INPUT_SERVICE_STATION_INDEX];
            String cycle = info[XLSX_CYCLE_INDEX];

            String memoText = info[XLSX_MEMO_INDEX] + MEMO_PARSE + info[XLSX_MEMO_TEXT_INDEX];
            SOURCE_CONTAIN_LEAVE.add(inputSource);

            String outputLine = status + LEAVE_WHITE_SPACE + ssn + LEAVE_WHITE_SPACE + name + LEAVE_WHITE_SPACE
                    + trans + LEAVE_WHITE_SPACE + desc + LEAVE_WHITE_SPACE + cycle + LEAVE_WHITE_SPACE + seqNum
                    + LEAVE_WHITE_SPACE + inputSource + LEAVE_WHITE_SPACE + ADSN + LEAVE_WHITE_SPACE + postDT
                    + LEAVE_WHITE_SPACE + updateNum + LEAVE_WHITE_SPACE + lvCtrlNum + LEAVE_WHITE_SPACE
                    + lvStartDate + LEAVE_WHITE_SPACE + lvStopDate + LEAVE_WHITE_SPACE + lvType + LEAVE_WHITE_SPACE
                    + lvDays;
            //System.out.println("line" + count + ": " + outputLine + "UpdateNum: " + updateNum + "Cycle: " + cycle);
            //updateNum = updateNum.substring(0,5); //09-16[WEB] become 09-16
            if (LEAVE_DATA.containsKey(updateNumKey)) {
                Map<String, List<String>> thisDTdata = LEAVE_DATA.get(updateNumKey);
                if (thisDTdata.containsKey(inputSource)) {
                    List<String> transactions = thisDTdata.get(inputSource);
                    transactions.add(outputLine);
                    //addMemoText(transactions, status, memoText); //add memo text if there is any
                } else {
                    List<String> transactions = new ArrayList<>();
                    setUpFirstPageTitle(transactions, postDT, updateNum, inputSource, PROCESS_YEAR, ADSN);
                    transactions.add(outputLine);
                    //addMemoText(transactions, status, memoText); //add memo text if there is any
                    thisDTdata.put(inputSource, transactions);
                }
            } else if (!updateNum.equalsIgnoreCase("UpdateNumber")) { //skip the title line
                Map<String, List<String>> thisDTdata = new TreeMap<>();
                List<String> transactions = new ArrayList<>();
                setUpFirstPageTitle(transactions, postDT, updateNum, inputSource, PROCESS_YEAR, ADSN);
                transactions.add(outputLine);
                //addMemoText(transactions, status, memoText); //add memo text if there is any
                thisDTdata.put(inputSource, transactions);
                LEAVE_DATA.put(updateNumKey, thisDTdata);
            }
        }
    }

    // work for raw data exported from leave tab 
    private void putLeaveDatainStorage(String[] info, String PROCESS_YEAR) {
        String status = readStatus(info[XLSX_STATUS_INDEX]);
        String updateNum = readUpdateNum(info[XLSX_UPDATE_NUM_INDEX]);
        String trans = info[XLSX_TRANS_INDEX]; //SB03

        if ((updateNum.contains("[WEB]") && status != null) && // ditch 10-10[OTH/Sys] and By Others
                (trans.substring(0, 2).equalsIgnoreCase("SB"))) {
            //   if(updateNum.contains("[WEB]") && status != null){     // ditch 10-10[OTH/Sys] and By Others
            String ssn = fullSSNgenerator(info[XLSX_SSN_INDEX]);
            String name = readName(info[XLSX_MEMBER_NAME_INDEX]);
            String desc = descriptionGenerator(info[XLSX_DESCRIPTION_INDEX]);
            String seqNum = seqNumGenerator(info[XLSX_SEQ_NUM_INDEX]);
            String inputSource = info[XLSX_INPUT_SOURCE_INDEX];
            String postDT = readPostDT(info[XLSX_POST_DT_INDEX]);
            String updateNumKey = updateNum.substring(0, 5);
            String errCode1 = errCodeGenerator(info[XLSX_ERR_CODE1_INDEX]);
            String errCode2 = errCodeGenerator(info[XLSX_ERR_CODE2_INDEX]);
            String errCode3 = errCodeGenerator(info[XLSX_ERR_CODE3_INDEX]);
            String errorCode = errCode1 + " " + errCode2 + " " + errCode3;
            // String cardData = info[XLSX_CARD_DATA_INDEX];
            //String cardData = readDataCard(info[XLSX_CARD_DATA_INDEX]);
            String lvCtrlNum = info[XLSX_CTRL_NUM_INDEX];
            String lvStartDate = readDate(info, XLSX_START_DT_INDEX);
            String lvStopDate = readDate(info, XLSX_STOP_DT_INDEX);
            String lvType = readLvType(info, XLSX_LV_TYPE_INDEX);
            String lvDays = readLvDays(info, XLSX_LV_DAYS_INDEX);

            String ADSN = info[XLSX_INPUT_SERVICE_STATION_INDEX];
            String cycle = info[XLSX_CYCLE_INDEX];

            String memoText = info[XLSX_MEMO_INDEX] + MEMO_PARSE + info[XLSX_MEMO_TEXT_INDEX];

            SOURCE_CONTAIN_LEAVE.add(inputSource);

            String outputLine = status + LEAVE_WHITE_SPACE + ssn + LEAVE_WHITE_SPACE + name + LEAVE_WHITE_SPACE
                    + trans + LEAVE_WHITE_SPACE + desc + LEAVE_WHITE_SPACE + cycle + LEAVE_WHITE_SPACE + seqNum
                    + LEAVE_WHITE_SPACE + inputSource + LEAVE_WHITE_SPACE + ADSN + LEAVE_WHITE_SPACE + postDT
                    + LEAVE_WHITE_SPACE + updateNum + LEAVE_WHITE_SPACE + lvCtrlNum + LEAVE_WHITE_SPACE
                    + lvStartDate + LEAVE_WHITE_SPACE + lvStopDate + LEAVE_WHITE_SPACE + lvType + LEAVE_WHITE_SPACE
                    + lvDays;
            //System.out.println("line" + count + ": " + outputLine + "UpdateNum: " + updateNum + "Cycle: " + cycle);
            //updateNum = updateNum.substring(0,5); //09-16[WEB] become 09-16
            if (LEAVE_DATA.containsKey(updateNumKey)) {
                Map<String, List<String>> thisDTdata = LEAVE_DATA.get(updateNumKey);
                if (thisDTdata.containsKey(inputSource)) {
                    List<String> transactions = thisDTdata.get(inputSource);
                    transactions.add(outputLine);
                    //addMemoText(transactions, status, memoText); //add memo text if there is any
                } else {
                    List<String> transactions = new ArrayList<>();
                    setUpFirstPageTitle(transactions, postDT, updateNum, inputSource, PROCESS_YEAR, ADSN);
                    transactions.add(outputLine);
                    //addMemoText(transactions, status, memoText); //add memo text if there is any
                    thisDTdata.put(inputSource, transactions);
                }
            } else if (!updateNum.equalsIgnoreCase("UpdateNumber")) { //skip the title line
                Map<String, List<String>> thisDTdata = new TreeMap<>();
                List<String> transactions = new ArrayList<>();
                setUpFirstPageTitle(transactions, postDT, updateNum, inputSource, PROCESS_YEAR, ADSN);
                transactions.add(outputLine);
                //addMemoText(transactions, status, memoText); //add memo text if there is any
                thisDTdata.put(inputSource, transactions);
                LEAVE_DATA.put(updateNumKey, thisDTdata);
            }
        }
    }

    // return a set of input sources that need to generate pdf files
    // if the given list is empty, return all the sources that contain leave transactions
    public Set<String> modifiedListFinder(List<String> inputSources) {
        if (inputSources.isEmpty()) {
            return SOURCE_CONTAIN_LEAVE; // return every thing
        } else {
            Set<String> result = new TreeSet<>();
            for (String inputSource : inputSources) {
                if (SOURCE_CONTAIN_LEAVE.contains(inputSource)) {
                    result.add(inputSource);
                }
            }
            return result;
        }
    }

    // generate multiple pdf files
    public void multiPdfGenerator(String pdfFileNameBase, Set<String> inputSources)
            throws IOException, COSVisitorException {
        GlobalVar.dirMake(new File(pdfFileNameBase)); //create a folder with the same name                          
        int rowCount = 0;
        int pageCount = 1;
        System.out.println("passed in " + inputSources);
        PDPage page; //default size PAGE_SIZE_A4
        PDPageContentStream stream;
        //page.setRotation(90); //counterclock wise rotate 90 degree  ////left hand rule

        //        stream.setFont(PDType1Font.COURIER, FONT_SIZE);
        String lastUpdate = null;
        String lastInputSource = null;
        System.out.println("LEAVE_DATA keyset:" + LEAVE_DATA.keySet());
        //        System.out.println("Cycles empty? " + cycles.isEmpty() + cycles.size());
        //        System.out.println(cycles);
        for (String updateDate : LEAVE_DATA.keySet()) {
            Map<String, List<String>> thisDTData = LEAVE_DATA.get(updateDate);
            lastUpdate = updateDate;
            System.out.println("thisDT_DATA keyset:" + thisDTData.keySet());
            for (String inputSource : thisDTData.keySet()) {
                if (inputSources.isEmpty() || inputSources.contains(inputSource)) {
                    PDDocument pdf = new PDDocument();
                    lastInputSource = inputSource;
                    List<String> thisCycle = thisDTData.get(inputSource);
                    pageCount = 1; // new cycle, restart page num
                    page = new PDPage(); //page break
                    stream = new PDPageContentStream(pdf, page, true, false);
                    stream.beginText();
                    page.setRotation(PAGE_ROT_DEGREE);
                    //stream.setFont(PDType1Font.COURIER, FONT_SIZE);
                    addBigFontUpdateNumberAndCycle(updateDate, lastInputSource, stream);
                    stream.setFont(PDType1Font.COURIER, FONT_SIZE);
                    // stream.setFont(PDType1Font.
                    int thisCycleRowCount = 0;
                    for (String row : thisCycle) {
                        if (thisCycleRowCount > MAX_NUM_TRANS) {
                            //close the current page
                            setupFootNote(stream, pageCount, lastInputSource, updateDate);
                            pageCount++;
                            stream.endText();
                            stream.close();
                            pdf.addPage(page);

                            // start a new page
                            page = new PDPage();
                            stream = new PDPageContentStream(pdf, page, true, false);
                            page.setRotation(PAGE_ROT_DEGREE);
                            stream.beginText();
                            stream.setFont(PDType1Font.COURIER, FONT_SIZE);
                            thisCycleRowCount = 0;
                        }
                        stream.setTextRotation(TEXT_ROT_RAD, TRANS_X + thisCycleRowCount * INVERVAL_X, TRANS_Y);
                        stream.drawString(row);
                        thisCycleRowCount++;
                        //System.out.println("Update:" + updateDate + " Cycle: " + cycle + " " + row);
                    }
                    setupFootNote(stream, pageCount, lastInputSource, lastUpdate);
                    stream.endText();
                    stream.close();
                    pdf.addPage(page);
                    String pdfFileName = pdfFileNameBase + "\\LEAVE UPDT " + updateDate + " " + lastInputSource
                            + ".pdf";

                    pdf.save(pdfFileName);
                    pdf.close();
                }
            }
        }

        // pdf.save(pdfFileName);        
        // pdf.close();      
    }

    // generate single pdf files
    public void singlePdfGenerator(String pdfFileNameBase, Set<String> inputSources)
            throws IOException, COSVisitorException {
        GlobalVar.dirMake(new File(pdfFileNameBase)); //create a folder with the same name                          
        int rowCount = 0;
        int pageCount = 1;
        System.out.println("passed in " + inputSources);
        PDDocument pdf = new PDDocument();
        PDPage page; //default size PAGE_SIZE_A4
        PDPageContentStream stream;
        //page.setRotation(90); //counterclock wise rotate 90 degree  ////left hand rule

        //        stream.setFont(PDType1Font.COURIER, FONT_SIZE);
        String lastUpdate = null;
        String lastInputSource = null;
        System.out.println("LEAVE_DATA keyset:" + LEAVE_DATA.keySet());
        //        System.out.println("Cycles empty? " + cycles.isEmpty() + cycles.size());
        //        System.out.println(cycles);

        String pdfFileName = pdfFileNameBase + "\\LEAVE UPDT";
        for (String updateDate : LEAVE_DATA.keySet()) {
            Map<String, List<String>> thisDTData = LEAVE_DATA.get(updateDate);
            lastUpdate = updateDate;
            System.out.println("thisDT_DATA keyset:" + thisDTData.keySet());
            pdfFileName = pdfFileName + " " + updateDate;
            for (String inputSource : thisDTData.keySet()) {
                if (inputSources.isEmpty() || inputSources.contains(inputSource)) {

                    lastInputSource = inputSource;
                    List<String> thisCycle = thisDTData.get(inputSource);
                    pageCount = 1; // new cycle, restart page num
                    page = new PDPage(); //page break
                    stream = new PDPageContentStream(pdf, page, true, false);
                    stream.beginText();
                    page.setRotation(PAGE_ROT_DEGREE);
                    //stream.setFont(PDType1Font.COURIER, FONT_SIZE);
                    addBigFontUpdateNumberAndCycle(updateDate, lastInputSource, stream);
                    stream.setFont(PDType1Font.COURIER, FONT_SIZE);
                    // stream.setFont(PDType1Font.
                    int thisCycleRowCount = 0;
                    for (String row : thisCycle) {
                        if (thisCycleRowCount > MAX_NUM_TRANS) {
                            //close the current page
                            setupFootNote(stream, pageCount, lastInputSource, updateDate);
                            pageCount++;
                            stream.endText();
                            stream.close();
                            pdf.addPage(page);

                            // start a new page
                            page = new PDPage();
                            stream = new PDPageContentStream(pdf, page, true, false);
                            page.setRotation(PAGE_ROT_DEGREE);
                            stream.beginText();
                            stream.setFont(PDType1Font.COURIER, FONT_SIZE);
                            thisCycleRowCount = 0;
                        }
                        stream.setTextRotation(TEXT_ROT_RAD, TRANS_X + thisCycleRowCount * INVERVAL_X, TRANS_Y);
                        stream.drawString(row);
                        thisCycleRowCount++;
                        //System.out.println("Update:" + updateDate + " Cycle: " + cycle + " " + row);
                    }
                    setupFootNote(stream, pageCount, lastInputSource, lastUpdate);
                    stream.endText();
                    stream.close();
                    pdf.addPage(page);
                }
            }
        }
        if (pdf.getNumberOfPages() > 0) {
            pdfFileName = pdfFileName + ".pdf";
            pdf.save(pdfFileName);
        }
        pdf.close();
    }

    // given the status, return the four letter long process status 
    private String readStatus(String status) {
        if (status != null && status.length() > 4) {
            if (status.equalsIgnoreCase("Reject")) {
                return "Rej "; // four charaters
            } else if (status.equalsIgnoreCase("By Others")) {
                return null;
            } else {
                return status.substring(0, 4);
            }
        } else {
            return status;
        }
    }

    public String fullSSNgenerator(String ssn) {
        if (ssn != null) {
            while (ssn.length() < SSN_LEN) {
                ssn = "0" + ssn;
            }
            return ssn;
        } else {
            JOptionPane.showMessageDialog(null, "Invalid SSN! SSN is longer than 9 digits");
            exit(1);
            return null;
        }
    }

    // take an integer, return LEN_SEQ_NUM character long string
    private String seqNumGenerator(String seqNum) {
        while (seqNum.length() < LEN_SEQ_NUM) {
            seqNum = "0" + seqNum;
        }
        return seqNum;
    }

    // take an integer, return LEN_SEQ_NUM character long string
    private String errCodeGenerator(String errCode) {
        while (errCode.length() < LEN_SEQ_NUM) {
            errCode = errCode + " ";
        }
        return errCode;
    }

    // get rid of 4830DAB0@0001
    private String readDataCard(String data) {
        if (data != null && data.length() > MAX_CARD_DATA_CHAR_NUM) {
            // System.out.println(data.length());
            //            data = data.replaceAll("  +", "");
            //            String[] info = data.split("  ");
            //            if (info != null && info.length > 1)
            String res = data.substring(0, MAX_CARD_DATA_CHAR_NUM);
            //System.out.println(res);
            return res;
        } else if (data != null) {
            return data;
        } else {
            return " ";
        }

    }

    private void addMemoText(List<String> transactions, String status, String memoText) {
        if (!status.equalsIgnoreCase("Proc")) {
            transactions.add("   ** " + memoText); //needs a memo text but which is missing
        }
        //        if(!memoText.equals()) {  // memo only contains parse
        //            transactions.add("   ** " + memoText);
        //        }else if(!status.equalsIgnoreCase("Proc")){ //not processed
        //            transactions.add("   ** ");  //needs a memo text but which is missing
        //        }
    }

    private void setUpFirstPageTitle(List<String> transactions, String postDT, String updateDT, String cycle,
            String PROCESS_YEAR, String ADSN) {
        GregorianCalendar today = new GregorianCalendar();
        if (PROCESS_YEAR != null) { //modified date is used
            processModifiedyDate(today, postDT, PROCESS_YEAR);
        }
        transactions.add("Date: " + today.getTime().toString());

        transactions
                .add("                         Information in this report is covered by the Privacy Act of 1974 ");
        transactions.add("                                and must be protected from unauthorized access or use. ");
        transactions.add("                                                  For Official Use Only.  ");
        transactions.add("                  ");
        transactions.add("                                                  Leave Transactions Report"); //DTL
        transactions.add("                                                        ADSN: " + ADSN);
        transactions.add("                                                   Update Number: " + updateDT);
        transactions.add("                  ");
        transactions.add(TITLE);
    }

    //return a modified date
    private void processModifiedyDate(GregorianCalendar today, String postDT, String PROCESS_YEAR) {
        String correctDate = postDT.trim();
        //String[] dates = correctDate.split("-");  //09-16
        int monthNum = Integer.parseInt(correctDate.substring(2, 4)) - 1; //zero based month
        // int dateNum = Integer.parseInt(dates[1]) + ADD_MODIFIED_DAYS; //print after two days
        int dateNum = Integer.parseInt(correctDate.substring(4, 6)) + ADD_MODIFIED_DAYS;
        //dateNum += (dateNum % 7 - ADD_MODIFIED_DAYS);  //first week minus 1 day, second week add 0 days, third week add 1 day, ... 
        int yearNum = Integer.parseInt(PROCESS_YEAR);
        Random r = new Random();
        int minNum = r.nextInt(60);
        int secNum = r.nextInt(60);
        int hourNum = r.nextInt(3) + 9; // a random hour between 9 - 12
        today.set(yearNum, monthNum, dateNum, hourNum, minNum, secNum); // yearnum must be 4 digits
        String[] date = today.getTime().toString().split(" ");
        if (date != null && date[0].equalsIgnoreCase("Sat")) {
            today.set(yearNum, monthNum, dateNum + 2, hourNum, minNum, secNum);
        } else if (date != null && date[0].equalsIgnoreCase("Sun")) {
            today.set(yearNum, monthNum, dateNum + 1, hourNum, minNum, secNum);
        }

    }

    private void setupFootNote(PDPageContentStream stream, int pageCount, String cycle, String updateDt)
            throws IOException {
        String pageNum = cycle + "  - " + pageCount + " -  " + updateDt;
        stream.setTextRotation(TEXT_ROT_RAD, FOOTNOTE_TRANS_X, FOOTNOTE_TRANS_Y);
        stream.drawString(pageNum);

    }

    private String readName(String name) {
        if (name != null) {
            while (name.length() < NAME_LENGTH) {
                name = name + " ";
            }
            return name;
        }
        return "     ";
    }

    // take an description, return certain character long string if the description is too long
    private String descriptionGenerator(String desc) {
        desc = desc.trim();
        if (desc.length() > LEN_DESCRIPTION) {
            return desc.substring(0, LEN_DESCRIPTION);
        } else {
            while (desc.length() < LEN_DESCRIPTION) {
                desc += " ";
            }
        }
        return desc;
    }

    private String readUpdateNum(String info) {
        if (info != null) {
            info = info.replaceAll(" ", "");
            return info;
        }
        return "          ";
    }

    // given the string[] line and the index, return line[index] if index is within the length of line
    // otherwise return "      "
    private String readDate(String[] info, int dateIndex) {
        if (info != null && info.length > dateIndex) {
            String res = info[dateIndex];
            while (res.length() < 6) {
                res += " ";
            }
            return res;
        } else {
            return "      ";
        }
    }

    // given the string[] line and the index, return line[index] if index is within the length of line
    // otherwise return "      "
    private String readLvType(String[] info, int typeIndex) {
        if (info != null && info.length > typeIndex) {
            String res = info[typeIndex];
            if (res == null || res.length() == 0) {
                return " ";
            } else {
                return res;
            }
        } else {
            return " ";
        }
    }

    // given the string[] line and the index, return line[index] if index is within the length of line
    // otherwise return "      "    
    private String readLvDays(String[] info, int daysIndex) {
        if (info != null && info.length > daysIndex) {
            return info[daysIndex];
        } else {
            return " ";
        }
    }

    private String readPostDT(String info) {
        if (info != null) {
            if (info.length() > 6) {
                return info.substring(2);
            } else {
                while (info.length() < 6) {
                    info = info + " ";
                }
                return info;
            }
        } else {
            return "      ";
        }
    }

    // add big font update number and cycle
    private void addBigFontUpdateNumberAndCycle(String updateDate, String cycle, PDPageContentStream stream)
            throws IOException {
        stream.setFont(PDType1Font.COURIER, BIG_FONT_SIZE);

        stream.setTextRotation(TEXT_ROT_RAD, BIG_FONT_UPDT_X, BIG_FONT_UPDT_Y);
        if (updateDate != null && updateDate.length() >= 5) {
            updateDate = updateDate.substring(0, 5); // choose the first 5 characters.  10-10
            stream.drawString(updateDate);
        }

        stream.setTextRotation(TEXT_ROT_RAD, BIG_FONT_CYCLE_X, BIG_FONT_CYCLE_Y);
        stream.drawString(cycle);
    }
}