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

import org.apache.commons.lang.StringUtils;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.kuali.kfs.kns.question.ConfirmationQuestion;
import org.kuali.kfs.kns.util.KNSGlobalVariables;
import org.kuali.kfs.krad.service.BusinessObjectService;
import org.kuali.kfs.krad.service.KualiRuleService;
import org.kuali.kfs.krad.util.GlobalVariables;
import org.kuali.kfs.module.bc.BCConstants;
import org.kuali.kfs.module.bc.BCKeyConstants;
import org.kuali.kfs.module.bc.BCPropertyConstants;
import org.kuali.kfs.module.bc.businessobject.BudgetConstructionAuthorizationStatus;
import org.kuali.kfs.module.bc.businessobject.BudgetConstructionMonthly;
import org.kuali.kfs.module.bc.businessobject.PendingBudgetConstructionGeneralLedger;
import org.kuali.kfs.module.bc.document.BudgetConstructionDocument;
import org.kuali.kfs.module.bc.document.service.BudgetDocumentService;
import org.kuali.kfs.module.bc.document.validation.event.SaveMonthlyBudgetEvent;
import org.kuali.kfs.sys.KFSConstants;
import org.kuali.kfs.sys.KFSKeyConstants;
import org.kuali.kfs.sys.context.SpringContext;
import org.kuali.rice.core.api.config.property.ConfigurationService;
import org.kuali.rice.core.api.util.type.KualiInteger;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;


public class MonthlyBudgetAction extends BudgetExpansionAction {
    private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(MonthlyBudgetAction.class);

    /**
     * added for testing - remove if not needed
     *
     * @see org.kuali.kfs.module.bc.document.web.struts.BudgetConstructionAction#execute(org.apache.struts.action.ActionMapping,
     * org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
     */
    @Override
    public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
        ActionForward forward = super.execute(mapping, form, request, response);

        MonthlyBudgetForm monthlyBudgetForm = (MonthlyBudgetForm) form;
        populateAuthorizationFields(monthlyBudgetForm);

        // set the readOnly status on initial load of the form
        if (monthlyBudgetForm.getMethodToCall().equals(BCConstants.MONTHLY_BUDGET_METHOD)) {
            BudgetConstructionMonthly bcMonthly = monthlyBudgetForm.getBudgetConstructionMonthly();
            PendingBudgetConstructionGeneralLedger pbgl = bcMonthly.getPendingBudgetConstructionGeneralLedger();

            boolean tmpReadOnly = monthlyBudgetForm.isSystemViewOnly() || !monthlyBudgetForm.isEditAllowed();
            tmpReadOnly |= bcMonthly.getFinancialObjectCode().equalsIgnoreCase(KFSConstants.BudgetConstructionConstants.OBJECT_CODE_2PLG);
            tmpReadOnly |= (!monthlyBudgetForm.isBenefitsCalculationDisabled() && ((pbgl.getLaborObject() != null) && pbgl.getLaborObject().getFinancialObjectFringeOrSalaryCode().equalsIgnoreCase(BCConstants.LABOR_OBJECT_FRINGE_CODE)));

            monthlyBudgetForm.setBudgetableDocument(SpringContext.getBean(BudgetDocumentService.class).isBudgetableDocumentNoWagesCheck(pbgl.getBudgetConstructionHeader()));
            monthlyBudgetForm.setMonthlyReadOnly(tmpReadOnly);

        }

        return forward;
    }

    protected void populateAuthorizationFields(MonthlyBudgetForm monthlyBudgetForm) {
        BudgetConstructionAuthorizationStatus authorizationStatus = (BudgetConstructionAuthorizationStatus) GlobalVariables.getUserSession().retrieveObject(BCConstants.BC_DOC_AUTHORIZATION_STATUS_SESSIONKEY);

        if (authorizationStatus == null) {
            // just return, BudgetExpansionAction.execute() will see the session time out
            // and redirect back to BudgetConstructionSelection
            return;
        }

        monthlyBudgetForm.setDocumentActions(authorizationStatus.getDocumentActions());
        monthlyBudgetForm.setEditingMode(authorizationStatus.getEditingMode());
    }

    public ActionForward loadExpansionScreen(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {

        MonthlyBudgetForm monthlyBudgetForm = (MonthlyBudgetForm) form;

        // use the passed url parms to get the record from DB
        Map fieldValues = new HashMap();
        fieldValues.put("documentNumber", monthlyBudgetForm.getDocumentNumber());
        fieldValues.put("universityFiscalYear", monthlyBudgetForm.getUniversityFiscalYear());
        fieldValues.put("chartOfAccountsCode", monthlyBudgetForm.getChartOfAccountsCode());
        fieldValues.put("accountNumber", monthlyBudgetForm.getAccountNumber());
        fieldValues.put("subAccountNumber", monthlyBudgetForm.getSubAccountNumber());
        fieldValues.put("financialObjectCode", monthlyBudgetForm.getFinancialObjectCode());
        fieldValues.put("financialSubObjectCode", monthlyBudgetForm.getFinancialSubObjectCode());
        fieldValues.put("financialBalanceTypeCode", monthlyBudgetForm.getFinancialBalanceTypeCode());
        fieldValues.put("financialObjectTypeCode", monthlyBudgetForm.getFinancialObjectTypeCode());
        BudgetConstructionMonthly budgetConstructionMonthly = SpringContext.getBean(BusinessObjectService.class).findByPrimaryKey(BudgetConstructionMonthly.class, fieldValues);
        if (budgetConstructionMonthly == null) {
            budgetConstructionMonthly = new BudgetConstructionMonthly();
            budgetConstructionMonthly.setDocumentNumber(monthlyBudgetForm.getDocumentNumber());
            budgetConstructionMonthly.setUniversityFiscalYear(monthlyBudgetForm.getUniversityFiscalYear());
            budgetConstructionMonthly.setChartOfAccountsCode(monthlyBudgetForm.getChartOfAccountsCode());
            budgetConstructionMonthly.setAccountNumber(monthlyBudgetForm.getAccountNumber());
            budgetConstructionMonthly.setSubAccountNumber(monthlyBudgetForm.getSubAccountNumber());
            budgetConstructionMonthly.setFinancialObjectCode(monthlyBudgetForm.getFinancialObjectCode());
            budgetConstructionMonthly.setFinancialSubObjectCode(monthlyBudgetForm.getFinancialSubObjectCode());
            budgetConstructionMonthly.setFinancialBalanceTypeCode(monthlyBudgetForm.getFinancialBalanceTypeCode());
            budgetConstructionMonthly.setFinancialObjectTypeCode(monthlyBudgetForm.getFinancialObjectTypeCode());
            budgetConstructionMonthly.refreshReferenceObject("pendingBudgetConstructionGeneralLedger");
            monthlyBudgetForm.setMonthlyPersisted(false);
        } else {
            monthlyBudgetForm.setMonthlyPersisted(true);
        }
        monthlyBudgetForm.setBudgetConstructionMonthly(budgetConstructionMonthly);


        return mapping.findForward(KFSConstants.MAPPING_BASIC);
    }

    /**
     * This saves the data and redisplays
     *
     * @param mapping
     * @param form
     * @param request
     * @param response
     * @return
     * @throws Exception
     */
    public ActionForward save(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {

        MonthlyBudgetForm monthlyBudgetForm = (MonthlyBudgetForm) form;
        BudgetConstructionMonthly budgetConstructionMonthly = monthlyBudgetForm.getBudgetConstructionMonthly();

        this.replaceMonthlyNullWithZero(budgetConstructionMonthly);

        BudgetConstructionForm budgetConstructionForm = (BudgetConstructionForm) GlobalVariables.getUserSession().retrieveObject(monthlyBudgetForm.getReturnFormKey());
        BudgetConstructionDocument bcDoc = budgetConstructionForm.getBudgetConstructionDocument();
        boolean rulePassed = SpringContext.getBean(KualiRuleService.class).applyRules(new SaveMonthlyBudgetEvent(BCPropertyConstants.BUDGET_CONSTRUCTION_MONTHLY, bcDoc, budgetConstructionMonthly));

        if (rulePassed) {

            // getting here means salary detail line monthly totals equal annual
            // or this is a non-salary detail line and overriding any difference needs to be confirmed
            KualiInteger monthTotalAmount = budgetConstructionMonthly.getFinancialDocumentMonthTotalLineAmount();
            KualiInteger pbglRequestAmount = budgetConstructionMonthly.getPendingBudgetConstructionGeneralLedger().getAccountLineAnnualBalanceAmount();
            if (!monthTotalAmount.equals(pbglRequestAmount)) {

                // total is different than annual
                Object question = request.getParameter(KFSConstants.QUESTION_INST_ATTRIBUTE_NAME);
                ConfigurationService kualiConfiguration = SpringContext.getBean(ConfigurationService.class);
                if (question == null || !(KFSConstants.CONFIRMATION_QUESTION.equals(question))) {
                    // ask question if not already asked
                    String questionText = SpringContext.getBean(ConfigurationService.class).getPropertyValueAsString(BCKeyConstants.QUESTION_CONFIRM_MONTHLY_OVERRIDE);
                    questionText = StringUtils.replace(questionText, "{0}", pbglRequestAmount.toString());
                    questionText = StringUtils.replace(questionText, "{1}", monthTotalAmount.toString());

                    return this.performQuestionWithoutInput(mapping, form, request, response, KFSConstants.CONFIRMATION_QUESTION, questionText, KFSConstants.CONFIRMATION_QUESTION, BCConstants.MAPPING_SAVE, "");
                } else {
                    Object buttonClicked = request.getParameter(KFSConstants.QUESTION_CLICKED_BUTTON);
                    if ((KFSConstants.CONFIRMATION_QUESTION.equals(question)) && ConfirmationQuestion.YES.equals(buttonClicked)) {

                        // yes do the override for non-salary line and save
                        SpringContext.getBean(BudgetDocumentService.class).saveMonthlyBudget(monthlyBudgetForm, budgetConstructionMonthly);
                        KNSGlobalVariables.getMessageList().add(BCKeyConstants.MESSAGE_MONTHLY_ANNUAL_OVERRIDE_SAVED);
                        monthlyBudgetForm.setMonthlyPersisted(true);
                    }
                }
            } else {
                // total is same as annual do the save with no confirmation
                SpringContext.getBean(BudgetDocumentService.class).saveMonthlyBudget(monthlyBudgetForm, budgetConstructionMonthly);
                KNSGlobalVariables.getMessageList().add(KFSKeyConstants.MESSAGE_SAVED);
                monthlyBudgetForm.setMonthlyPersisted(true);
            }
        }

        return mapping.findForward(KFSConstants.MAPPING_BASIC);
    }

    @Override
    public ActionForward close(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {

        MonthlyBudgetForm monthlyBudgetForm = (MonthlyBudgetForm) form;
        BudgetConstructionMonthly budgetConstructionMonthly = monthlyBudgetForm.getBudgetConstructionMonthly();

        if (!monthlyBudgetForm.isMonthlyReadOnly()) {
            Object question = request.getParameter(KFSConstants.QUESTION_INST_ATTRIBUTE_NAME);
            ConfigurationService kualiConfiguration = SpringContext.getBean(ConfigurationService.class);

            // logic for close question
            if (question == null) {
                // ask question if not already asked
                return this.performQuestionWithoutInput(mapping, form, request, response, KFSConstants.DOCUMENT_SAVE_BEFORE_CLOSE_QUESTION, kualiConfiguration.getPropertyValueAsString(KFSKeyConstants.QUESTION_SAVE_BEFORE_CLOSE), KFSConstants.CONFIRMATION_QUESTION, KFSConstants.MAPPING_CLOSE, "");
            } else {
                Object buttonClicked = request.getParameter(KFSConstants.QUESTION_CLICKED_BUTTON);
                if ((KFSConstants.CONFIRMATION_QUESTION.equals(question)) || ((KFSConstants.DOCUMENT_SAVE_BEFORE_CLOSE_QUESTION.equals(question)) && ConfirmationQuestion.YES.equals(buttonClicked))) {

                    // yes button clicked - validate and save the row
                    return this.save(mapping, form, request, response);
                }
                // else go to close logic below
            }
        }

        return returnToCaller(mapping, form, request, response);
    }

    public ActionForward performMonthlySpread(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {

        MonthlyBudgetForm tForm = (MonthlyBudgetForm) form;
        BudgetConstructionMonthly bcMth = tForm.getBudgetConstructionMonthly();
        KualiInteger requestAmt = bcMth.getPendingBudgetConstructionGeneralLedger().getAccountLineAnnualBalanceAmount();
        if (requestAmt != null) {
            bcMth.setFinancialDocumentMonth2LineAmount(new KualiInteger(requestAmt.divide(new KualiInteger(12))));
            bcMth.setFinancialDocumentMonth3LineAmount(new KualiInteger(requestAmt.divide(new KualiInteger(12))));
            bcMth.setFinancialDocumentMonth4LineAmount(new KualiInteger(requestAmt.divide(new KualiInteger(12))));
            bcMth.setFinancialDocumentMonth5LineAmount(new KualiInteger(requestAmt.divide(new KualiInteger(12))));
            bcMth.setFinancialDocumentMonth6LineAmount(new KualiInteger(requestAmt.divide(new KualiInteger(12))));
            bcMth.setFinancialDocumentMonth7LineAmount(new KualiInteger(requestAmt.divide(new KualiInteger(12))));
            bcMth.setFinancialDocumentMonth8LineAmount(new KualiInteger(requestAmt.divide(new KualiInteger(12))));
            bcMth.setFinancialDocumentMonth9LineAmount(new KualiInteger(requestAmt.divide(new KualiInteger(12))));
            bcMth.setFinancialDocumentMonth10LineAmount(new KualiInteger(requestAmt.divide(new KualiInteger(12))));
            bcMth.setFinancialDocumentMonth11LineAmount(new KualiInteger(requestAmt.divide(new KualiInteger(12))));
            bcMth.setFinancialDocumentMonth12LineAmount(new KualiInteger(requestAmt.divide(new KualiInteger(12))));

            KualiInteger totSoFar = bcMth.getFinancialDocumentMonth2LineAmount();
            totSoFar = totSoFar.add(bcMth.getFinancialDocumentMonth3LineAmount().add(bcMth.getFinancialDocumentMonth4LineAmount()));
            totSoFar = totSoFar.add(bcMth.getFinancialDocumentMonth5LineAmount().add(bcMth.getFinancialDocumentMonth6LineAmount()));
            totSoFar = totSoFar.add(bcMth.getFinancialDocumentMonth7LineAmount().add(bcMth.getFinancialDocumentMonth8LineAmount()));
            totSoFar = totSoFar.add(bcMth.getFinancialDocumentMonth9LineAmount().add(bcMth.getFinancialDocumentMonth10LineAmount()));
            totSoFar = totSoFar.add(bcMth.getFinancialDocumentMonth11LineAmount().add(bcMth.getFinancialDocumentMonth12LineAmount()));

            bcMth.setFinancialDocumentMonth1LineAmount(requestAmt.subtract(totSoFar));
        }

        return mapping.findForward(KFSConstants.MAPPING_BASIC);
    }

    public ActionForward performMonthlyZero(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {

        MonthlyBudgetForm tForm = (MonthlyBudgetForm) form;
        BudgetConstructionMonthly bcMth = tForm.getBudgetConstructionMonthly();

        bcMth.setFinancialDocumentMonth1LineAmount(new KualiInteger(0));
        bcMth.setFinancialDocumentMonth2LineAmount(new KualiInteger(0));
        bcMth.setFinancialDocumentMonth3LineAmount(new KualiInteger(0));
        bcMth.setFinancialDocumentMonth4LineAmount(new KualiInteger(0));
        bcMth.setFinancialDocumentMonth5LineAmount(new KualiInteger(0));
        bcMth.setFinancialDocumentMonth6LineAmount(new KualiInteger(0));
        bcMth.setFinancialDocumentMonth7LineAmount(new KualiInteger(0));
        bcMth.setFinancialDocumentMonth8LineAmount(new KualiInteger(0));
        bcMth.setFinancialDocumentMonth9LineAmount(new KualiInteger(0));
        bcMth.setFinancialDocumentMonth10LineAmount(new KualiInteger(0));
        bcMth.setFinancialDocumentMonth11LineAmount(new KualiInteger(0));
        bcMth.setFinancialDocumentMonth12LineAmount(new KualiInteger(0));

        return mapping.findForward(KFSConstants.MAPPING_BASIC);
    }

    public ActionForward performMonthlyDelete(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {

        MonthlyBudgetForm monthlyBudgetForm = (MonthlyBudgetForm) form;
        BudgetConstructionMonthly budgetConstructionMonthly = monthlyBudgetForm.getBudgetConstructionMonthly();

        // don't really need this test since the delete button isn't displayed in readOnly mode
        if (!monthlyBudgetForm.isSystemViewOnly() && monthlyBudgetForm.isEditAllowed()) {
            Object question = request.getParameter(KFSConstants.QUESTION_INST_ATTRIBUTE_NAME);
            ConfigurationService kualiConfiguration = SpringContext.getBean(ConfigurationService.class);

            // logic for delete question
            if (question == null) {
                // ask question if not already asked
                return this.performQuestionWithoutInput(mapping, form, request, response, KFSConstants.DOCUMENT_DELETE_QUESTION, kualiConfiguration.getPropertyValueAsString(BCKeyConstants.QUESTION_DELETE), KFSConstants.CONFIRMATION_QUESTION, KFSConstants.MAPPING_CLOSE, "");
            } else {
                Object buttonClicked = request.getParameter(KFSConstants.QUESTION_CLICKED_BUTTON);
                if ((KFSConstants.DOCUMENT_DELETE_QUESTION.equals(question)) && ConfirmationQuestion.YES.equals(buttonClicked)) {

                    // if yes button clicked - delete and close
                    SpringContext.getBean(BusinessObjectService.class).delete(budgetConstructionMonthly);

                    // if benefits calculation is turned on, check if the line is benefits related and call for calculation after
                    // save
                    BudgetConstructionForm budgetConstructionForm = (BudgetConstructionForm) GlobalVariables.getUserSession().retrieveObject(monthlyBudgetForm.getReturnFormKey());
                    BudgetConstructionDocument bcDoc = budgetConstructionForm.getBudgetConstructionDocument();
                    SpringContext.getBean(BudgetDocumentService.class).callForBenefitsCalcIfNeeded(bcDoc, budgetConstructionMonthly, KualiInteger.ZERO);

                    return returnToCaller(mapping, form, request, response);
                }
                // else go to close logic below
            }
        }

        return mapping.findForward(KFSConstants.MAPPING_BASIC);
    }

    /**
     * checks monthly object for nulls in the amounts and replaces with zeros
     *
     * @param bcMth
     */
    public void replaceMonthlyNullWithZero(BudgetConstructionMonthly bcMth) {

        if (bcMth.getFinancialDocumentMonth1LineAmount() == null) {
            bcMth.setFinancialDocumentMonth1LineAmount(new KualiInteger(0));
        }
        if (bcMth.getFinancialDocumentMonth2LineAmount() == null) {
            bcMth.setFinancialDocumentMonth2LineAmount(new KualiInteger(0));
        }
        if (bcMth.getFinancialDocumentMonth3LineAmount() == null) {
            bcMth.setFinancialDocumentMonth3LineAmount(new KualiInteger(0));
        }
        if (bcMth.getFinancialDocumentMonth4LineAmount() == null) {
            bcMth.setFinancialDocumentMonth4LineAmount(new KualiInteger(0));
        }
        if (bcMth.getFinancialDocumentMonth5LineAmount() == null) {
            bcMth.setFinancialDocumentMonth5LineAmount(new KualiInteger(0));
        }
        if (bcMth.getFinancialDocumentMonth6LineAmount() == null) {
            bcMth.setFinancialDocumentMonth6LineAmount(new KualiInteger(0));
        }
        if (bcMth.getFinancialDocumentMonth7LineAmount() == null) {
            bcMth.setFinancialDocumentMonth7LineAmount(new KualiInteger(0));
        }
        if (bcMth.getFinancialDocumentMonth8LineAmount() == null) {
            bcMth.setFinancialDocumentMonth8LineAmount(new KualiInteger(0));
        }
        if (bcMth.getFinancialDocumentMonth9LineAmount() == null) {
            bcMth.setFinancialDocumentMonth9LineAmount(new KualiInteger(0));
        }
        if (bcMth.getFinancialDocumentMonth10LineAmount() == null) {
            bcMth.setFinancialDocumentMonth10LineAmount(new KualiInteger(0));
        }
        if (bcMth.getFinancialDocumentMonth11LineAmount() == null) {
            bcMth.setFinancialDocumentMonth11LineAmount(new KualiInteger(0));
        }
        if (bcMth.getFinancialDocumentMonth12LineAmount() == null) {
            bcMth.setFinancialDocumentMonth12LineAmount(new KualiInteger(0));
        }
    }

    /**
     * This action changes the value of the hide field in the user interface so that when the page is rendered, the UI knows to show
     * all of the descriptions and labels for each of the pbgl line values.
     *
     * @param mapping
     * @param form
     * @param request
     * @param response
     * @return ActionForward
     * @throws Exception
     */
    public ActionForward showDetails(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
        MonthlyBudgetForm tForm = (MonthlyBudgetForm) form;
        tForm.setHideDetails(false);
        return mapping.findForward(KFSConstants.MAPPING_BASIC);
    }

    /**
     * This action toggles the value of the hide field in the user interface to "hide" so that when the page is rendered, the UI
     * displays values without all of the descriptions and labels for each of the pbgl lines.
     *
     * @param mapping
     * @param form
     * @param request
     * @param response
     * @return ActionForward
     * @throws Exception
     */
    public ActionForward hideDetails(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
        MonthlyBudgetForm tForm = (MonthlyBudgetForm) form;
        tForm.setHideDetails(true);
        return mapping.findForward(KFSConstants.MAPPING_BASIC);
    }
}
