package ca.ualberta.cs.team5geotopics;
import java.util.ArrayList;
import android.content.Context;
import android.graphics.Bitmap;
import android.util.Log;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
/**
* Cache is what is responsible for saving and loading data to and from the
* user's device. This file is the 'history' of the program.
*/
public class Cache extends AModel<AView> {
private CacheIO cacheIO;
private Context context;
private GeoTopicsApplication application;
boolean isLoaded;
private static Cache myself;
/**
* Cache constructor. Will load its necessary files from disk.
*
* @return A cache object
*/
private Cache() {
this.application = GeoTopicsApplication.getInstance();
context = application.getContext();
try {
cacheIO = new CacheIO(context.getFilesDir().getAbsolutePath());
} catch (NullPointerException e) {
// just go on. This is Null in the test
}
isLoaded = false;
}
public CacheIO getCacheIO(){
return this.cacheIO;
}
/**
* Returns the cache singleton. Only one cache object can exist at once.
* Will construct a new one if one does not currently exist.
*
* @return The cache
*/
public static Cache getInstance() {
if (myself == null)
myself = new Cache();
return myself;
}
/**
* Loads the file directory list from disk for the cache.
*
*/
public void loadFileList() {
cacheIO.loadFileList();
}
/**
* Used to determine if any replies are currently cached at the file
* location.
*
* @param filename
* The location on disk to search for replies
* @return True if replies exist at said location.
*/
public boolean repliesExist(String filename) {
// returns true if there are replies in the cache
if (!filename.equals("-1")) {
return this.cacheIO.getFileDir().contains(filename);
} else {
return this.cacheIO.getFileDir().contains("history.sav");
}
}
/**
* This will search the cache and return the requested comment. The EsID of
* the parent is necessary as we catalogue comments based on their parent ID
* and thus we need this to find the location in the file system to look.
* Will return null if we cannot find the comment in the cache.
*
* @param mParent
* The EsID of the parent Comment.
* @param EsID
* The EsID of the comment we want.
* @return The comment we requested from the cache, null if not found.
*/
public CommentModel loadComment(String mParentID, String EsID) {
ArrayList<CommentModel> commentList;
cacheIO.loadFileList();
if (this.repliesExist(mParentID)) {
if (mParentID.equals("-1")) {
commentList = this.cacheIO.load("history.sav");
} else {
commentList = this.cacheIO.load(mParentID);
}
for (CommentModel comment : commentList) {
if (comment.getmEsID().equals(EsID)) {
return comment;
}
}
}
return null;
}
/**
* Updates the cache with a whole list of comments. This update assumes that
* the list of comments all have the SAME parent and that a version of the
* list exists in the cache.
*
* @param updatedList
* Updated list of comments
*/
public void updateCache(ArrayList<CommentModel> updatedList, String mParentID) {
ArrayList<CommentModel> commentList;
if (this.repliesExist(mParentID)) {
Log.w("Cache", "Parent Exists");
if (mParentID.equals("-1")) {
Log.w("Cache", "Updating with a top level");
commentList = this.cacheIO.load("history.sav");
} else {
Log.w("Cache", "Updating with a reply level");
commentList = this.cacheIO.load(mParentID);
}
for (CommentModel comment : updatedList) {
findAndReplace(commentList, comment);
}
}else{
commentList = new ArrayList<CommentModel>();
commentList.addAll(updatedList);
}
writeListToCache(commentList, mParentID);
}
/**
* Takes in a list of comments and searches it for a comment withe the same
* ID in the list. If we find one then we replace the list version with the
* supplied version. If we do not find it then we add it to the end.
*
* @param commentList
* The list we are searching
* @param comment
* Version of the comment we want to replace in the list
*/
public void findAndReplace(ArrayList<CommentModel> commentList,
CommentModel comment) {
int i;
String EsID = comment.getmEsID();
boolean findFlag = false;
for (i = 0; i < commentList.size(); i++) {
if (commentList.get(i).getmEsID().equals(EsID)) {
// We found a copy of it so lets replace it and
// flag that we found it.
commentList.set(i, comment);
findFlag = true;
Log.w("Cache", "Found a copy of it");
break;
}
}
// We did not find a copy of this comment
// in its parents folder. Add it to the list then
if (!findFlag) {
Log.w("Cache", "Did not find a copy of the comment");
commentList.add(comment);
}
}
/**
* Will take a comment and either update a current version of it or add it
* to the cache.
*
* @param comment
* The comment to add/update in the cache
*/
public void updateCache(CommentModel comment) {
ArrayList<CommentModel> commentList;
String mParentID = comment.getmParentID();
cacheIO.loadFileList();
Log.w("Cache", "Updating cache");
// If the parent folder exists search it
if (this.repliesExist(mParentID)) {
Log.w("Cache", "Parent Exists");
if (mParentID.equals("-1")) {
Log.w("Cache", "Updating with a top level");
commentList = this.cacheIO.load("history.sav");
} else {
Log.w("Cache", "Updating with a reply level");
commentList = this.cacheIO.load(mParentID);
}
this.findAndReplace(commentList, comment);
} else {
// There was not folder for the parent so we
// Create a new empty list and add the comment to it.
Log.w("Cache", "No parent folder");
commentList = new ArrayList<CommentModel>();
commentList.add(comment);
}
writeListToCache(commentList, mParentID);
}
/**
* Takes a list of comment models and determines where to write them to disk (cache).
* This is determined using the supplied parent ID
* @param commentList The list to write to the cache
* @param mParentID The ID of the parent to all the comments in the list
*/
public void writeListToCache(ArrayList<CommentModel> commentList, String mParentID){
if (mParentID.equals("-1")) {
Log.w("Cache", "Write top level");
serializeAndWrite(commentList, "history.sav");
} else {
Log.w("Cache", "Write parent level: " + mParentID);
serializeAndWrite(commentList, mParentID);
}
}
/**
* This will serialize the array list using JSON then write it to the
* appropriate place on disk.
*
* @param commentList
* The list to serialise and write to disk
* @param filename
* The file to save the list too
*/
public void serializeAndWrite(ArrayList<CommentModel> commentList,
String filename) {
Gson gson = new Gson();
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(Bitmap.class, new BitmapJsonConverter());
gson = builder.create();
cacheIO.replaceFileHistory(gson.toJson(commentList), filename);
}
/**
* Loads from the cache at the given filename location. Puts the results
* into the comment list model supplied.T he file name is the EsID of the
* parent comment for which you are looking for the list of replies. If we
* are looking for top levels then supply filename as null.
*
* @param filename
* The location to read.
* @param clm
* The comment list model we need to populate.
*/
public void loadFromCache(String filename, CommentListModel clm) {
ArrayList<CommentModel> commentList;
if (!filename.equals("-1")) {
commentList = this.cacheIO.load(filename);
} else {
commentList = this.cacheIO.load("history.sav");
}
clm.addNew(commentList);
}
}