package com.mindflakes.TeamRED.server;
//
//import com.google.appengine.api.users.User;
//import com.google.appengine.api.users.UserService;
//import com.google.appengine.api.users.UserServiceFactory;
import com.google.appengine.api.datastore.Query.FilterOperator;
import com.google.appengine.api.datastore.*;
import org.joda.time.DateTime;
//import org.joda.time.format.DateTimeFormat;
//import com.mindflakes.TeamRED.utils.MealMenuUtil;
//import com.mindflakes.TeamRED.tests.MealMenuTestUtils;
import com.mindflakes.TeamRED.UCSBScrape.*;
import com.mindflakes.TeamRED.menuClasses.*;
import java.util.Iterator;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import com.vercer.engine.persist.annotation.AnnotationObjectDatastore;
import com.google.appengine.api.labs.taskqueue.Queue;
import com.google.appengine.api.labs.taskqueue.QueueFactory;
import com.google.appengine.api.labs.taskqueue.TaskOptions;
import static com.google.appengine.api.labs.taskqueue.TaskOptions.Builder.*;
/**
* @author Johan Henkens
* Utility class used for managing the datastore for the REDMenu app.
*/
public class DatastoreUpdater {
/**
* Method to be used ONLY WHEN USING THE LOCAL DEVELOPMENT SUITE.
* Requests will be FAR TOO LARGE for the deployed app
*/
public static void updateDatastoreLocal(){
//Create Queue and menus
Queue queue = QueueFactory.getDefaultQueue();
ArrayList<MealMenu> menus;
UCSBJMenuScraper scraper;
for(int menuCode=11;menuCode<=42;menuCode++){
System.out.println(menuCode);
scraper = new UCSBJMenuScraper(new RemoteUCSBMenuFile(getCommonsURL(menuCode)));
menus = scraper.getMenus();
updateDatastoreHelper(0, menus.size(), menus);
if(menuCode%2==0)menuCode+=8;
}
}
/**
* Method to be used ONLY ON DEPLOYED APPLICATION.
* Local suit does NOT support the Task Queue!
* Method deletes all menus that are over a month old. Corresponding FoodItems are left in the datastore.
*/
public static void deleteOldMealMenus(){
DatastoreService service = DatastoreServiceFactory.getDatastoreService();
AnnotationObjectDatastore datastore = new AnnotationObjectDatastore(service);
Iterator<MealMenu> toDelete = datastore.find().type(MealMenu.class)
.addFilter("endMillis",FilterOperator.LESS_THAN_OR_EQUAL, (new DateTime().minusMonths(1)).getMillis())
.fetchResultsBy(5).returnResultsNow();
boolean doMore = toDelete.hasNext();
while(toDelete.hasNext()){
datastore.delete(toDelete.next());
}
Queue queue = QueueFactory.getDefaultQueue();
if(doMore) queue.add(TaskOptions.Builder.url("/cron/deleteOldMenus.jsp"));
}
/**
* Method to be used ONLY ON DEPLOYED SERVERS
* Local suite does NOT support the Task Queue!<br>
* Updates the datastore with the latest information from the web
* Only updates 5 menus at a time, and then hands off remainder of the work to Task Queue
* @param iteration represents where in the currently parsed file to start adding to the datastore
* @param menuCode two digit number that determines which menu we are pulling from.
* The second digit represents either this weeks menus (1) or next week's (2).
* The first digit represents the dining common: 1=Carrillo, 2=DLG, 3=Ortega, 4=Portola
* For example, a menuCode of 32 would represent Ortega's menu for next week.
*/
public static void updateDatastore(int iteration, int menuCode){
//Create Queue and menus
Queue queue = QueueFactory.getDefaultQueue();
ArrayList<MealMenu> menus;
UCSBJMenuScraper scraper = new UCSBJMenuScraper(new RemoteUCSBMenuFile(getCommonsURL(menuCode)));
menus = scraper.getMenus();
if(iteration<menus.size()){
iteration+=5;
if(iteration<menus.size()) queue.add(TaskOptions.Builder.url("/cron/update.jsp")
.param("count", ""+iteration).param("menu",""+menuCode));
updateDatastoreHelper(iteration-5, iteration, menus);
}
}
/**
* @param start start position in the arraylist passed in
* @param stop stop position in the arraylist passed in
* @param menus arraylist of meal menus to be added to the datastore
*/
private static void updateDatastoreHelper(int start, int stop, ArrayList<MealMenu> menus){
DatastoreService service = DatastoreServiceFactory.getDatastoreService();
AnnotationObjectDatastore datastore = new AnnotationObjectDatastore(service);
List<Future<Key>> keys = new LinkedList<Future<Key>>();
for(int o = start;o<stop&&o<menus.size();o++){
MealMenu tmp = datastore.load(MealMenu.class,menus.get(o).getMenuKey());
if(tmp!=null){
if(menus.get(0).getModDate().getMillis()>tmp.getModDate().getMillis()){
datastore.delete(tmp);
keys.add(datastore.store().instance(menus.get(0)).returnKeyLater());
}
} else{
keys.add(datastore.store().instance(menus.get(o)).returnKeyLater());
}
// datastore.store().instance().returnKeyNow();
}
for(Future<Key> key:keys){
try {
key.get();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
/**
* TO BE USED ON DEPLOYED SERVERS ONLY. WILL NOT WORK ON LOCAL SERVERS AS TASK QUEUE ISN'T IMPLEMENTED
* @param mode 0 to clear meal menus, 1 to clear food items.
*/
public static void clearAll(int mode){
Queue queue = QueueFactory.getDefaultQueue();
DatastoreService service = DatastoreServiceFactory.getDatastoreService();
AnnotationObjectDatastore datastore = new AnnotationObjectDatastore(service);
boolean shouldContinue = false;
switch(mode){
case 0:
{
Iterator<MealMenu> it = datastore.find().type(MealMenu.class).fetchResultsBy(5).returnResultsNow();
if(it.hasNext()) shouldContinue=true;
MealMenu mm;
int count = 0;
while(it.hasNext() && count<5){
mm = it.next();
datastore.delete(mm);
count++;
}
}
break;
case 1:
{
Iterator<FoodItem> it = datastore.find().type(FoodItem.class).fetchResultsBy(20).returnResultsNow();
if(it.hasNext()) shouldContinue=true;
int count = 0;
while(it.hasNext()&&count<20){
datastore.delete(it.next());
count++;
}
}
break;
}
if(shouldContinue) queue.add(TaskOptions.Builder.url("/cron/clear.jsp").param("count",""+mode));
}
private static String getCommonsURL(int menuCode){
switch(menuCode){
case 11:
return RemoteUCSBMenuFile.CARRILLO_THIS_WEEK;
case 12:
return RemoteUCSBMenuFile.CARRILLO_NEXT_WEEK;
case 21:
return RemoteUCSBMenuFile.DLG_THIS_WEEK;
case 22:
return RemoteUCSBMenuFile.DLG_NEXT_WEEK;
case 31:
return RemoteUCSBMenuFile.ORTEGA_THIS_WEEK;
case 32:
return RemoteUCSBMenuFile.ORTEGA_NEXT_WEEK;
case 41:
return RemoteUCSBMenuFile.PORTOLA_THIS_WEEK;
case 42:
return RemoteUCSBMenuFile.PORTOLA_NEXT_WEEK;
default:
return RemoteUCSBMenuFile.CARRILLO_THIS_WEEK;
}
}
}