Grundaufbau der App
[DHBWCampusApp.git] / app / src / main / java / de / dhbwloe / campusapp / vorlesungen / VorlesungsplanManager.java
1 package de.dhbwloe.campusapp.vorlesungen;
2
3
4 import android.util.Log;
5
6 import net.fortuna.ical4j.model.Calendar;
7 import net.fortuna.ical4j.model.Component;
8 import net.fortuna.ical4j.model.Property;
9
10 import java.text.DateFormat;
11 import java.text.ParseException;
12 import java.text.SimpleDateFormat;
13 import java.util.ArrayList;
14 import java.util.Date;
15 import java.util.ListIterator;
16 import java.util.Locale;
17
18 import de.dhbwloe.campusapp.CampusAppContext;
19 import de.dhbwloe.campusapp.network.IscRequestHelper;
20 import de.dhbwloe.campusapp.search.SearchIndices;
21
22 /**
23  * Created by pk910 on 19.01.2016.
24  */
25 public class VorlesungsplanManager extends IscRequestHelper {
26     private static final String[][] PLAN_SOURCES = {
27             {"STUV", "https://www.google.com/calendar/ical/asta.dhbw.de_c0g35t6hrh16kr4ankrqg2rdm4%40group.calendar.google.com/public/basic.ics"},
28     };
29
30     private CampusAppContext AppContext;
31     private boolean bRequestRunning = false;
32     private boolean bFastSynchronisation = false;
33     private String sCourseName;
34     private String source[];
35     private ArrayList<VorlesungsplanManagerInterface> aCallbackInterfaces = new ArrayList<VorlesungsplanManagerInterface>();
36
37     public VorlesungsplanManager(CampusAppContext context, String courseName) {
38         AppContext = context;
39         sCourseName = courseName;
40
41         for(String src[] : PLAN_SOURCES) {
42             if(src[0].equalsIgnoreCase(courseName)) {
43                 source = src;
44                 break;
45             }
46         }
47     }
48
49     public void performFastSynchronisation(VorlesungsplanManagerInterface callback) {
50         performSynchronisation(callback, false);
51     }
52
53     public void performFullSynchronisation(VorlesungsplanManagerInterface callback) {
54         performSynchronisation(callback, true);
55     }
56
57     private void performSynchronisation(VorlesungsplanManagerInterface callback, boolean fullsync) {
58         if(sCourseName.length() == 0) {
59             callback.onVorlesungsplanUpdateFail("no course name");
60             return;
61         }
62
63         aCallbackInterfaces.add(callback);
64         if(bRequestRunning)
65             return;
66
67         bFastSynchronisation = !fullsync;
68         bRequestRunning = true;
69         String courseCalendarUrl;
70         if(source == null) {
71             courseCalendarUrl = "https://webmail.dhbw-loerrach.de/owa/calendar/kal-" + sCourseName + "@dhbw-loerrach.de/Kalender/calendar.ics";
72         } else {
73             courseCalendarUrl = source[1];
74         }
75         requestCalenderFromWeb(courseCalendarUrl);
76     }
77
78     @Override
79     protected void onCalendarReceived(Calendar calendar) {
80         long timeFrom, timeTo;
81         long now = (new Date()).getTime() / 1000;
82         if(bFastSynchronisation) {
83             timeFrom = now - (86400 * 5);
84             timeTo = now + (86400 * 7 * 4);
85         } else {
86             timeFrom = now - (86400 * 365 * 3);
87             timeTo = now + (86400 * 365 * 4);
88         }
89         CourseEvent[] events = AppContext.getDatabaseManager().getCourseCalendarEvents(sCourseName, timeFrom, timeTo);
90         Log.i("VPMSync", "Event count: " + events.length);
91         ArrayList<CourseEvent> newEvents = new ArrayList<CourseEvent>();
92         ArrayList<SearchIndices> newIndices = new ArrayList<SearchIndices>();
93         int lastEventIndex = 0;
94         ListIterator cIterator = calendar.getComponents().listIterator();
95
96         while (cIterator.hasNext()) {
97             Component event = (Component)cIterator.next();
98             CourseEvent dbEvent;
99             Property prop;
100
101             prop = event.getProperty("UID");
102             String uid;
103             if(prop != null)
104                 uid = prop.getValue();
105             else
106                 continue;
107
108             prop = event.getProperty("SEQUENCE");
109             int sequence;
110             if(prop != null)
111                 sequence = Integer.parseInt(prop.getValue());
112             else
113                 sequence = 1;
114
115             long startTime = 0, endTime = 0;
116             prop = event.getProperty("DTSTART");
117             if(prop != null)
118                 startTime = getTimeFromTimestamp(prop.getValue());
119             else
120                 Log.i("VPMSync", "Parse Event: DTSTART not found!");
121
122             prop = event.getProperty("DTEND");
123             if(prop != null)
124                 endTime = getTimeFromTimestamp(prop.getValue());
125             else
126                 Log.i("VPMSync", "Parse Event: DTEND not found!");
127
128             if(!(endTime > timeFrom && startTime < timeTo)) {
129                 Log.i("VPMSync", "Skip Entry: ("+timeFrom+" - "+timeTo+")   Filter: "+startTime+" - "+endTime);
130                 continue;
131             }
132
133             dbEvent = null;
134             for(int i = lastEventIndex; i < events.length; i++) {
135                 if(events[i].getUniqueId().equalsIgnoreCase(uid)) {
136                     dbEvent = events[i];
137                     break;
138                 }
139             }
140             if(dbEvent == null && lastEventIndex > 0) {
141                 for(int i = 0; i < lastEventIndex; i++) {
142                     if(events[i].getUniqueId().equalsIgnoreCase(uid)) {
143                         dbEvent = events[i];
144                         break;
145                     }
146                 }
147             }
148             if(dbEvent == null) {
149                 for(CourseEvent cevent : newEvents) {
150                     if(cevent.getUniqueId().equalsIgnoreCase(uid)) {
151                         dbEvent = cevent;
152                         break;
153                     }
154                 }
155             }
156
157             if(dbEvent == null) {
158                 // new event!
159                 Log.i("VLPSync", "New Event "+uid);
160                 dbEvent = new CourseEvent(sCourseName, uid, sequence, true);
161                 newEvents.add(dbEvent);
162             } else {
163                 Log.i("VLPSync", "Existing Event "+uid+" ("+dbEvent.getSequenceId()+" >= "+sequence+")");
164                 if(dbEvent.getSequenceId() >= sequence) {
165                     continue; // skip event
166                 }
167                 dbEvent.setSequenceId(sequence);
168             }
169             // perform update
170             prop = event.getProperty("SUMMARY");
171             if(prop != null)
172                 dbEvent.setEventTitle(prop.getValue());
173             else
174                 Log.i("VPMSync", "Parse Event: SUMMARY not found!");
175
176             dbEvent.setEventFrom(startTime);
177             dbEvent.setEventTo(endTime);
178
179             prop = event.getProperty("LOCATION");
180             if(prop != null)
181                 dbEvent.setEventLocation(prop.getValue());
182             else
183                 Log.i("VPMSync", "Parse Event: LOCATION not found!");
184
185             prop = event.getProperty("STATUS");
186             if(prop != null)
187                 dbEvent.setEventStatus(prop.getValue());
188             else
189                 Log.i("VPMSync", "Parse Event: STATUS not found!");
190
191             prop = event.getProperty("RRULE");
192             if(prop != null)
193                 dbEvent.setRecurRule(prop.getValue());
194             else
195                 dbEvent.setRecurRule("");
196
197             prop = event.getProperty("EXDATE");
198             if(prop != null)
199                 dbEvent.setExcludeDates(prop.getValue());
200             else
201                 dbEvent.setExcludeDates("");
202
203             CourseGroup group = CourseGroup.GetCourseGroupByName(AppContext.getDatabaseManager(), sCourseName, dbEvent.getGroupTitle().trim());
204             if(group != null)
205                 dbEvent.setCourseGroup(group);
206
207             if(group.isNewGroup(true)) {
208                 SearchIndices indices = new SearchIndices("Vorlesungsplan#Group"+group.getGroupId(), false);
209                 indices.setUpdateTime(dbEvent.getEventFrom());
210                 indices.setTarget("#Vorlesungsplan#groupid=" + group.getGroupId());
211                 indices.setTitle("Vorlesungsplan " + dbEvent.getCourseName());
212                 indices.setDescription("Vorlesung " + dbEvent.getEventTitle());
213                 indices.addKeyWord(dbEvent.getGroupTitle());
214                 indices.addKeyWord(dbEvent.getEventLocation());
215                 newIndices.add(indices);
216             }
217
218             dbEvent.update(AppContext.getDatabaseManager());
219             Log.i("VPMSync", "Update Event: "+dbEvent.getUniqueId());
220         }
221
222         SearchIndices[] newIndicesArr = new SearchIndices[newIndices.size()];
223         newIndicesArr = newIndices.toArray(newIndicesArr);
224         AppContext.addSearchIndices(newIndicesArr);
225
226         for(VorlesungsplanManagerInterface callback : aCallbackInterfaces) {
227             callback.onVorlesungsplanUpdateDone();
228         }
229         aCallbackInterfaces.clear();
230         bRequestRunning = false;
231     }
232
233     private long getTimeFromTimestamp(String timestamp) {
234         // 20160425T090000
235         // 20160321
236         DateFormat df = new SimpleDateFormat("yyyyMMdd'T'kkmmss", Locale.ENGLISH);
237         try {
238             Date result =  df.parse(timestamp);
239             return result.getTime()/1000;
240         } catch (ParseException e) {
241             df = new SimpleDateFormat("yyyyMMdd", Locale.ENGLISH);
242             try {
243                 Date result =  df.parse(timestamp);
244                 return result.getTime()/1000;
245             } catch (ParseException e2) {
246                 Log.i("VPMSync", "Failed parsing: "+timestamp);
247                 return 0;
248             }
249         }
250     }
251
252     @Override
253     protected void onCalendarRequestFail(int statusCode, String errorMessage) {
254         Log.i("VPM", "Calendar Error: "+statusCode);
255         for(VorlesungsplanManagerInterface callback : aCallbackInterfaces) {
256             callback.onVorlesungsplanUpdateFail("error "+statusCode+": "+errorMessage);
257         }
258         aCallbackInterfaces.clear();
259         bRequestRunning = false;
260     }
261 }