001: /*
002: Copyright (C) 2003 Know Gate S.L. All rights reserved.
003: C/Oņa, 107 1š2 28050 Madrid (Spain)
004:
005: Redistribution and use in source and binary forms, with or without
006: modification, are permitted provided that the following conditions
007: are met:
008:
009: 1. Redistributions of source code must retain the above copyright
010: notice, this list of conditions and the following disclaimer.
011:
012: 2. The end-user documentation included with the redistribution,
013: if any, must include the following acknowledgment:
014: "This product includes software parts from hipergate
015: (http://www.hipergate.org/)."
016: Alternately, this acknowledgment may appear in the software itself,
017: if and wherever such third-party acknowledgments normally appear.
018:
019: 3. The name hipergate must not be used to endorse or promote products
020: derived from this software without prior written permission.
021: Products derived from this software may not be called hipergate,
022: nor may hipergate appear in their name, without prior written
023: permission.
024:
025: This library is distributed in the hope that it will be useful,
026: but WITHOUT ANY WARRANTY; without even the implied warranty of
027: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
028:
029: You should have received a copy of hipergate License with this code;
030: if not, visit http://www.hipergate.org or mail to info@hipergate.org
031: */
032:
033: package com.knowgate.addrbook;
034:
035: import java.util.Date;
036:
037: import java.sql.SQLException;
038:
039: import com.knowgate.debug.DebugFile;
040: import com.knowgate.jdc.JDCConnection;
041: import com.knowgate.dataobjs.DB;
042: import com.knowgate.dataobjs.DBBind;
043: import com.knowgate.dataobjs.DBSubset;
044:
045: /**
046: * <p>A bidimensional array with daily scheduled meeting in quarters of an hour.</p>
047: * @author Sergio Montoro Ten
048: * @version 1.0
049: */
050:
051: /*
052: This class stores internally a bidimensional matrix that associates daily
053: time slices with meetings having place at each slice. The association is
054: stablished by first loading meetings for a given date and then building a
055: list for each slice witch entries point to meetings having place at that
056: slice.
057: Lets say that there are four meetings in a day, one from 9:30 to 10:30
058: [nš 0], another from 10:00 to 10:30 [nš 1], another from 11:00 to 12:00
059: [nš 2] and a last one from 11:45 to 12:30 [nš 3].
060: The internal array will then have this form:
061:
062: ... [slots from 00:00 up to 9:30]
063: 09:30 -----------------------------------------------------------------------
064: slot 0 | slot 1 | slot 2 | slot 3 | slot 4 | slot 5 | slot 6 | slot 7
065: 0 (empty) (empty) (empty) (empty) (empty) (empty) (empty)
066: 09:45 -----------------------------------------------------------------------
067: slot 0 | slot 1 | slot 2 | slot 3 | slot 4 | slot 5 | slot 6 | slot 7
068: 0 (empty) (empty) (empty) (empty) (empty) (empty) (empty)
069: 10:00 -----------------------------------------------------------------------
070: slot 0 | slot 1 | slot 2 | slot 3 | slot 4 | slot 5 | slot 6 | slot 7
071: 0 1 (empty) (empty) (empty) (empty) (empty) (empty)
072: 10:15 -----------------------------------------------------------------------
073: slot 0 | slot 1 | slot 2 | slot 3 | slot 4 | slot 5 | slot 6 | slot 7
074: 0 1 (empty) (empty) (empty) (empty) (empty) (empty)
075: 10:30 -----------------------------------------------------------------------
076: slot 0 | slot 1 | slot 2 | slot 3 | slot 4 | slot 5 | slot 6 | slot 7
077: (empty) (empty) (empty) (empty) (empty) (empty) (empty) (empty)
078: 11:00 -----------------------------------------------------------------------
079: slot 0 | slot 1 | slot 2 | slot 3 | slot 4 | slot 5 | slot 6 | slot 7
080: 2 (empty) (empty) (empty) (empty) (empty) (empty) (empty)
081: 11:15 -----------------------------------------------------------------------
082: slot 0 | slot 1 | slot 2 | slot 3 | slot 4 | slot 5 | slot 6 | slot 7
083: 2 (empty) (empty) (empty) (empty) (empty) (empty) (empty)
084: 11:30 -----------------------------------------------------------------------
085: slot 0 | slot 1 | slot 2 | slot 3 | slot 4 | slot 5 | slot 6 | slot 7
086: 2 (empty) (empty) (empty) (empty) (empty) (empty) (empty)
087: 11:45 -----------------------------------------------------------------------
088: slot 0 | slot 1 | slot 2 | slot 3 | slot 4 | slot 5 | slot 6 | slot 7
089: 2 3 (empty) (empty) (empty) (empty) (empty) (empty)
090: 12:00 -----------------------------------------------------------------------
091: slot 0 | slot 1 | slot 2 | slot 3 | slot 4 | slot 5 | slot 6 | slot 7
092: 3 (empty) (empty) (empty) (empty) (empty) (empty) (empty)
093: 12:15 -----------------------------------------------------------------------
094: slot 0 | slot 1 | slot 2 | slot 3 | slot 4 | slot 5 | slot 6 | slot 7
095: 3 (empty) (empty) (empty) (empty) (empty) (empty) (empty)
096:
097: ... [slots from 12:30:00 up to 23:45]
098:
099: This implies that there is a maximum of 8 concurrent meetings per slice.
100: If there were more concurrent meeting the class shall not raise any error
101: but will simply not show all of them.
102: */
103:
104: public class DayPlan {
105: private int aMeetings[][];
106: private DBSubset oMeetings;
107: private Meeting oMeeting;
108:
109: private final int MaxSlots = 8; // Maximum allowed concurrent meetings per slot
110: private final int MaxSlices = 96; // Slices per day 96=24/4 -> slices of 15 mins.
111: private final int EmptySlot = -1;
112: private final long SliceLapsus = (24 * 3600 * 1000) / MaxSlices;
113:
114: public DayPlan() {
115: oMeeting = new Meeting();
116: aMeetings = new int[MaxSlots][MaxSlices];
117: for (int slice = 0; slice < MaxSlices; slice++)
118: for (int slot = 0; slot < MaxSlots; slot++)
119: aMeetings[slot][slice] = EmptySlot;
120: } // DayPlan
121:
122: // ----------------------------------------------------------
123:
124: /**
125: * <p>Load scheduled meetings for a given Fellow.</p>
126: * @param oConn Database Connection
127: * @param sFellowId Fellow Unique Identifier
128: * @param dtToday Date for witch meeting are to be retrieved
129: * @throws SQLException
130: * @see {@link Fellow}
131: */
132: public void load(JDCConnection oConn, String sFellowId,
133: java.util.Date dtToday) throws SQLException {
134: if (DebugFile.trace) {
135: DebugFile.writeln("Begin DayPlan.load([Connection], "
136: + sFellowId + "," + dtToday.toString() + ")");
137: DebugFile.incIdent();
138: }
139:
140: long lToday = dtToday.getTime();
141: java.util.Date zero = new java.util.Date(lToday);
142: java.util.Date four = new java.util.Date(lToday);
143:
144: zero.setHours(0);
145: zero.setMinutes(0);
146: zero.setSeconds(0);
147: zero.setTime((zero.getTime() / 1000l) * 1000l); // truncar los milisegundos
148:
149: four.setHours(23);
150: four.setMinutes(59);
151: four.setSeconds(59);
152:
153: oMeetings = new DBSubset(DB.k_meetings + " m,"
154: + DB.k_x_meeting_fellow + " f", "m." + DB.gu_meeting
155: + ",m." + DB.gu_fellow + ",m." + DB.dt_start + ",m."
156: + DB.dt_end + ",m." + DB.bo_private + ",m."
157: + DB.df_before + ",m." + DB.tp_meeting + ",m."
158: + DB.tx_meeting + ",m." + DB.de_meeting, "m."
159: + DB.gu_meeting + "=f." + DB.gu_meeting + " AND f."
160: + DB.gu_fellow + "=? AND m." + DB.dt_start + ">="
161: + DBBind.escape(zero, "ts") + " AND m." + DB.dt_start
162: + "< " + DBBind.escape(four, "ts") + " ORDER BY m."
163: + DB.dt_start, 8);
164:
165: int mCount = oMeetings.load(oConn, new Object[] { sFellowId });
166:
167: if (DebugFile.trace)
168: DebugFile.writeln(String.valueOf(mCount)
169: + " meetings found");
170:
171: long dtStart, dtEnd, dtSliceBegin, dtZero = zero.getTime();
172:
173: for (int meeting = 0; meeting < mCount; meeting++) {
174: dtStart = oMeetings.getDate(2, meeting).getTime();
175: dtEnd = oMeetings.getDate(3, meeting).getTime();
176:
177: dtSliceBegin = dtZero;
178: for (int slice = 0; slice < MaxSlices; slice++) {
179: if ((dtStart >= dtSliceBegin && dtStart < dtSliceBegin
180: + SliceLapsus)
181: || (dtStart < dtSliceBegin && dtEnd > dtSliceBegin
182: + SliceLapsus))
183: for (int slot = 0; slot < MaxSlots; slot++)
184: if (EmptySlot == aMeetings[slot][slice]) {
185: if (DebugFile.trace) {
186: DebugFile.writeln("set slot["
187: + String.valueOf(slot)
188: + "]["
189: + String.valueOf(slice)
190: + "] to meeting "
191: + String.valueOf(meeting)
192: + " "
193: + oMeetings.getStringNull(7,
194: meeting, ""));
195: DebugFile.writeln("dtStart="
196: + new Date(dtStart).toString()
197: + "(" + String.valueOf(dtStart)
198: + "ms)");
199: DebugFile.writeln("dtEnd="
200: + new Date(dtEnd).toString()
201: + "(" + String.valueOf(dtEnd)
202: + "ms)");
203: DebugFile.writeln("dtSliceBegin="
204: + new Date(dtSliceBegin)
205: .toString() + "("
206: + String.valueOf(dtSliceBegin)
207: + "ms)");
208: DebugFile.writeln("dtSliceNext="
209: + new Date(dtSliceBegin
210: + SliceLapsus)
211: .toString()
212: + "("
213: + String.valueOf(dtSliceBegin
214: + SliceLapsus) + "ms)");
215: }
216: aMeetings[slot][slice] = meeting;
217: break;
218: } // fi (aMeetings[slot][slice])
219: dtSliceBegin += SliceLapsus;
220: } // next (slice)
221: } // next(meeting)
222:
223: if (DebugFile.trace) {
224: DebugFile.decIdent();
225: DebugFile.writeln("End DayPlan.load()");
226: }
227: } // load
228:
229: // ----------------------------------------------------------
230:
231: /**
232: * <p>Slice count per day.</p>
233: * <p>96 is the default and equals a day divided in 15 minutes slices</p>
234: * @return Maximum number of slices per day
235: */
236: public int sliceCount() {
237: return MaxSlices;
238: }
239:
240: // ----------------------------------------------------------
241:
242: /**
243: * @return Maximum number of allowed concurrent meetings per day slice
244: */
245: public int slotsPerSlice() {
246: return MaxSlots;
247: }
248:
249: // ----------------------------------------------------------
250:
251: /**
252: * <p>Get count of concurrent meetings at a given slice</p>
253: * @param slice [0...sliceCount()-1]
254: * @throws ArrayIndexOutOfBoundsException If slice<0 or slice>=sliceCount()
255: */
256:
257: public int concurrentMeetings(int slice)
258: throws ArrayIndexOutOfBoundsException {
259: int slots = 0;
260:
261: do {
262: if (EmptySlot != aMeetings[slots][slice])
263: slots++;
264: else
265: break;
266: } while (slots < MaxSlots);
267:
268: return slots;
269: } // concurrentMeetings
270:
271: // ----------------------------------------------------------
272:
273: /**
274: * <p>Get meeting information</p>
275: * <p>Each meeting is asoociated with one or more day slices by having a list
276: * at the slice that point to every meeting taking place on the slice.</p>
277: * <p>Thus for retriving a meeting both the slice number and the relative ordinal
278: * position of the meeting at the slice are needed.</p>
279: * @param slice [0...sliceCount()-1]
280: * @param slot [0...slotsPerSlice()-1]
281: * @throws ArrayIndexOutOfBoundsException If slice<0 or slice>=sliceCount() or slot<0 or slot>=slotsPerSlice()
282: * @return {@link Meeting} or <b>null</b> if no meeting was found at the given (slice,slot) pair.
283: */
284: public Meeting getMeeting(int slice, int slot)
285: throws ArrayIndexOutOfBoundsException {
286: if (DebugFile.trace) {
287: DebugFile.writeln("Begin DayPlan.getMeeting("
288: + String.valueOf(slice) + ","
289: + String.valueOf(slot) + ")");
290: }
291:
292: if (slice >= MaxSlices || slot >= MaxSlots)
293: return null;
294:
295: int iMeeting = aMeetings[slot][slice];
296:
297: if (DebugFile.trace)
298: DebugFile.writeln("iMeeting=" + String.valueOf(iMeeting));
299:
300: if (-1 == iMeeting)
301: return null;
302:
303: oMeeting.clear();
304:
305: if (DebugFile.trace)
306: DebugFile.writeln("Meeting object cleared");
307:
308: oMeeting.put(DB.gu_meeting, oMeetings.getString(0, iMeeting));
309: oMeeting.put(DB.gu_fellow, oMeetings.getString(1, iMeeting));
310: oMeeting.put(DB.dt_start, oMeetings.getDate(2, iMeeting));
311: oMeeting.put(DB.dt_end, oMeetings.getDate(3, iMeeting));
312:
313: if (DebugFile.trace)
314: if (oMeetings.getShort(4, iMeeting) != (short) 0)
315: DebugFile.writeln("meeting is private");
316:
317: oMeeting.put(DB.bo_private, oMeetings.getShort(4, iMeeting));
318:
319: if (!oMeetings.isNull(5, iMeeting))
320: oMeeting.put(DB.df_before, oMeetings.getInt(5, iMeeting));
321: if (!oMeetings.isNull(6, iMeeting))
322: oMeeting.put(DB.tp_meeting, oMeetings
323: .getString(6, iMeeting));
324: oMeeting.put(DB.tx_meeting, oMeetings.getStringNull(7,
325: iMeeting, ""));
326: oMeeting.put(DB.de_meeting, oMeetings.getStringNull(8,
327: iMeeting, ""));
328:
329: if (DebugFile.trace) {
330: DebugFile.writeln("End DayPlan.getMeeting() : "
331: + oMeetings.getString(0, iMeeting));
332: }
333:
334: return oMeeting;
335: } // getMeeting()
336:
337: // ----------------------------------------------------------
338:
339: /**
340: * <p>Lookup a meeting given its unique identifier</p>
341: * @param sMeeting Meeting Unique Identifier
342: * @return {@link Meeting} or <b>null</b> if no meeting was found with given identifier.
343: */
344: public Meeting seekMeeting(String sMeeting) {
345: int iMeetings = oMeetings.getRowCount();
346:
347: for (int m = 0; m < iMeetings; m++) {
348: if (sMeeting.equals(oMeetings.getString(0, m))) {
349: oMeeting.clear();
350:
351: oMeeting.put(DB.gu_meeting, oMeetings.getString(0, m));
352: oMeeting.put(DB.gu_fellow, oMeetings.getString(1, m));
353: oMeeting.put(DB.dt_start, oMeetings.getDate(2, m));
354: oMeeting.put(DB.dt_end, oMeetings.getDate(3, m));
355: oMeeting.put(DB.bo_private, oMeetings.getShort(4, m));
356: if (!oMeetings.isNull(5, m))
357: oMeeting.put(DB.df_before, oMeetings.getInt(5, m));
358: if (!oMeetings.isNull(6, m))
359: oMeeting.put(DB.tp_meeting, oMeetings.getString(6,
360: m));
361: oMeeting.put(DB.tx_meeting, oMeetings.getStringNull(7,
362: m, ""));
363: oMeeting.put(DB.de_meeting, oMeetings.getStringNull(8,
364: m, ""));
365:
366: return oMeeting;
367: }
368: }
369: return null;
370: } // seekMeeting
371: } // DayPlay
|