/*
 * The Kuali Financial System, a comprehensive financial management system for higher education.
 *
 * Copyright 2005-2016 The Kuali Foundation
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.kuali.kfs.gl.batch;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.kuali.kfs.coa.businessobject.Chart;
import org.kuali.kfs.coa.businessobject.Organization;
import org.kuali.kfs.gl.GeneralLedgerConstants;
import org.kuali.kfs.gl.batch.service.RunDateService;
import org.kuali.kfs.gl.batch.service.impl.OriginEntryTotals;
import org.kuali.kfs.gl.businessobject.CollectorDetail;
import org.kuali.kfs.gl.businessobject.CollectorHeader;
import org.kuali.kfs.gl.businessobject.OriginEntryFull;
import org.kuali.kfs.gl.businessobject.OriginEntryGroup;
import org.kuali.kfs.gl.businessobject.OriginEntrySource;
import org.kuali.kfs.gl.report.CollectorReportData;
import org.kuali.kfs.gl.service.CollectorDetailService;
import org.kuali.kfs.kns.service.BusinessObjectDictionaryService;
import org.kuali.kfs.kns.service.DataDictionaryService;
import org.kuali.kfs.krad.bo.PersistableBusinessObjectBase;
import org.kuali.kfs.krad.service.BusinessObjectService;
import org.kuali.kfs.krad.util.MessageMap;
import org.kuali.kfs.sys.KFSConstants;
import org.kuali.kfs.sys.KFSKeyConstants;
import org.kuali.kfs.sys.KFSPropertyConstants;
import org.kuali.kfs.sys.ObjectUtil;
import org.kuali.kfs.sys.context.SpringContext;
import org.kuali.kfs.sys.exception.ParseException;
import org.kuali.rice.core.api.datetime.DateTimeService;
import org.kuali.rice.core.api.util.type.KualiDecimal;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintStream;
import java.sql.Date;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * Object representation of collector xml input.
 */
public class CollectorBatch extends PersistableBusinessObjectBase {
    // way to distinguish this batch from others
    private String batchName;

    // common field for header records and trailer records
    private String universityFiscalYear;
    private String chartOfAccountsCode;
    private String organizationCode;
    private Date transmissionDate;
    private String recordType;

    // header record additional fields
    private String personUserID;
    private Integer batchSequenceNumber;
    private String emailAddress;
    private String campusCode;
    private String phoneNumber;
    private String mailingAddress;
    private String departmentName;

    private List<OriginEntryFull> originEntries;
    private List<CollectorDetail> collectorDetails;

    // trailer records
    private String firstEmptyField; //first,second,third Empty Fields are dummy fields to read the spaces in the file using dd
    private String secondEmptyField;
    private Integer totalRecords;
    private KualiDecimal totalAmount;

    private MessageMap messageMap;
    private OriginEntryTotals originEntryTotals;

    private boolean headerlessBatch;

    private static CollectorBatchHeaderFieldUtil collectorBatchHeaderFieldUtil;
    private static CollectorBatchTrailerRecordFieldUtil collectorBatchTrailerRecordFieldUtil;

    /**
     * Constructs a CollectorBatch
     */
    public CollectorBatch() {
        originEntries = new ArrayList();
        collectorDetails = new ArrayList();
        messageMap = new MessageMap();
        originEntryTotals = null;
        totalRecords = 0;
        headerlessBatch = false;
    }

    /**
     * Gets the universityFiscalYear attribute.
     */
    public String getUniversityFiscalYear() {
        return universityFiscalYear;
    }

    /**
     * Sets the universityFiscalYear attribute
     */
    public void setUniversityFiscalYear(String universityFiscalYear) {
        this.universityFiscalYear = universityFiscalYear;
    }

    /**
     * Gets the batchSequenceNumber attribute.
     */
    public Integer getBatchSequenceNumber() {
        return batchSequenceNumber;
    }

    /**
     * Sets the batchSequenceNumber attribute value.
     */
    public void setBatchSequenceNumber(Integer batchSequenceNumber) {
        this.batchSequenceNumber = batchSequenceNumber;
    }

    /**
     * Gets the chartOfAccountsCode attribute.
     */
    public String getChartOfAccountsCode() {
        return chartOfAccountsCode;
    }

    /**
     * Sets the chartOfAccountsCode attribute value.
     */
    public void setChartOfAccountsCode(String chartOfAccountsCode) {
        this.chartOfAccountsCode = chartOfAccountsCode;
    }

    /**
     * Gets the organizationCode attribute.
     */
    public String getOrganizationCode() {
        return organizationCode;
    }

    /**
     * Sets the organizationCode attribute value.
     */
    public void setOrganizationCode(String organizationCode) {
        this.organizationCode = organizationCode;
    }

    /**
     * Gets the totalAmount attribute.
     */
    public KualiDecimal getTotalAmount() {
        return totalAmount;
    }

    /**
     * Sets the totalAmount attribute value.
     */
    public void setTotalAmount(KualiDecimal totalAmount) {
        this.totalAmount = totalAmount;
    }

    /**
     * Sets the total amount from the String.
     */
    public void setTotalAmount(String totalAmount) {
        this.totalAmount = new KualiDecimal(totalAmount);
    }

    /**
     * Sets the total amount field to null.
     */
    public void clearTotalAmount() {
        this.totalAmount = null;
    }

    /**
     * Gets the secondEmptyField attribute
     */
    public String getSecondEmptyField() {
        return secondEmptyField;
    }

    /**
     * Sets the secondEmptyField attribute
     */
    public void setSecondEmptyField(String secondEmptyField) {
        this.secondEmptyField = secondEmptyField;
    }

    /**
     * Gets the firstEmptyField attribute
     */
    public String getFirstEmptyField() {
        return firstEmptyField;
    }

    /**
     * Sets the firstEmptyField attribute
     */
    public void setFirstEmptyField(String firstEmptyField) {
        this.firstEmptyField = firstEmptyField;
    }

    /**
     * Gets the totalRecords attribute.
     */
    public Integer getTotalRecords() {
        return totalRecords;
    }

    /**
     * Sets the totalRecords attribute value.
     */
    public void setTotalRecords(Integer totalRecords) {
        this.totalRecords = totalRecords;
    }

    /**
     * Gets the transmissionDate attribute.
     */
    public Date getTransmissionDate() {
        return transmissionDate;
    }

    /**
     * Sets the transmissionDate attribute value.
     */
    public void setTransmissionDate(Date transmissionDate) {
        this.transmissionDate = transmissionDate;
    }

    /**
     * Gets the recordType attribute.
     */
    public String getRecordType() {
        return recordType;
    }

    /**
     * Sets the recordType attribute.
     */
    public void setRecordType(String recordType) {
        this.recordType = recordType;
    }

    /**
     * Gets the emailAddress attribute.
     */
    public String getEmailAddress() {
        return emailAddress;
    }

    /**
     * Sets the emailAddress attribute value.
     */
    public void setEmailAddress(String emailAddress) {
        this.emailAddress = emailAddress;
    }

    /**
     * Gets the personUserID attribute.
     */
    public String getPersonUserID() {
        return personUserID;
    }

    /**
     * Sets the personUserID attribute value.
     */
    public void setPersonUserID(String personUserID) {
        this.personUserID = personUserID;
    }

    /**
     * Gets the idBillings attribute.
     */
    public List<CollectorDetail> getCollectorDetails() {
        return collectorDetails;
    }

    /**
     * Sets the idBillings attribute value.
     */
    public void setCollectorDetails(List<CollectorDetail> idDetails) {
        this.collectorDetails = idDetails;
    }

    /**
     * Gets the originEntries attribute.
     */
    public List<OriginEntryFull> getOriginEntries() {
        return originEntries;
    }

    /**
     * Sets the originEntries attribute value.
     */
    public void setOriginEntries(List<OriginEntryFull> batchOriginEntry) {
        this.originEntries = batchOriginEntry;
    }

    /**
     * Adds a processed origin entry to the list.
     */
    public void addOriginEntry(OriginEntryFull orginEntry) {
        this.originEntries.add(orginEntry);
    }

    /**
     * Adds a processed id billing to the list.
     */
    public void addCollectorDetail(CollectorDetail collectorDetail) {
        this.collectorDetails.add(collectorDetail);
    }

    /**
     * Attempts to retrieve a collector header already exists with the primary key values given for this object
     *
     * @return the CollectorHeader found in the database
     */
    public CollectorHeader retrieveDuplicateHeader() {
        // checkHeader is used to check whether a record with the same PK values exist already (i.e. only PK values are filled in).
        CollectorHeader checkHeader = createCollectorHeaderWithPKValuesOnly();

        CollectorHeader foundHeader = (CollectorHeader) SpringContext.getBean(BusinessObjectService.class).retrieve(checkHeader);
        return foundHeader;
    }

    /**
     * Sets defaults for fields not populated from file. Store an origin entry group, all gl entries and id billing entries from the
     * processed file. Also write the header for the duplicate file check.
     *
     * @param originEntryGroup    the group into which to store the origin entries
     * @param collectorReportData report data
     */
    public void setDefaultsAndStore(CollectorReportData collectorReportData, String demergerOutputFileName, PrintStream originEntryOutputPs) {
        BusinessObjectService businessObjectService = SpringContext.getBean(BusinessObjectService.class);
        CollectorDetailService collectorDetailService = SpringContext.getBean(CollectorDetailService.class);

        // persistHeader is used to persist a collector header record into the DB
        CollectorHeader persistHeader = createCollectorHeaderForStorage();
        CollectorHeader foundHeader = retrieveDuplicateHeader();

        if (foundHeader != null) {
            // update the version number to prevent OptimisticLockingExceptions
            persistHeader.setVersionNumber(foundHeader.getVersionNumber());
        }
        businessObjectService.save(persistHeader);

        // store origin entries by using the demerger output file

        BufferedReader inputFileReader = null;
        try {
            inputFileReader = new BufferedReader(new FileReader(demergerOutputFileName));
            String line = null;
            while ((line = inputFileReader.readLine()) != null) {
                originEntryOutputPs.printf("%s\n", line);
            }
        } catch (IOException e) {
            throw new RuntimeException("IO Error encountered trying to persist collector batch.", e);
        } finally {
            IOUtils.closeQuietly(inputFileReader);
            inputFileReader = null;
        }
        Date nowDate = new Date(SpringContext.getBean(DateTimeService.class).getCurrentDate().getTime());
        RunDateService runDateService = SpringContext.getBean(RunDateService.class);
        Date createDate = new java.sql.Date((runDateService.calculateRunDate(nowDate).getTime()));

        Integer sequenceNumber = new Integer(0);
        Integer nextSequence = collectorDetailService.getNextCreateSequence(createDate);
        if (nextSequence != null) {
            sequenceNumber = nextSequence;
        }
        int countOfdetails = collectorDetails.size();
        for (int numSavedDetails = 0; numSavedDetails < countOfdetails; numSavedDetails++) {
            CollectorDetail idDetail = this.collectorDetails.get(numSavedDetails);
            //  setDefaultsCollectorDetail(idDetail);

            idDetail.setTransactionLedgerEntrySequenceNumber(++sequenceNumber);
            idDetail.setCreateDate(createDate);
            CollectorDetail foundIdDetail = (CollectorDetail) businessObjectService.retrieve(idDetail);
            if (foundIdDetail != null) {
                idDetail.setVersionNumber(foundIdDetail.getVersionNumber());
            }

            businessObjectService.save(idDetail);
        }

        collectorReportData.setNumSavedDetails(this, countOfdetails);
    }

    /**
     * Uppercases the appropriate fields in the batch, if told to do so by the data dictionary
     */
    public void prepareDataForStorage() {
        BusinessObjectDictionaryService businessObjectDictionaryService = SpringContext.getBean(BusinessObjectDictionaryService.class);
        DataDictionaryService dataDictionaryService = SpringContext.getBean(DataDictionaryService.class);

        // uppercase the data used to generate the collector header
        if (dataDictionaryService.getAttributeForceUppercase(Chart.class, KFSPropertyConstants.CHART_OF_ACCOUNTS_CODE)) {
            setChartOfAccountsCode(getChartOfAccountsCode().toUpperCase());
        }
        if (dataDictionaryService.getAttributeForceUppercase(Organization.class, KFSPropertyConstants.ORGANIZATION_CODE)) {
            setOrganizationCode(getOrganizationCode().toUpperCase());
        }

        // now uppercase all of the origin entry data
        for (OriginEntryFull entry : originEntries) {
            businessObjectDictionaryService.performForceUppercase(entry);
        }

        // uppercase the id billing entries
        for (CollectorDetail collectorDetail : collectorDetails) {
            businessObjectDictionaryService.performForceUppercase(collectorDetail);
        }
    }

    /**
     * Creates origin entry group from header fields.
     *
     * @return OriginEntryGroup
     */
    private OriginEntryGroup createOriginEntryGroup() {
        OriginEntryGroup group = new OriginEntryGroup();

        group.setSourceCode(OriginEntrySource.COLLECTOR);
        group.setDate(new java.sql.Date(SpringContext.getBean(DateTimeService.class).getCurrentDate().getTime()));
        group.setProcess(new Boolean(true));
        group.setScrub(new Boolean(true));
        group.setValid(new Boolean(true));

        return group;
    }

    /**
     * Creates a CollectorHeader from the batch to be used for storage
     *
     * @return CollectorHeader
     */
    public CollectorHeader createCollectorHeaderForStorage() {
        CollectorHeader header = new CollectorHeader();

        header.setChartOfAccountsCode(getChartOfAccountsCode());
        header.setOrganizationCode(getOrganizationCode());
        header.setProcessTransmissionDate(getTransmissionDate());
        header.setProcessBatchSequenceNumber(getBatchSequenceNumber());
        header.setProcessTotalRecordCount(getTotalRecords());
        header.setProcessTotalAmount(getTotalAmount());
        header.setContactCampusCode(getCampusCode());
        header.setContactPersonPhoneNumber(getPhoneNumber());
        header.setContactMailingAddress(getMailingAddress());
        header.setContactDepartmentName(getDepartmentName());

        return header;
    }

    /**
     * Creates an origin entry record with the PK values filled in only. This is useful to check for duplicate headers.
     *
     * @return CollectorHeader with chart of accounts code, organization code, process transmission date, batch sequence number
     * total record count, and process total amount from this CollectorBatch
     */
    public CollectorHeader createCollectorHeaderWithPKValuesOnly() {
        CollectorHeader header = new CollectorHeader();

        header.setChartOfAccountsCode(getChartOfAccountsCode());
        header.setOrganizationCode(getOrganizationCode());
        header.setProcessTransmissionDate(getTransmissionDate());
        header.setProcessBatchSequenceNumber(getBatchSequenceNumber());
        header.setProcessTotalRecordCount(getTotalRecords());
        header.setProcessTotalAmount(getTotalAmount());

        return header;
    }

//    /**
//     * Sets defaults for missing id billing fields.
//     *
//     * @param idDetail CollectorDetail object which has its create date being set
//     */
//    private void setDefaultsCollectorDetail(CollectorDetail idDetail) {
//        // TODO: Get current fiscal year and period if blank?
//        // idBilling.setUniversityFiscalPeriodCode(String.valueOf(RandomUtils.nextInt(2)));
//        // idBilling.setCreateSequence(String.valueOf(RandomUtils.nextInt(2)));
//        // idBilling.setInterDepartmentalBillingSequenceNumber(String.valueOf(RandomUtils.nextInt(2)));
//        idDetail.setCreateDate(new Date(SpringContext.getBean(DateTimeService.class).getCurrentDate().getTime()));
//
//    }

    /**
     * Gets the campusCode attribute.
     *
     * @return Returns the campusCode.
     */
    public String getCampusCode() {
        return campusCode;
    }

    /**
     * Sets the campusCode attribute value.
     *
     * @param campusCode The campusCode to set.
     */
    public void setCampusCode(String campusCode) {
        this.campusCode = campusCode;
    }

    /**
     * Gets the departmentName attribute.
     *
     * @return Returns the departmentName.
     */
    public String getDepartmentName() {
        return departmentName;
    }

    /**
     * Sets the departmentName attribute value.
     *
     * @param departmentName The departmentName to set.
     */
    public void setDepartmentName(String departmentName) {
        this.departmentName = departmentName;
    }

    /**
     * Gets the mailingAddress attribute.
     *
     * @return Returns the mailingAddress.
     */
    public String getMailingAddress() {
        return mailingAddress;
    }

    /**
     * Sets the mailingAddress attribute value.
     *
     * @param mailingAddress The mailingAddress to set.
     */
    public void setMailingAddress(String mailingAddress) {
        this.mailingAddress = mailingAddress;
    }

    /**
     * Gets the phoneNumber attribute.
     *
     * @return Returns the phoneNumber.
     */
    public String getPhoneNumber() {
        return phoneNumber;
    }

    /**
     * Sets the phoneNumber attribute value.
     *
     * @param phoneNumber The phoneNumber to set.
     */
    public void setPhoneNumber(String phoneNumber) {
        this.phoneNumber = phoneNumber;
    }

    /**
     * Gets the batchName attribute.
     *
     * @return Returns the batchName.
     */
    public String getBatchName() {
        return batchName;
    }

    /**
     * Sets the batchName attribute value.
     *
     * @param batchName The batchName to set.
     */
    public void setBatchName(String batchName) {
        this.batchName = batchName;
    }

    public MessageMap getMessageMap() {
        return messageMap;
    }

    public void setMessageMap(MessageMap messageMap) {
        if (messageMap == null) {
            throw new NullPointerException("messageMap is null");
        }
        if (this.messageMap.hasMessages()) {
            throw new RuntimeException("Cannot reset MessageMap unless original instance has no messages.");
        }
        this.messageMap = messageMap;
    }

    public OriginEntryTotals getOriginEntryTotals() {
        return originEntryTotals;
    }

    public void setOriginEntryTotals(OriginEntryTotals originEntryTotals) {
        this.originEntryTotals = originEntryTotals;
    }

    public boolean isHeaderlessBatch() {
        return headerlessBatch;
    }

    public void setHeaderlessBatch(boolean headerlessBatch) {
        this.headerlessBatch = headerlessBatch;
    }

    protected LinkedHashMap toStringMapper_RICE20_REFACTORME() {
        LinkedHashMap map = new LinkedHashMap();
        map.put("chartOfAccountsCode", getChartOfAccountsCode());
        map.put("organizationCode", getOrganizationCode());
        map.put("transmissionDate", getTransmissionDate());
        map.put("personUserID", getPersonUserID());
        map.put("batchSequenceNumber", getBatchSequenceNumber());
        map.put("emailAddress", getEmailAddress());
        map.put("campusCode", getCampusCode());
        map.put("phoneNumber", getPhoneNumber());
        map.put("mailingAddress", getMailingAddress());
        map.put("departmentName", getDepartmentName());
        map.put("firstEmptyField", getFirstEmptyField());
        map.put("totalRecords", getTotalRecords());
        map.put("secondEmptyField", getSecondEmptyField());
        map.put("totalAmount", getTotalAmount());

        return map;
    }

    protected Date parseSqlDate(String date) throws ParseException {
        try {
            return new Date(new SimpleDateFormat("yy-MM-dd").parse(date).getTime());
        } catch (java.text.ParseException e) {
            throw new ParseException(e.getMessage(), e);
        }
    }

    protected String getValue(String headerLine, int s, int e) {
        return org.springframework.util.StringUtils.trimTrailingWhitespace(StringUtils.substring(headerLine, s, e));
    }

    /**
     * @return the static instance of the CollectorBatchHeaderFieldUtil
     */
    protected static CollectorBatchHeaderFieldUtil getCollectorBatchHeaderFieldUtil() {
        if (collectorBatchHeaderFieldUtil == null) {
            collectorBatchHeaderFieldUtil = new CollectorBatchHeaderFieldUtil();
        }
        return collectorBatchHeaderFieldUtil;
    }

    public void setFromTextFileForCollectorBatch(String headerLine) {
        try {
            final Map<String, Integer> pMap = getCollectorBatchHeaderFieldUtil().getFieldBeginningPositionMap();

            headerLine = org.apache.commons.lang.StringUtils.rightPad(headerLine, GeneralLedgerConstants.getSpaceAllCollectorBatchHeaderFields().length(), ' ');

            setChartOfAccountsCode(getValue(headerLine, pMap.get(KFSPropertyConstants.CHART_OF_ACCOUNTS_CODE), pMap.get(KFSPropertyConstants.ORGANIZATION_CODE)));
            setOrganizationCode(getValue(headerLine, pMap.get(KFSPropertyConstants.ORGANIZATION_CODE), pMap.get(KFSPropertyConstants.TRANSMISSION_DATE)));

            String transmissionDate = org.apache.commons.lang.StringUtils.trim(getValue(headerLine, pMap.get(KFSPropertyConstants.TRANSMISSION_DATE), pMap.get(KFSPropertyConstants.COLLECTOR_BATCH_RECORD_TYPE)));
            try {
                setTransmissionDate(parseSqlDate(transmissionDate));
            } catch (ParseException e) {
                getMessageMap().putError(KFSConstants.GLOBAL_ERRORS, KFSKeyConstants.Collector.HEADER_BAD_TRANSMISSION_DATE_FORMAT, transmissionDate);
                setTransmissionDate(null);
            }
            String batchNumber = org.apache.commons.lang.StringUtils.trim(getValue(headerLine, pMap.get(KFSPropertyConstants.BATCH_SEQUENCE_NUMBER), pMap.get(KFSPropertyConstants.EMAIL_ADDRESS)));

            if (ObjectUtil.isInteger(batchNumber)) {
                setBatchSequenceNumber(new Integer(batchNumber));
            } else {
                setBatchSequenceNumber(0);
            }
            setEmailAddress(getValue(headerLine, pMap.get(KFSPropertyConstants.EMAIL_ADDRESS), pMap.get(KFSPropertyConstants.COLLECTOR_BATCH_PERSON_USER_ID)));
            setPersonUserID(getValue(headerLine, pMap.get(KFSPropertyConstants.COLLECTOR_BATCH_PERSON_USER_ID), pMap.get(KFSPropertyConstants.DEPARTMENT_NAME)));
            setDepartmentName(getValue(headerLine, pMap.get(KFSPropertyConstants.DEPARTMENT_NAME), pMap.get(KFSPropertyConstants.MAILING_ADDRESS)));
            setMailingAddress(getValue(headerLine, pMap.get(KFSPropertyConstants.MAILING_ADDRESS), pMap.get(KFSPropertyConstants.CAMPUS_CODE)));
            setCampusCode(getValue(headerLine, pMap.get(KFSPropertyConstants.CAMPUS_CODE), pMap.get(KFSPropertyConstants.PHONE_NUMBER)));
            setPhoneNumber(org.apache.commons.lang.StringUtils.trim(getValue(headerLine, pMap.get(KFSPropertyConstants.PHONE_NUMBER), GeneralLedgerConstants.getSpaceAllCollectorBatchHeaderFields().length())));
        } catch (Exception e) {
            throw new RuntimeException(e + " occurred in CollectorBatch.setFromTextFileForCollectorBatch()");
        }
    }

    /**
     * @return the static instance of the CollectorBatchTrailerRecordFieldUtil
     */
    protected static CollectorBatchTrailerRecordFieldUtil getCollectorBatchTrailerRecordFieldUtil() {
        if (collectorBatchTrailerRecordFieldUtil == null) {
            collectorBatchTrailerRecordFieldUtil = new CollectorBatchTrailerRecordFieldUtil();
        }
        return collectorBatchTrailerRecordFieldUtil;
    }

    public void setFromTextFileForCollectorBatchTrailerRecord(String trailerLine, int lineNumber) {
        final Map<String, Integer> pMap = getCollectorBatchTrailerRecordFieldUtil().getFieldBeginningPositionMap();

        trailerLine = org.apache.commons.lang.StringUtils.rightPad(trailerLine, GeneralLedgerConstants.getSpaceAllCollectorBatchTrailerFields().length(), ' ');
        setTotalRecords(new Integer(org.apache.commons.lang.StringUtils.trim(getValue(trailerLine, pMap.get(KFSPropertyConstants.TOTAL_RECORDS), pMap.get(KFSPropertyConstants.TRAILER_RECORD_SECOND_EMPTY_FIELD)))));

        String trailerAmount = org.apache.commons.lang.StringUtils.trim(getValue(trailerLine, pMap.get(KFSPropertyConstants.TOTAL_AMOUNT), GeneralLedgerConstants.getSpaceAllCollectorBatchTrailerFields().length()));

        try {
            setTotalAmount(trailerAmount);
        } catch (NumberFormatException e) {
            setTotalAmount(KualiDecimal.ZERO);
            getMessageMap().putError(KFSConstants.GLOBAL_ERRORS, KFSKeyConstants.ERROR_CUSTOM, "Collector trailer total amount cannot be parsed on line " + lineNumber + " amount string " + trailerAmount);
        }
    }
}
