001: package net.sf.jmoney.charts;
002:
003: import java.util.Date;
004: import java.util.Hashtable;
005: import java.util.Iterator;
006: import java.util.List;
007: import java.util.Vector;
008:
009: import net.sf.jmoney.model2.CapitalAccount;
010: import net.sf.jmoney.model2.Entry;
011: import net.sf.jmoney.model2.Session;
012:
013: import org.jfree.data.MovingAverage;
014: import org.jfree.data.time.Day;
015: import org.jfree.data.time.TimeSeries;
016: import org.jfree.data.time.TimeSeriesCollection;
017: import org.jfree.data.time.TimeSeriesDataItem;
018:
019: /**
020: * @author Faucheux
021: */
022: public class ActivLineChart extends LineChart {
023:
024: /**
025: *
026: */
027: private static final long serialVersionUID = -5937219526820401153L;
028:
029: /**
030: * @param title
031: * @param session
032: */
033: public ActivLineChart(String title, Session session,
034: LineChartParameters params) {
035: super (title, session);
036: this .params = params;
037: }
038:
039: /**
040: * Calculate the values for each selected account.
041: */
042: protected void createOrUpdateValues(LineChartParameters param) {
043:
044: // Read the parameters.
045: /*String*/Vector accountsToShow = param.accountList;
046: int numberOfAccounts = accountsToShow.size();
047:
048: // Collect the dataes
049: TimeSeries timeSeries[] = new TimeSeries[numberOfAccounts];
050: for (int i = 0; i < numberOfAccounts; i++) {
051: String accountFullName = (String) accountsToShow.get(i);
052:
053: timeSeries[i] = getTimeSerieForAccount(accountFullName,
054: session);
055: }
056:
057: // Trick for BALANCE-Graph: we add all the dataes in the same Serie
058: if (param.type == LineChartParameters.BALANCE) {
059: TimeSeries balanceTimeSeries = new TimeSeries("BALANCE");
060: for (int i = 0; i < numberOfAccounts; i++) {
061: mixTimeSeries(balanceTimeSeries, timeSeries[i], true /* the debit accounts are already nagative */);
062: }
063: timeSeries[0] = balanceTimeSeries;
064: numberOfAccounts = 1;
065: }
066:
067: // Create the collection of wanted curves
068: if (data == null)
069: data = new TimeSeriesCollection();
070: else
071: data.removeAllSeries();
072:
073: for (int i = 0; i < numberOfAccounts; i++) {
074:
075: // Daily values and moving averages
076: TimeSeries mav;
077:
078: if (params.daily)
079: data.addSeries(timeSeries[i]);
080:
081: if (param.average30) {
082: mav = MovingAverage.createMovingAverage(timeSeries[i],
083: timeSeries[i].getName() + " (30 days)", 30, 30);
084: data.addSeries(mav);
085: }
086:
087: if (param.average120) {
088: mav = MovingAverage.createMovingAverage(timeSeries[i],
089: timeSeries[i].getName() + " (120 days)", 120,
090: 120);
091: data.addSeries(mav);
092: }
093:
094: if (param.average365) {
095: mav = MovingAverage.createMovingAverage(timeSeries[i],
096: timeSeries[i].getName() + " (365 days)", 365,
097: 365);
098: data.addSeries(mav);
099: }
100:
101: }
102: }
103:
104: /**
105: * Calculate the values for an account.
106: * @param acccount
107: * @param session
108: * @return
109: */
110: private TimeSeries getTimeSerieForAccount(String acccount,
111: Session session) {
112: Date fromDateForThisAccount = params.fromDate;
113:
114: TimeSeries bts = new TimeSeries(acccount);
115: if (params.withSubaccounts)
116: bts.setName(bts.getName() + " (and sub.)");
117:
118: CapitalAccount a = (CapitalAccount) Util.getAccountByFullName(
119: session, acccount);
120: Entry e = null;
121:
122: // Sort the entries chronologicaly
123: List sortedEntries;
124: if (params.withSubaccounts)
125: sortedEntries = Util.getEntriesFromAccountAndSubaccounts(
126: session, a);
127: else
128: sortedEntries = Util.getEntriesFromAccount(session, a);
129:
130: sortedEntries = Util.sortChronogicalyEntries(sortedEntries);
131:
132: // If the first movement is after fromDate, set fromDate to this one
133: e = (Entry) sortedEntries.get(0);
134: if (e.getTransaction().getDate().after(params.fromDate))
135: fromDateForThisAccount = e.getTransaction().getDate();
136:
137: Hashtable saldos = new Hashtable();
138: Iterator it = sortedEntries.iterator();
139: long saldo = 0;
140: Day dateOfPreviousMouvement = null;
141: while (it.hasNext()) {
142: e = (Entry) it.next();
143: Day date = new Day(e.getTransaction().getDate());
144:
145: if (params.type == LineChartParameters.MOUVEMENT) {
146: // When calculating the MOUVEMENT, we have to sum the entries on a day only.
147: if (date.compareTo(dateOfPreviousMouvement) != 0)
148: saldo = 0;
149: saldo = saldo + e.getAmount();
150: } else if (params.type == LineChartParameters.SALDO_ABSOLUT
151: || params.type == LineChartParameters.BALANCE) {
152: // Saldo absolut: the entry is added to the last result
153: saldo = saldo + e.getAmount();
154: } else if (params.type == LineChartParameters.SALDO_RELATIV) {
155: // Saldo relativ: the entry is added only if after the begin of the
156: // chart
157: if (e.getTransaction().getDate().after(
158: fromDateForThisAccount))
159: saldo = saldo + e.getAmount();
160: }
161:
162: saldos.put(date, new Long(saldo));
163: dateOfPreviousMouvement = date;
164: }
165:
166: // Now, enter them in the table
167: Day date = new Day(fromDateForThisAccount);
168: saldo = 0;
169: while (!date.getEnd().after(params.toDate)) {
170: if (saldos.containsKey(date)) {
171: saldo = ((Long) saldos.get(date)).longValue() / 100;
172: } else if (params.type == LineChartParameters.MOUVEMENT) {
173: saldo = 0;
174: }
175:
176: if (ChartsPlugin.DEBUG)
177: System.out.println("Add to the graph: " + saldo
178: + " at " + date);
179: bts.add(date, new Double(saldo));
180: date = (Day) date.next();
181: }
182:
183: return bts;
184:
185: }
186:
187: /**
188: * Mix two series of dataes by adding or substracting the
189: * values of ts2 to the one of ts1.
190: * @param ts1 First series. It will be updated
191: * @param ts2 Second series. Won't be altered.
192: * @param ts2IsToAdd True if the values of ts2 have to be added to the one of ts1.
193: * False if they have to be substracted
194: * @see the function addAndOrUpdate from TimeSeries. This function has perhaps the same role
195: * but isn't documented.
196: * @author Faucheux
197: */
198: void mixTimeSeries(TimeSeries ts1, TimeSeries ts2,
199: boolean ts2IsToAdd) {
200: for (int i = 0; i < ts2.getItemCount(); i++) {
201: TimeSeriesDataItem itemOfTs2 = (TimeSeriesDataItem) ts2
202: .getDataItem(i).clone();
203: TimeSeriesDataItem itemOfTs1 = ts1.getDataItem(itemOfTs2
204: .getPeriod());
205: if (!ts2IsToAdd) {
206: itemOfTs2.setValue(new Long((-1)
207: * itemOfTs2.getValue().longValue()));
208: }
209: if (itemOfTs1 != null) {
210: System.out.println("I'm adding " + itemOfTs1.getValue()
211: + " and " + itemOfTs2.getValue());
212: itemOfTs2.setValue(new Long(itemOfTs2.getValue()
213: .longValue()
214: + itemOfTs1.getValue().longValue()));
215: }
216: System.out.println("I'm adding " + itemOfTs2.getValue()
217: + " to ts1 for " + itemOfTs2.getPeriod());
218: ts1
219: .addOrUpdate(itemOfTs2.getPeriod(), itemOfTs2
220: .getValue());
221: }
222: }
223: }
|