/*
 * 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.module.tem.document.web.struts;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.kuali.kfs.kns.util.WebUtils;
import org.kuali.kfs.kns.web.struts.form.KualiDocumentFormBase;
import org.kuali.kfs.krad.bo.Note;
import org.kuali.kfs.krad.util.GlobalVariables;
import org.kuali.kfs.krad.util.ObjectUtils;
import org.kuali.kfs.krad.util.UrlFactory;
import org.kuali.kfs.krad.workflow.service.WorkflowDocumentService;
import org.kuali.kfs.module.tem.TemConstants;
import org.kuali.kfs.module.tem.TemPropertyConstants;
import org.kuali.kfs.module.tem.businessobject.AccountingDocumentRelationship;
import org.kuali.kfs.module.tem.businessobject.Attendee;
import org.kuali.kfs.module.tem.businessobject.TravelerDetail;
import org.kuali.kfs.module.tem.document.TravelDocument;
import org.kuali.kfs.module.tem.document.TravelEntertainmentDocument;
import org.kuali.kfs.module.tem.document.service.TravelEntertainmentDocumentService;
import org.kuali.kfs.module.tem.document.web.bean.TravelEntertainmentMvcWrapperBean;
import org.kuali.kfs.module.tem.document.web.bean.TravelMvcWrapperBean;
import org.kuali.kfs.module.tem.pdf.Coversheet;
import org.kuali.kfs.module.tem.report.EntertainmentHostCertificationReport;
import org.kuali.kfs.module.tem.report.NonEmployeeCertificationReport;
import org.kuali.kfs.module.tem.report.service.NonEmployeeCertificationReportService;
import org.kuali.kfs.module.tem.report.service.TravelEntertainmentHostCertificationService;
import org.kuali.kfs.module.tem.report.util.BarcodeHelper;
import org.kuali.kfs.sys.KFSConstants;
import org.kuali.kfs.sys.context.SpringContext;
import org.kuali.rice.core.api.util.type.KualiDecimal;
import org.kuali.rice.kew.api.KewApiConstants;
import org.kuali.rice.kew.api.WorkflowDocument;
import org.kuali.rice.kew.api.exception.WorkflowException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.util.List;
import java.util.Properties;

import static org.kuali.kfs.module.tem.TemConstants.COVERSHEET_FILENAME_FORMAT;
import static org.kuali.kfs.module.tem.TemConstants.SHOW_REPORTS_ATTRIBUTE;
import static org.kuali.kfs.sys.KFSPropertyConstants.DOCUMENT_NUMBER;

/**
 * This class...
 */
public class TravelEntertainmentAction extends TravelActionBase {

    public static Logger LOG = Logger.getLogger(TravelEntertainmentAction.class);

    public static final String[] ATTENDEE_ATTRIBUTE_NAMES = {TemPropertyConstants.AttendeeProperties.ATTENDEE_TYPE, TemPropertyConstants.AttendeeProperties.COMPANY, TemPropertyConstants.AttendeeProperties.TITLE, TemPropertyConstants.AttendeeProperties.NAME};
    public static final Integer[] MAX_LENGTH = {10, 40, 40, 40};

    /**
     * Constructs a TravelEntertainmentDocumentAction.java.
     */
    public TravelEntertainmentAction() {

    }

    @Override
    public ActionForward docHandler(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
        final ActionForward retval = super.docHandler(mapping, form, request, response);
        final TravelEntertainmentForm entForm = (TravelEntertainmentForm) form;
        final TravelEntertainmentDocument document = entForm.getEntertainmentDocument();

        initializeNewAttendeeLines(entForm.getNewAttendeeLines(), document.getAttendee());


        return retval;
    }


    /**
     * Initiates the document based on another entertainment reimbursement if the expected query fields (needed: travelDocumentIdentifier; maybe: fromDocumentNumber) are filled in
     *
     * @see org.kuali.kfs.module.tem.document.web.struts.TravelActionBase#createDocument(org.kuali.rice.kns.web.struts.form.KualiDocumentFormBase)
     */
    @Override
    protected void createDocument(KualiDocumentFormBase form) throws WorkflowException {
        super.createDocument(form);

        final TravelEntertainmentForm entForm = (TravelEntertainmentForm) form;
        final TravelEntertainmentDocument document = entForm.getEntertainmentDocument();

        final String identifierStr = entForm.getTravelDocumentIdentifier();
        final String fromDocumentNumber = entForm.getFromDocumentNumber();

        if (!StringUtils.isBlank(identifierStr) && !StringUtils.isBlank(fromDocumentNumber)) {

            LOG.debug("Creating reimbursement for document number " + identifierStr);
            document.setTravelDocumentIdentifier(identifierStr);
            TravelEntertainmentDocument travelDocument = (TravelEntertainmentDocument) getDocumentService().getByDocumentHeaderId(fromDocumentNumber);

            LOG.debug("Setting traveler with id " + travelDocument.getTravelerDetailId());
            document.setTravelerDetailId(travelDocument.getTravelerDetailId());
            document.refreshReferenceObject(TemPropertyConstants.TRAVELER);
            LOG.debug("Traveler is " + document.getTraveler() + " with customer number " + document.getTraveler().getCustomerNumber());

            if (document.getTraveler().getPrincipalId() != null) {
                document.getTraveler().setPrincipalName(getPersonService().getPerson(document.getTraveler().getPrincipalId()).getPrincipalName());
            }

            document.setHostProfileId(travelDocument.getHostProfileId());
            document.setHostName(travelDocument.getHostName());
            document.setHostAsPayee(travelDocument.getHostAsPayee());
            document.setEventTitle(travelDocument.getEventTitle());
            document.setPurposeCode(travelDocument.getPurposeCode());
            document.setTripBegin(travelDocument.getTripBegin());
            document.setTripEnd(travelDocument.getTripEnd());
            document.setSpouseIncluded(travelDocument.getSpouseIncluded());
            document.setDescription(travelDocument.getDescription());
            document.setAttendeeListAttached(travelDocument.getAttendeeListAttached());
            document.setAttendee(travelDocument.getAttendee());
            document.setNumberOfAttendees(travelDocument.getNumberOfAttendees());
            document.setPrimaryDestinationId(travelDocument.getPrimaryDestinationId());
            document.setPaymentMethod(travelDocument.getPaymentMethod());


            document.setExpenseLimit(travelDocument.getExpenseLimit());
            document.configureTraveler(travelDocument.getTemProfileId(), travelDocument.getTraveler());
            document.getDocumentHeader().setOrganizationDocumentNumber(travelDocument.getDocumentHeader().getOrganizationDocumentNumber());


            document.updatePayeeTypeForReimbursable();

            final AccountingDocumentRelationship relationship = buildRelationshipToProgenitorDocument(travelDocument, document);
            getBusinessObjectService().save(relationship);


        } else {
            document.setTripProgenitor(true); // this is the trip progenitor
        }
        initializeAssignAccounts(entForm);
    }

    /**
     * Refreshes the collections on the document
     *
     * @see org.kuali.kfs.sys.web.struts.KualiAccountingDocumentActionBase#loadDocument(org.kuali.rice.kns.web.struts.form.KualiDocumentFormBase)
     */
    @Override
    protected void loadDocument(KualiDocumentFormBase form) throws WorkflowException {
        super.loadDocument(form);
        final TravelEntertainmentForm entForm = (TravelEntertainmentForm) form;
        final TravelEntertainmentDocument document = entForm.getEntertainmentDocument();

        refreshCollectionsFor(document);
        entForm.setDistribution(getAccountingDistributionService().buildDistributionFrom(entForm.getTravelDocument()));
        initializeAssignAccounts(entForm);
    }

    protected void populateFromPreviousENTDoc(TravelEntertainmentDocument document, String temDocId) {
        TravelEntertainmentDocument entDocument = getBusinessObjectService().findBySinglePrimaryKey(TravelEntertainmentDocument.class, temDocId);
        document.setTravelerDetailId(entDocument.getTravelerDetailId());
        document.refreshReferenceObject(TemPropertyConstants.TRAVELER);
        if (document.getAttendee() != null) {
            document.setAttendee(entDocument.getAttendee());
        }
        if (document.getTraveler() != null) {
            document.setTraveler(entDocument.getTraveler());
        }
        document.setHostProfileId(entDocument.getHostProfileId());
        document.setTemProfileId(entDocument.getTemProfileId());
        document.setEventTitle(entDocument.getEventTitle());
        document.setPurposeCode(entDocument.getPurposeCode());
        document.setPaymentMethod(entDocument.getPaymentMethod());
        document.setTripBegin(entDocument.getTripBegin());
        document.setTripEnd(entDocument.getTripEnd());
        document.setSpouseIncluded(entDocument.getSpouseIncluded());
        document.setDescription(entDocument.getDescription());
        document.updatePayeeTypeForReimbursable();

        try {
            final WorkflowDocument entDocWorkflowDocument = SpringContext.getBean(WorkflowDocumentService.class).loadWorkflowDocument(entDocument.getDocumentNumber(), GlobalVariables.getUserSession().getPerson());
            entDocument.getDocumentHeader().setWorkflowDocument(entDocWorkflowDocument);
            final AccountingDocumentRelationship relationship = buildRelationshipToProgenitorDocument(entDocument, document);
            getBusinessObjectService().save(relationship);
        } catch (WorkflowException we) {
            throw new RuntimeException("Could not load workflow document for old entertainment document " + temDocId, we);
        }

        // we're not the progenitor so let's force a refresh of notes
        final List<Note> notes = getNoteService().getByRemoteObjectId(entDocument.getNoteTarget().getObjectId());
        document.setNotes(notes);
    }

    protected void initializeNewAttendeeLines(final List<Attendee> newAttendeeLines, List<Attendee> attendees) {
        for (Attendee attendee : attendees) {
            if (ObjectUtils.isNull(attendee)) {
                Attendee newAttendeeLine = new Attendee();
                newAttendeeLine.setAttendeeType(attendee.getAttendeeType());
                newAttendeeLine.setCompany(attendee.getCompany());
                newAttendeeLine.setName(attendee.getName());
                newAttendeeLine.setTitle(attendee.getTitle());
                newAttendeeLines.add(newAttendeeLine);
            }
        }
    }

    @Override
    public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
        final ActionForward retval = super.execute(mapping, form, request, response);
        final TravelEntertainmentForm entForm = (TravelEntertainmentForm) form;
        final TravelEntertainmentDocument document = (TravelEntertainmentDocument) ((TravelEntertainmentForm) form).getDocument();
        final String travelIdentifier = document.getTravelDocumentIdentifier();

        initializeNames(entForm, document);
        setButtonPermissions(entForm);

        if (ObjectUtils.isNotNull(document.getActualExpenses())) {
            document.enableExpenseTypeSpecificFields(document.getActualExpenses());
        }

        if (!getCalculateIgnoreList().contains(entForm.getMethodToCall())) {
            recalculateTripDetailTotalOnly(mapping, form, request, response);
        }

        refreshRelatedDocuments(entForm);

        showAccountDistribution(request, document);

        request.setAttribute(SHOW_REPORTS_ATTRIBUTE, !document.getDocumentHeader().getWorkflowDocument().isInitiated());

        entForm.setCanPrintHostCertification(document.canShowHostCertification());

        final KualiDecimal paymentTotal = document.getPaymentAmount();
        if (paymentTotal != null && !ObjectUtils.isNull(document.getTravelPayment())) {
            document.getTravelPayment().setCheckTotalAmount(paymentTotal);
        }

        if (entForm.getAccountDistributionsourceAccountingLines() == null || entForm.getAccountDistributionsourceAccountingLines().isEmpty()) {
            initializeAssignAccounts(entForm);
        }

        return retval;
    }

    private void initializeNames(final TravelEntertainmentForm entForm, final TravelEntertainmentDocument document) {
        if (document.getHostProfile() != null) {
            document.setHostName(document.getHostProfile().getLastName() + KFSConstants.COMMA + document.getHostProfile().getFirstName() + KFSConstants.BLANK_SPACE +
                (document.getHostProfile().getMiddleName() == null ? KFSConstants.BLANK_SPACE : document.getHostProfile().getMiddleName()));
        }
        entForm.getNewAttendeeLines().get(0).setName(getTravelerCompleteName(document.getAttendeeDetail()));
    }

    private String getTravelerCompleteName(TravelerDetail travelerdetail) {
        String completeName = KFSConstants.EMPTY_STRING;
        if (validateTravelerDetailName(travelerdetail)) {
            completeName = travelerdetail.getLastName() + KFSConstants.COMMA + travelerdetail.getFirstName() + KFSConstants.BLANK_SPACE +
                (travelerdetail.getMiddleName() == null ? KFSConstants.BLANK_SPACE : travelerdetail.getMiddleName());
        }
        return completeName;
    }

    private boolean validateTravelerDetailName(TravelerDetail travelerdetail) {
        if (travelerdetail == null) {
            return false;
        }
        if (travelerdetail.getLastName() == null) {
            return false;
        }
        if (travelerdetail.getFirstName() == null) {
            return false;
        }
        if (travelerdetail.getLastName().equals(KFSConstants.EMPTY_STRING) && travelerdetail.getFirstName().equals(KFSConstants.EMPTY_STRING)) {
            return false;
        }

        return true;
    }


    /**
     * Recalculates the Expenses Total Tab
     *
     * @param mapping
     * @param form
     * @param request
     * @param response
     * @throws Exception
     */
    public ActionForward recalculate(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
        return recalculateTripDetailTotal(mapping, form, request, response);
    }

    protected void refreshCollectionsFor(final TravelEntertainmentDocument entDoc) {
        if (!entDoc.getDocumentHeader().getWorkflowDocument().isInitiated()) {
            LOG.debug("Refreshing objects in entertainment document");
            entDoc.refreshReferenceObject(TemPropertyConstants.TRAVELER);
            entDoc.refreshReferenceObject(TemPropertyConstants.ACTUAL_EXPENSES);
            entDoc.refreshReferenceObject(TemPropertyConstants.SPECIAL_CIRCUMSTANCES);
        }
    }

    /**
     * Performs necessary updates after the requester on the relocation document was updated, such as updating the payee type
     *
     * @param document the document to update
     */
    @Override
    protected void performRequesterRefresh(TravelDocument document, TravelFormBase travelForm, HttpServletRequest request) {
        TravelEntertainmentDocument entDoc = (TravelEntertainmentDocument) document;
        if (entDoc.getHostAsPayee()) {
            entDoc.setHostName(document.getTraveler().getFirstName() + " " + document.getTraveler().getLastName());
        } else {
            entDoc.setHostName(KFSConstants.EMPTY_STRING);
        }
        entDoc.updatePayeeTypeForReimbursable();
        updateAccountsWithNewProfile(travelForm, document.getTemProfile());
    }

    public ActionForward printCoversheet(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
        final TravelEntertainmentForm entForm = (TravelEntertainmentForm) form;
        final String documentNumber = request.getParameter(DOCUMENT_NUMBER);
        if (documentNumber != null && !documentNumber.isEmpty()) {
            entForm.setDocument(getEntertainmentDocumentService().find(documentNumber));
        }
        final TravelEntertainmentDocument document = entForm.getEntertainmentDocument();
        final Coversheet cover = getEntertainmentDocumentService().generateCoversheetFor(document);
        final ByteArrayOutputStream stream = new ByteArrayOutputStream();
        cover.print(stream);

        WebUtils.saveMimeOutputStreamAsFile(response, KFSConstants.ReportGeneration.PDF_MIME_TYPE, stream, String.format(COVERSHEET_FILENAME_FORMAT, document.getTravelDocumentIdentifier()));

        return null;
    }

    public ActionForward viewNonEmployeeForms(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
        final TravelEntertainmentForm entForm = (TravelEntertainmentForm) form;
        entForm.setDocument(getEntertainmentDocumentService().find(request.getParameter(DOCUMENT_NUMBER)));
        final TravelEntertainmentDocument entertainment = entForm.getEntertainmentDocument();
        final NonEmployeeCertificationReport report = getNonEmployeeCertificationReportService().buildReport(entertainment);
        BarcodeHelper barcode = new BarcodeHelper();
        report.setBarcodeImage(barcode.generateBarcodeImage(entertainment.getDocumentNumber()));
        File reportFile = getNonEmployeeCertificationReportService().generateReport(report);

        StringBuilder fileName = new StringBuilder();
        fileName.append(entertainment.getTravelDocumentIdentifier());
        fileName.append(TemConstants.NON_EMPLOYEE_CERTIFICATION_REPORT_TITLE);
        fileName.append(KFSConstants.ReportGeneration.PDF_FILE_EXTENSION);
        if (reportFile.length() == 0) {
            return mapping.findForward(KFSConstants.MAPPING_BASIC);
        }

        displayPDF(request, response, reportFile, fileName);

        return null;
    }

    public ActionForward viewEntertainmentCertification(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
        final TravelEntertainmentForm entForm = (TravelEntertainmentForm) form;
        final String documentNumber = request.getParameter(DOCUMENT_NUMBER);
        if (documentNumber != null && !documentNumber.isEmpty()) {
            entForm.setDocument(getEntertainmentDocumentService().find(documentNumber));
        }
        final TravelEntertainmentDocument document = entForm.getEntertainmentDocument();
        entForm.setDocument(getEntertainmentDocumentService().find(request.getParameter(DOCUMENT_NUMBER)));
        final EntertainmentHostCertificationReport report = getEntertainmentHostCertificationService().buildReport(document);
        BarcodeHelper barcode = new BarcodeHelper();
        report.setBarcodeImage(barcode.generateBarcodeImage(document.getDocumentNumber()));
        File reportFile = getEntertainmentHostCertificationService().generateEntertainmentHostCertReport(report);

        StringBuilder fileName = new StringBuilder();
        fileName.append(document.getTravelDocumentIdentifier());
        fileName.append(TemConstants.ENTERTAINMENT_CERTIFICATION_REPORT_TITLE);
        fileName.append(KFSConstants.ReportGeneration.PDF_FILE_EXTENSION);
        if (reportFile.length() == 0) {
            return mapping.findForward(KFSConstants.MAPPING_BASIC);
        }

        displayPDF(request, response, reportFile, fileName);

        return null;
    }

    /**
     * @see org.kuali.kfs.module.tem.document.web.struts.TravelActionBase#route(org.apache.struts.action.ActionMapping, org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
     */
    @Override
    public ActionForward route(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
        //remove the emergency contacts so that it does not get validated
        final TravelEntertainmentForm entertainment = (TravelEntertainmentForm) form;
        TravelDocument document = entertainment.getTravelDocument();
        document.getTraveler().getEmergencyContacts().clear();

        return super.route(mapping, form, request, response);
    }

    public ActionForward addAttendeeLine(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
        final TravelFormBase travelForm = (TravelFormBase) form;
        final TravelEntertainmentMvcWrapperBean mvcWrapper = newMvcDelegate(form);
        mvcWrapper.setNewAttendeeLine(mvcWrapper.getNewAttendeeLines().get(getSelectedLine(request)));
        travelForm.getObservable().notifyObservers(mvcWrapper);
        return mapping.findForward(KFSConstants.MAPPING_BASIC);
    }

    public ActionForward deleteAttendeeLine(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
        final TravelFormBase travelForm = (TravelFormBase) form;
        final TravelMvcWrapperBean mvcWrapper = newMvcDelegate(form);
        travelForm.getObservable().notifyObservers(new Object[]{mvcWrapper, getSelectedLine(request)});
        return mapping.findForward(KFSConstants.MAPPING_BASIC);
    }

    /**
     * Import Attendees to the document from a spreadsheet.
     *
     * @param mapping  An ActionMapping
     * @param form     An ActionForm
     * @param request  The HttpServletRequest
     * @param response The HttpServletResponse
     * @return An ActionForward
     * @throws Exception
     */
    public ActionForward importAttendees(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
        final TravelEntertainmentForm travelForm = (TravelEntertainmentForm) form;
        final TravelEntertainmentMvcWrapperBean mvcWrapper = newMvcDelegate(form);

        travelForm.getObservable().notifyObservers(new Object[]{mvcWrapper, new String(travelForm.getAttendeesImportFile().getFileData())});

        return mapping.findForward(KFSConstants.MAPPING_BASIC);
    }

    /**
     * Forward to MAPPING_BASIC. The newEntertainment button is assumed to have java script
     *
     * @param mapping
     * @param form
     * @param request
     * @param response
     * @return
     * @throws Exception
     */
    public ActionForward newEntertainment(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
        final TravelEntertainmentDocument entDoc = ((TravelEntertainmentForm) form).getEntertainmentDocument();
        final String url = buildNewEntertainmentUrl(entDoc);
        return new ActionForward(url, true);
    }

    /**
     * Builds a new entertainment url for the given travel document
     *
     * @param travelDoc the travel document to create a new reimbursement for
     * @return the url to redirect to to create a new entertainment
     */
    protected String buildNewEntertainmentUrl(TravelEntertainmentDocument entDoc) {
        Properties props = new Properties();
        props.put(TemPropertyConstants.TRAVEL_DOCUMENT_IDENTIFIER, entDoc.getTravelDocumentIdentifier());
        props.put(KFSConstants.DOCUMENT_TYPE_NAME, TemConstants.TravelDocTypes.TRAVEL_ENTERTAINMENT_DOCUMENT);
        props.put(TemPropertyConstants.EntertainmentFields.FROM_DOCUMENT_NUMBER, entDoc.getDocumentNumber());
        props.put(KFSConstants.PARAMETER_COMMAND, KewApiConstants.INITIATE_COMMAND);

        final String docUrlBase = getResolvedUrlForDocumentType(TemConstants.TravelDocTypes.TRAVEL_ENTERTAINMENT_DOCUMENT);
        final String url = UrlFactory.parameterizeUrl(docUrlBase, props);
        return url;
    }

    /**
     * This method sets all the boolean properties on the form to determine what buttons can be displayed depending on what is going
     * on
     */
    protected void setButtonPermissions(TravelEntertainmentForm form) {
        setCanCalculate(form);
    }

    @Override
    public ActionForward downloadBOAttachment(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
        return super.downloadBOAttachment(mapping, form, request, response);
    }

    protected void setContactMasking(TravelEntertainmentForm entForm) {
        entForm.setCanUnmask(entForm.isUserDocumentInitiator());
    }

    protected TravelEntertainmentHostCertificationService getEntertainmentHostCertificationService() {
        return SpringContext.getBean(TravelEntertainmentHostCertificationService.class);
    }

    protected TravelEntertainmentDocumentService getEntertainmentDocumentService() {
        return SpringContext.getBean(TravelEntertainmentDocumentService.class);
    }

    protected NonEmployeeCertificationReportService getNonEmployeeCertificationReportService() {
        return SpringContext.getBean(NonEmployeeCertificationReportService.class);
    }

    @Override
    protected Class<? extends TravelMvcWrapperBean> getMvcWrapperInterface() {
        return TravelEntertainmentMvcWrapperBean.class;
    }

}
