001    /*
002     * Copyright 2011 The Kuali Foundation.
003     * 
004     * Licensed under the Educational Community License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     * 
008     * http://www.opensource.org/licenses/ecl2.php
009     * 
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    package org.kuali.kfs.module.ec.util;
017    
018    import java.util.EnumSet;
019    import java.util.HashMap;
020    import java.util.HashSet;
021    import java.util.Map;
022    import java.util.Set;
023    
024    import org.kuali.kfs.sys.KFSConstants;
025    
026    /**
027     * To enumerate the accounting periods as months and provides a set of utilities to manage the period code.
028     */
029    public enum AccountingPeriodMonth {
030        MONTH1(KFSConstants.MONTH1), MONTH2(KFSConstants.MONTH2), MONTH3(KFSConstants.MONTH3), MONTH4(KFSConstants.MONTH4), MONTH5(KFSConstants.MONTH5), MONTH6(KFSConstants.MONTH6), MONTH7(KFSConstants.MONTH7), MONTH8(KFSConstants.MONTH8), MONTH9(KFSConstants.MONTH9), MONTH10(KFSConstants.MONTH10), MONTH11(KFSConstants.MONTH11), MONTH12(KFSConstants.MONTH12);
031    
032        public final String periodCode;
033    
034        /**
035         * Constructs a AccountingPeriodMonth.java.
036         * @param periodCode a period code
037         */
038        private AccountingPeriodMonth(String periodCode) {
039            this.periodCode = periodCode;
040        }
041    
042        /**
043         * find an accounting period with the given period code
044         * 
045         * @param periodCode the given period code
046         * @return an accounting period with the given period code
047         */
048        public static AccountingPeriodMonth findAccountingPeriod(String periodCode) {
049            for (AccountingPeriodMonth accountingPeriod : AccountingPeriodMonth.values()) {
050                if (accountingPeriod.periodCode.equals(periodCode)) {
051                    return accountingPeriod;
052                }
053            }
054            return null;
055        }
056    
057        /**
058         * find all accounting periods between the given begin period and end period. Here, a period can be represented by the
059         * combination of year and period code. The begin perid should be no later than the end period.
060         * 
061         * @param beginYear the begin year
062         * @param beginPeriodCode the begin period code
063         * @param endYear the end year
064         * @param endPeriodCode the end period code
065         * @return all accounting periods between the given begin period and end period. The returning results are stored in a map,
066         *         whose keys is year and whose values are period code set.
067         */
068        public static Map<Integer, Set<String>> findAccountingPeriodsBetween(Integer beginYear, String beginPeriodCode, Integer endYear, String endPeriodCode) {
069            Map<Integer, Set<String>> accountingPeriods = new HashMap<Integer, Set<String>>();
070    
071            AccountingPeriodMonth beginPeriod = findAccountingPeriod(beginPeriodCode);
072            AccountingPeriodMonth endPeriod = findAccountingPeriod(endPeriodCode);
073    
074            int difference = endYear - beginYear;
075            if (difference > 0) {
076                accountingPeriods.put(beginYear, buildPeriodCodeSetWithinRange(beginPeriod, AccountingPeriodMonth.MONTH12));
077    
078                for (int middleYear = beginYear + 1; middleYear < endYear; middleYear++) {
079                    accountingPeriods.put(middleYear, buildPeriodCodeSetWithinRange(AccountingPeriodMonth.MONTH1, AccountingPeriodMonth.MONTH12));
080                }
081    
082                accountingPeriods.put(endYear, buildPeriodCodeSetWithinRange(AccountingPeriodMonth.MONTH1, endPeriod));
083            }
084            else if (difference == 0) {
085                accountingPeriods.put(beginYear, buildPeriodCodeSetWithinRange(beginPeriod, endPeriod));
086            }
087            else {
088                throw new IllegalArgumentException("The begin year " + beginYear + "should be no later than the end year " + endYear);
089            }
090            return accountingPeriods;
091        }
092    
093        /**
094         * get the period codes between the begin period and the end period. The begin period should not later than the end period;
095         * otherwise, IllegalArgumentException occurs.
096         * 
097         * @param beginPeriod the begin period
098         * @param endPeriod the end period
099         * @return the period codes between the begin period and the end period. The returning codes include The codes of begin and end
100         *         periods.
101         */
102        public static Set<String> buildPeriodCodeSetWithinRange(AccountingPeriodMonth beginPeriod, AccountingPeriodMonth endPeriod) {
103            if (beginPeriod.compareTo(endPeriod) > 0) {
104                throw new IllegalArgumentException("The begin period " + beginPeriod + "should be no later than the end period " + endPeriod);
105            }
106    
107            Set<String> periodCodesWithinRange = new HashSet<String>();
108            for (AccountingPeriodMonth period : EnumSet.range(beginPeriod, endPeriod)) {
109                periodCodesWithinRange.add(period.periodCode);
110            }
111            return periodCodesWithinRange;
112        }
113    }