/**
   * This is the web service method that creates a new account 1. Creates an account object using
   * the parameters from KC and the default Account table 2. Creates an account automatic
   * maintenance document and puts the account object into it 3. Returns the status object
   *
   * @param AccountAutoCreateDefaults
   * @return AccountCreationStatusDTO
   */
  @Override
  public AccountCreationStatusDTO createAccount(AccountParametersDTO accountParameters) {

    AccountCreationStatusDTO accountCreationStatus = new AccountCreationStatusDTO();
    accountCreationStatus.setErrorMessages(new ArrayList<String>());
    accountCreationStatus.setStatus(KcConstants.KcWebService.STATUS_KC_SUCCESS);

    // check to see if the user has the permission to create account
    String principalId = accountParameters.getPrincipalId();
    LOG.debug("principalId  ::::" + principalId);
    if (!isValidUser(principalId)) {
      this.setFailStatus(
          accountCreationStatus,
          KcUtils.getErrorMessage(
              KcConstants.AccountCreationService.ERROR_KC_DOCUMENT_INVALID_USER,
              new String[] {principalId}));
      return accountCreationStatus;
    }

    // get the defaults table
    String unitNumber = accountParameters.getUnit();
    AccountAutoCreateDefaults defaults = getAccountDefaultsService().getAccountDefaults(unitNumber);

    if (defaults == null) {
      this.setFailStatus(
          accountCreationStatus,
          KcConstants.AccountCreationService.ERROR_KC_ACCOUNT_PARAMS_UNIT_NOT_DEFINED);
      return accountCreationStatus;
    }

    try {
      // create an account object
      Account account = createAccountObject(accountParameters, defaults);

      // if invalid chart/account number, failure status and return to KC
      if (!isValidAccount(account, accountCreationStatus)) {
        return accountCreationStatus;
      }
      // create an account automatic maintenance document
      createAutomaticCGAccountMaintenanceDocument(account, accountCreationStatus);

    } catch (Exception ex) {
      this.setFailStatus(
          accountCreationStatus,
          KcConstants.AccountCreationService.ERROR_KC_DOCUMENT_ACCOUNT_GENERATION_PROBLEM);
      return accountCreationStatus;
    }

    // set required values to AccountCreationStatus
    if (accountCreationStatus.getStatus().equals(KcConstants.KcWebService.STATUS_KC_SUCCESS)) {
      accountCreationStatus.setAccountNumber(accountParameters.getAccountNumber());
      accountCreationStatus.setChartOfAccountsCode(defaults.getChartOfAccountsCode());
    }

    return accountCreationStatus;
  }
  /**
   * This method creates an account to be used for automatic maintenance document
   *
   * @param AccountParametersDTO
   * @return Account
   */
  public Account createAccountObject(
      AccountParametersDTO parameters, AccountAutoCreateDefaults defaults) {

    Account account = new Account();

    // * Account: required but off campus indicator, closed, fringe benefit indicator, fringe
    // benefit COA, endowment
    account.setChartOfAccountsCode(defaults.getChartOfAccountsCode());
    account.setOrganizationCode(defaults.getOrganizationCode());
    account.setAccountNumber(parameters.getAccountNumber()); // what if account number is null?
    account.setAccountName(parameters.getAccountName());
    account.setAccountPhysicalCampusCode(defaults.getAccountPhysicalCampusCode());
    if (parameters.getExpirationDate() != null) {
      account.setAccountExpirationDate(new java.sql.Date(parameters.getExpirationDate().getTime()));
    }
    if (parameters.getEffectiveDate() != null) {
      account.setAccountEffectiveDate(new java.sql.Date(parameters.getEffectiveDate().getTime()));
    }
    boolean isKCOverrideKFS =
        parameterService.getParameterValueAsBoolean(
            Account.class,
            KcConstants.AccountCreationService.PARAMETER_KC_OVERRIDES_KFS_DEFAULT_ACCOUNT_IND);
    if (isKCOverrideKFS) {
      // set the right address based on the system parameter RESEARCH_ADMIN_ACCOUNT_ADDRESS_TYPE
      List<String> addressTypes =
          new ArrayList<String>(
              parameterService.getParameterValuesAsString(
                  Account.class,
                  KcConstants.AccountCreationService.PARAMETER_KC_ACCOUNT_ADDRESS_TYPE));
      for (String addressType : addressTypes) {
        if (addressType.equals(KcConstants.AccountCreationService.PI_ADDRESS_TYPE)
            && (!StringUtils.isBlank(parameters.getDefaultAddressStreetAddress()))) {
          account.setAccountStreetAddress(parameters.getDefaultAddressStreetAddress());
          account.setAccountCityName(parameters.getDefaultAddressCityName());
          account.setAccountStateCode(parameters.getDefaultAddressStateCode());
          account.setAccountZipCode(parameters.getDefaultAddressZipCode());
          break;
        } else if (addressType.equals(KcConstants.AccountCreationService.ADMIN_ADDRESS_TYPE)
            && (!StringUtils.isBlank(parameters.getAdminContactAddressStreetAddress()))) {
          account.setAccountStreetAddress(parameters.getAdminContactAddressStreetAddress());
          account.setAccountCityName(parameters.getAdminContactAddressCityName());
          account.setAccountStateCode(parameters.getAdminContactAddressStateCode());
          account.setAccountZipCode(parameters.getAdminContactAddressZipCode());
          break;
        }
      }

    } else {
      // use default address
      account.setAccountStreetAddress(defaults.getAccountStreetAddress());
      account.setAccountCityName(defaults.getAccountCityName());
      account.setAccountStateCode(defaults.getAccountStateCode());
      account.setAccountZipCode(defaults.getAccountZipCode());
    }

    // set the following from parameters
    account.setAccountOffCampusIndicator(parameters.isOffCampusIndicator());
    account.setFinancialHigherEdFunctionCd(parameters.getHigherEdFunctionCode());
    account.setAcctIndirectCostRcvyTypeCd(parameters.getIndirectCostTypeCode());
    account.setFinancialIcrSeriesIdentifier(parameters.getIndirectCostRate());
    account.setAccountGuideline(new AccountGuideline());
    account
        .getAccountGuideline()
        .setAccountExpenseGuidelineText(parameters.getExpenseGuidelineText());
    account
        .getAccountGuideline()
        .setAccountIncomeGuidelineText(parameters.getIncomeGuidelineText());
    account.getAccountGuideline().setAccountPurposeText(parameters.getPurposeText());

    account.setClosed(false);
    account.setAccountTypeCode(defaults.getAccountTypeCode());
    account.setSubFundGroupCode(defaults.getSubFundGroupCode());

    account.setAccountsFringesBnftIndicator(defaults.isAccountsFringesBnftIndicator());

    account.setReportsToAccountNumber(defaults.getReportsToAccountNumber());
    account.setReportsToChartOfAccountsCode(defaults.getReportsToChartOfAccountsCode());

    account.setAccountRestrictedStatusCode("R");
    account.setAccountRestrictedStatusDate(null);

    account.setEndowmentIncomeChartOfAccounts(null);
    account.setEndowmentIncomeAccountNumber(null);

    // * Accounts Responsibility: required - fiscal officer principal name, account supervisor
    // principal name, account manager
    // principal name, budget record level, account sufficient funds
    account.setAccountFiscalOfficerSystemIdentifier(
        defaults.getAccountFiscalOfficerSystemIdentifier());

    account.setAccountsSupervisorySystemsIdentifier(
        defaults.getAccountsSupervisorySystemsIdentifier());
    account.setAccountManagerSystemIdentifier(defaults.getAccountManagerSystemIdentifier());

    account.setContinuationFinChrtOfAcctCd(defaults.getContinuationFinChrtOfAcctCd());
    account.setContinuationAccountNumber(defaults.getContinuationAccountNumber());

    account.setIncomeStreamAccountNumber(defaults.getIncomeStreamAccountNumber());
    account.setIncomeStreamChartOfAccounts(defaults.getIncomeStreamChartOfAccounts());
    account.setIncomeStreamFinancialCoaCode(defaults.getIncomeStreamFinancialCoaCode());

    account.setBudgetRecordingLevelCode(defaults.getBudgetRecordingLevelCode());
    account.setAccountSufficientFundsCode(defaults.getAccountSufficientFundsCode());

    account.setPendingAcctSufficientFundsIndicator(
        defaults.isPendingAcctSufficientFundsIndicator());
    account.setExtrnlFinEncumSufficntFndIndicator(defaults.isExtrnlFinEncumSufficntFndIndicator());
    account.setIntrnlFinEncumSufficntFndIndicator(defaults.isIntrnlFinEncumSufficntFndIndicator());
    account.setFinPreencumSufficientFundIndicator(defaults.isFinPreencumSufficientFundIndicator());
    account.setFinancialObjectivePrsctrlIndicator(defaults.isFinancialObjectivePrsctrlIndicator());

    // * Contract and Grants: not required
    account.setContractControlFinCoaCode(null);
    account.setContractControlAccountNumber(null);
    account.setContractsAndGrantsAccountResponsibilityId(
        defaults.getContractsAndGrantsAccountResponsibilityId());
    account.setAccountCfdaNumber(parameters.getCfdaNumber());

    // set up ICR distribution
    for (IndirectCostRecoveryAutoDefAccount indirectCostRecoveryAutoDefAccount :
        defaults.getIndirectCostRecoveryAutoDefAccounts()) {
      account
          .getIndirectCostRecoveryAccounts()
          .add(
              createIndirectCostRecoveryAccount(
                  indirectCostRecoveryAutoDefAccount,
                  account.getChartOfAccountsCode(),
                  account.getAccountNumber()));
    }
    return account;
  }