package com.fourtails.usuariolecturista.jobs;
import android.text.format.Time;
import com.activeandroid.ActiveAndroid;
import com.activeandroid.query.Delete;
import com.activeandroid.query.Select;
import com.appspot.ocr_backend.backend.Backend;
import com.appspot.ocr_backend.backend.model.MessagesGetReadings;
import com.appspot.ocr_backend.backend.model.MessagesGetReadingsResponse;
import com.appspot.ocr_backend.backend.model.MessagesReading;
import com.fourtails.usuariolecturista.MainActivity;
import com.fourtails.usuariolecturista.model.ChartReading;
import com.fourtails.usuariolecturista.ottoEvents.BackendObjectsEvent;
import com.google.api.client.extensions.android.http.AndroidHttp;
import com.google.api.client.extensions.android.json.AndroidJsonFactory;
import com.orhanobut.logger.Logger;
import com.path.android.jobqueue.Job;
import com.path.android.jobqueue.Params;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import static com.fourtails.usuariolecturista.ottoEvents.BackendObjectsEvent.Status;
import static com.fourtails.usuariolecturista.ottoEvents.BackendObjectsEvent.Type;
/**
* Get readings async job
*/
public class GetReadingsJob extends Job {
boolean responseOk = false;
boolean retry = true;
String accountNumber;
public GetReadingsJob(String accountNumber) {
super(new Params(Priority.MID).requireNetwork().groupBy("get-readings"));
this.accountNumber = accountNumber;
}
@Override
public void onAdded() {
}
/**
* TODO: ask for a period of time on the backend, we can't just go and get all the readings ever
*
* @throws Throwable
*/
@Override
public void onRun() throws Throwable {
// Use a builder to help formulate the API request.
Backend.Builder builder = new Backend.Builder(AndroidHttp.newCompatibleTransport(), new AndroidJsonFactory(), null);
Backend service = builder.build();
MessagesGetReadings messagesGetReadings = new MessagesGetReadings();
messagesGetReadings.setAccountNumber(accountNumber);
MessagesGetReadingsResponse response = service.reading().get(messagesGetReadings).execute();
if (response.getOk()) {
List<MessagesReading> readingsArray = response.getReadings();
eraseReadingsDataFromLocalDB();
populateDBWithReadings(readingsArray);
Logger.json(response.toPrettyString());
responseOk = true;
} else {
responseOk = false;
if (response.getError().contains("no readings found")) {
Logger.d(response.getError());
retry = true;
} else {
Logger.e(response.getError());
}
}
// Go back to main activity and call the rest of the backend tasks
MainActivity.bus.post(new BackendObjectsEvent(Type.READING, Status.NORMAL));
}
/**
* Database erase
* Erases the db so we don't have to check if the reading already exists and don't put duplicates
*/
private void eraseReadingsDataFromLocalDB() {
List<ChartReading> tempList = new Select().from(ChartReading.class).execute();
if (tempList != null && tempList.size() > 0) {
// we need the time of the last value to help us render the new values differently
ChartReading lastListValue = tempList.get(tempList.size() - 1);
MainActivity.oldReadingsLastDateInMillis = lastListValue.timeInMillis;
ActiveAndroid.beginTransaction();
try {
new Delete().from(ChartReading.class).execute();
ActiveAndroid.setTransactionSuccessful();
} catch (Exception e) {
Logger.e(e, "error deleting existing db");
} finally {
ActiveAndroid.endTransaction();
}
}
}
/**
* Database save
* This will attempt to save the readings from the backend to the
*
* @param readingsArray they array from the backend
*/
private void populateDBWithReadings(List<MessagesReading> readingsArray) {
Time time = new Time();
ActiveAndroid.beginTransaction();
try {
// values come unsorted, and we sort them by date
Collections.sort(readingsArray, new ReadingsCompare());
for (MessagesReading readings : readingsArray) {
long timeInMillis = readings.getCreationDate().getValue();
time.set(timeInMillis);
ChartReading chartReading = new ChartReading(
time.monthDay,
time.month,
time.year,
timeInMillis,
readings.getMeasure(),
readings.getUrlsafeKey(),
readings.getAccountNumber());
chartReading.save();
}
ActiveAndroid.setTransactionSuccessful();
} catch (Exception e) {
Logger.e(e, "there was an error saving to the database, most likely the data doesn't have" +
"the needed fields from the database or they are null");
} finally {
ActiveAndroid.endTransaction();
}
}
/**
* I don't like inner classes but this is too small for its own file, it just compares 2 values
*/
class ReadingsCompare implements Comparator<MessagesReading> {
@Override
public int compare(MessagesReading lhs, MessagesReading rhs) {
Long value1 = lhs.getCreationDate().getValue();
Long values2 = rhs.getCreationDate().getValue();
return value1.compareTo(values2);
}
}
@Override
protected void onCancel() {
Logger.d("ReadingsJob canceled");
MainActivity.bus.post(new BackendObjectsEvent(Type.READING, Status.ERROR));
}
@Override
protected boolean shouldReRunOnThrowable(Throwable throwable) {
return retry;
}
}