package com.instructure.canvasapi.api;
import android.content.Context;
import android.text.TextUtils;
import com.instructure.canvasapi.model.CanvasContext;
import com.instructure.canvasapi.model.ScheduleItem;
import com.instructure.canvasapi.utilities.APIHelpers;
import com.instructure.canvasapi.utilities.CanvasCallback;
import com.instructure.canvasapi.utilities.ExhaustiveBridgeCallback;
import java.util.ArrayList;
import retrofit.Callback;
import retrofit.http.Body;
import retrofit.http.DELETE;
import retrofit.http.EncodedQuery;
import retrofit.http.GET;
import retrofit.http.POST;
import retrofit.http.Path;
import retrofit.http.Query;
/**
* Created by Brady Larson on 10/9/13.
*
* Copyright (c) 2014 Instructure. All rights reserved.
*/
public class CalendarEventAPI extends BuildInterfaceAPI {
public enum EVENT_TYPE {CALENDAR_EVENT, ASSIGNMENT_EVENT;
public static String getEventTypeName(EVENT_TYPE eventType) {
if(eventType == CALENDAR_EVENT) {
return "event";
} else {
return "assignment";
}
}
}
private static String getCalendarEventCacheFilename(long eventID) {
return "/calendar_events/" + eventID;
}
private static String getCalendarEventsCacheFilename(CanvasContext canvasContext) {
return "/calendar_events?start_date=1990-01-01&end_date=2099-12-31&context_codes[]=" + canvasContext.getId();
}
private static String getUpcomingEventsCacheFilename(){
return "/users/self/upcoming_events";
}
private static String getAllEventsCacheFilename(String startDate, EVENT_TYPE eventType){
String resultString = startDate.replaceAll("[^\\p{L}\\p{Nd}]+", "");
return "/users/self/all" + eventType.name() + resultString.substring(0, 7);
}
private static String getAllCalendarEventsCacheFilename(String contextIds, EVENT_TYPE eventType){
int lengthLimit = contextIds.length();
if (lengthLimit > 30) {
lengthLimit = 30;
}
return "/calendar_events?all_events=1&type=" + eventType.name() + "&" + contextIds.substring(0, lengthLimit); // limit the filename length
}
public interface CalendarEventsInterface {
@GET("/calendar_events/{event_id}")
void getCalendarEvent(@Path("event_id") long event_id, Callback<ScheduleItem> callback);
@GET("/canvas/{parentId}/{studentId}/calendar_events/{eventId}")
void getCalendarEventAirwolf(@Path("parentId") String parentId, @Path("studentId") String studentId, @Path("eventId") String eventId, Callback<ScheduleItem> callback);
@GET("/calendar_events?start_date=1990-01-01&end_date=2099-12-31")
void getCalendarEvents(@Query("context_codes[]") String context_id, Callback<ScheduleItem[]> callback);
@GET("/users/self/upcoming_events")
void getUpcomingEvents(Callback<ScheduleItem[]> callback);
@GET("/{next}")
void getNextPageCalendarEvents(@Path(value = "next", encode = false) String nextURL, Callback<ScheduleItem[]> callback);
@GET("/calendar_events/")
void getCalendarEvents(
@Query("all_events") boolean allEvents,
@Query("type") String type,
@EncodedQuery("context_codes[]") String contextCodes,
Callback<ScheduleItem[]> callback);
@GET("/calendar_events/")
void getCalendarEvents(
@Query("all_events") boolean allEvents,
@Query("type") String type,
@Query("start_date") String startDate,
@Query("end_date") String endDate,
@EncodedQuery("context_codes[]") String contextCodes,
Callback<ScheduleItem[]> callback);
@POST("/calendar_events/")
void createCalendarEvent(@Query("calendar_event[context_code]") String contextCode,
@Query("calendar_event[title]") String title,
@Query("calendar_event[description]") String description,
@Query("calendar_event[start_at]") String startDate,
@Query("calendar_event[end_at]") String endDate,
@Query("calendar_event[location_name]") String locationName,
@Body String body,
CanvasCallback<ScheduleItem> callback);
@DELETE("/calendar_events/{event_id}")
void deleteCalendarEvent(@Path("event_id") long event_id, @Query("cancel_reason") String cancelReason,
CanvasCallback<ScheduleItem> callback);
@GET("/users/{user_id}/calendar_events/")
void getCalendarEventsForUser(
@Path("user_id") long user_id,
@Query("type") String type,
@Query("start_date") String startDate,
@Query("end_date") String endDate,
@EncodedQuery("context_codes[]") String contextCodes,
Callback<ScheduleItem[]> callback);
@GET("/users/{user_id}/calendar_events?include[]=submission")
void getCalendarEventsForUserWithSubmissions(
@Path("user_id") long user_id,
@Query("type") String type,
@Query("start_date") String startDate,
@Query("end_date") String endDate,
@EncodedQuery("context_codes[]") String contextCodes,
Callback<ScheduleItem[]> callback);
@GET("/canvas/{parent_id}/{student_id}/calendar_events?include[]=submission")
void getCalendarEventsWithSubmissionsAirwolf(
@Path("parent_id") String parentId,
@Path("student_id") String studentId,
@Query("start_date") String startDate,
@Query("end_date") String endDate,
@EncodedQuery("context_codes[]") String contextCodes,
Callback<ScheduleItem[]> callback);
/////////////////////////////////////////////////////////////////////////////
// Synchronous
/////////////////////////////////////////////////////////////////////////////
@GET("/users/self/upcoming_events")
ScheduleItem[] getUpcomingEvents();
}
/////////////////////////////////////////////////////////////////////////
// API Calls
/////////////////////////////////////////////////////////////////////////
public static void getCalendarEvent(long calendarEventId, final CanvasCallback<ScheduleItem> callback) {
if (APIHelpers.paramIsNull(callback)) { return; }
buildCacheInterface(CalendarEventsInterface.class, callback).getCalendarEvent(calendarEventId, callback);
buildInterface(CalendarEventsInterface.class, callback).getCalendarEvent(calendarEventId, callback);
}
public static void getCalendarEventAirwolf(String parentId, String studentId, String eventId, final CanvasCallback<ScheduleItem> callback) {
if (APIHelpers.paramIsNull(callback)) { return; }
buildCacheInterface(CalendarEventsInterface.class, callback).getCalendarEventAirwolf(parentId, studentId, eventId, callback);
buildInterface(CalendarEventsInterface.class, callback).getCalendarEventAirwolf(parentId, studentId, eventId, callback);
}
public static void getCalendarEvents(CanvasContext canvasContext, final CanvasCallback<ScheduleItem[]> callback) {
if (APIHelpers.paramIsNull(callback, canvasContext)) { return; }
buildCacheInterface(CalendarEventsInterface.class, callback).getCalendarEvents(canvasContext.getContextId(), callback);
buildInterface(CalendarEventsInterface.class, callback).getCalendarEvents(canvasContext.getContextId(), callback);
}
public static void getUpcomingEvents(final CanvasCallback<ScheduleItem[]> callback) {
if (APIHelpers.paramIsNull(callback)) { return; }
buildCacheInterface(CalendarEventsInterface.class, callback).getUpcomingEvents(callback);
buildInterface(CalendarEventsInterface.class, callback).getUpcomingEvents(callback);
}
public static void getNextPageCalendarEventsChained(String nextURL, CanvasCallback<ScheduleItem[]> callback, boolean isCached){
if(APIHelpers.paramIsNull(callback, nextURL)){ return;}
callback.setIsNextPage(true);
if (isCached) {
buildCacheInterface(CalendarEventsInterface.class, callback, false).getNextPageCalendarEvents(nextURL, callback);
} else {
buildInterface(CalendarEventsInterface.class, callback, false).getNextPageCalendarEvents(nextURL, callback);
}
}
public static void getAllCalendarEventsExhaustive(EVENT_TYPE eventType, String startDate, String endDate, ArrayList<String> canvasContextIds, final CanvasCallback<ScheduleItem[]> callback) {
String contextIds = buildContextArray(canvasContextIds);
CanvasCallback<ScheduleItem[]> bridge = new ExhaustiveBridgeCallback<>(ScheduleItem.class, callback, new ExhaustiveBridgeCallback.ExhaustiveBridgeEvents() {
@Override
public void performApiCallWithExhaustiveCallback(CanvasCallback bridgeCallback, String nextURL, boolean isCached) {
if(callback.isCancelled()) { return; }
CalendarEventAPI.getNextPageCalendarEventsChained(nextURL, bridgeCallback, isCached);
}
});
buildCacheInterface(CalendarEventsInterface.class, callback).getCalendarEvents(false, EVENT_TYPE.getEventTypeName(eventType), startDate, endDate, contextIds, bridge);
buildInterface(CalendarEventsInterface.class, callback).getCalendarEvents(false, EVENT_TYPE.getEventTypeName(eventType), startDate, endDate, contextIds, bridge);
}
public static void getAllCalendarEventsExhaustive(EVENT_TYPE eventType, ArrayList<String> canvasContextIds, final CanvasCallback<ScheduleItem[]> callback) {
String contextIds = buildContextArray(canvasContextIds);
CanvasCallback<ScheduleItem[]> bridge = new ExhaustiveBridgeCallback<>(ScheduleItem.class, callback, new ExhaustiveBridgeCallback.ExhaustiveBridgeEvents() {
@Override
public void performApiCallWithExhaustiveCallback(CanvasCallback bridgeCallback, String nextURL, boolean isCached) {
if(callback.isCancelled()) { return; }
CalendarEventAPI.getNextPageCalendarEventsChained(nextURL, bridgeCallback, isCached);
}
});
buildCacheInterface(CalendarEventsInterface.class, callback).getCalendarEvents(true, EVENT_TYPE.getEventTypeName(eventType), contextIds, bridge);
buildInterface(CalendarEventsInterface.class, callback).getCalendarEvents(true, EVENT_TYPE.getEventTypeName(eventType), contextIds, bridge);
}
public static void createCalendarEvent(String contextCode, String title, String description, String startDate, String endDate, String location, final CanvasCallback<ScheduleItem> callback){
if(APIHelpers.paramIsNull(callback, contextCode) || TextUtils.isEmpty(startDate) || TextUtils.isEmpty(endDate)){return;}
buildInterface(CalendarEventsInterface.class, callback).createCalendarEvent(contextCode, title, description, startDate, endDate, location, "", callback);
}
public static void deleteCalendarEvent(long calendarEventId, String cancelReason, CanvasCallback<ScheduleItem> callback){
if(APIHelpers.paramIsNull(callback)){return;}
buildInterface(CalendarEventsInterface.class, callback).deleteCalendarEvent(calendarEventId, cancelReason, callback);
}
public static void getAllCalendarEventsForUserExhaustive(long userId, EVENT_TYPE eventType, String startDate, String endDate, ArrayList<String> canvasContextIds, final CanvasCallback<ScheduleItem[]> callback) {
CanvasCallback<ScheduleItem[]> bridge = new ExhaustiveBridgeCallback<>(ScheduleItem.class, callback, new ExhaustiveBridgeCallback.ExhaustiveBridgeEvents() {
@Override
public void performApiCallWithExhaustiveCallback(CanvasCallback bridgeCallback, String nextURL, boolean isCached) {
if(callback.isCancelled()) { return; }
CalendarEventAPI.getNextPageCalendarEventsChained(nextURL, bridgeCallback, isCached);
}
});
buildCacheInterface(CalendarEventsInterface.class, callback).getCalendarEventsForUser(userId, EVENT_TYPE.getEventTypeName(eventType), startDate, endDate, buildContextArray(canvasContextIds), bridge);
buildInterface(CalendarEventsInterface.class, callback).getCalendarEventsForUser(userId, EVENT_TYPE.getEventTypeName(eventType), startDate, endDate, buildContextArray(canvasContextIds), bridge);
}
public static void getAllCalendarEventsForUserWithSubmissionsExhaustive(long userId, EVENT_TYPE eventType, String startDate, String endDate, ArrayList<String> canvasContextIds, final CanvasCallback<ScheduleItem[]> callback) {
CanvasCallback<ScheduleItem[]> bridge = new ExhaustiveBridgeCallback<>(ScheduleItem.class, callback, new ExhaustiveBridgeCallback.ExhaustiveBridgeEvents() {
@Override
public void performApiCallWithExhaustiveCallback(CanvasCallback bridgeCallback, String nextURL, boolean isCached) {
if(callback.isCancelled()) { return; }
CalendarEventAPI.getNextPageCalendarEventsChained(nextURL, bridgeCallback, isCached);
}
});
buildCacheInterface(CalendarEventsInterface.class, callback).getCalendarEventsForUserWithSubmissions(userId, EVENT_TYPE.getEventTypeName(eventType), startDate, endDate, buildContextArray(canvasContextIds), bridge);
buildInterface(CalendarEventsInterface.class, callback).getCalendarEventsForUserWithSubmissions(userId, EVENT_TYPE.getEventTypeName(eventType), startDate, endDate, buildContextArray(canvasContextIds), bridge);
}
public static void getAllCalendarEventsWithSubmissionsExhaustiveAirwolf(String parentId, String studentId, String startDate, String endDate, ArrayList<String> canvasContextIds, final CanvasCallback<ScheduleItem[]> callback) {
CanvasCallback<ScheduleItem[]> bridge = new ExhaustiveBridgeCallback<>(ScheduleItem.class, callback, new ExhaustiveBridgeCallback.ExhaustiveBridgeEvents() {
@Override
public void performApiCallWithExhaustiveCallback(CanvasCallback bridgeCallback, String nextURL, boolean isCached) {
if(callback.isCancelled()) { return; }
CalendarEventAPI.getNextPageCalendarEventsChained(nextURL, bridgeCallback, isCached);
}
});
buildCacheInterface(CalendarEventsInterface.class, APIHelpers.getAirwolfDomain(callback.getContext()), callback).getCalendarEventsWithSubmissionsAirwolf(parentId, studentId, startDate, endDate, buildContextArray(canvasContextIds), bridge);
buildInterface(CalendarEventsInterface.class, APIHelpers.getAirwolfDomain(callback.getContext()), callback).getCalendarEventsWithSubmissionsAirwolf(parentId, studentId, startDate, endDate, buildContextArray(canvasContextIds), bridge);
}
private static String buildContextArray(ArrayList<String> canvasContextIds){
//Builds an array of context_codes, the way we have to build and send the array is funky.
StringBuilder sb = new StringBuilder();
for (int i = 0; i < canvasContextIds.size(); i++) {
sb.append(canvasContextIds.get(i));
if(i == canvasContextIds.size() - 1) {
break;
}
sb.append("&context_codes[]=");
}
return sb.toString();
}
/////////////////////////////////////////////////////////////////////////////
// Synchronous
//
// If Retrofit is unable to parse (no network for example) Synchronous calls
// will throw a nullPointer exception. All synchronous calls need to be in a
// try catch block.
/////////////////////////////////////////////////////////////////////////////
public static ScheduleItem[] getUpcomingEventsSynchronous(Context context) {
try {
return buildInterface(CalendarEventsInterface.class, context).getUpcomingEvents();
} catch (Exception E){
return null;
}
}
}