package com.codegy.aerlink.services.aerlink.reminders;
import android.bluetooth.BluetoothGattCharacteristic;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.util.Log;
import com.codegy.aerlink.services.aerlink.ALSConstants;
import com.codegy.aerlink.Constants;
import com.codegy.aerlink.connection.command.Command;
import com.codegy.aerlink.utils.PacketProcessor;
import com.codegy.aerlink.utils.ServiceHandler;
import com.codegy.aerlink.utils.ServiceUtils;
import org.json.JSONArray;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
/**
* Created by Guiye on 20/5/15.
*/
public class ReminderServiceHandler extends ServiceHandler {
public interface CalendarsCallback {
void onDataTransferStarted();
void onCalendarsUpdated(List<ReminderCalendar> calendars);
}
public interface RemindersCallback {
void onDataTransferStarted();
void onRemindersUpdated(List<ReminderItem> reminders);
}
private static final String LOG_TAG = ReminderServiceHandler.class.getSimpleName();
private Context mContext;
private ServiceUtils mServiceUtils;
private CalendarsCallback calendarsCallback;
private RemindersCallback remindersCallback;
private PacketProcessor mPacketProcessor;
public ReminderServiceHandler(Context context, ServiceUtils serviceUtils) {
this.mContext = context;
this.mServiceUtils = serviceUtils;
}
public void setSelectedCalendar(ReminderCalendar calendar) {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext);
sp.edit().putString(Constants.SPK_REMINDER_SELECTED_CALENDAR, calendar.getIdentifier()).apply();
}
public void requestCalendarsUpdate(boolean forceUpdate, Runnable failure) {
if (!forceUpdate) {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext);
String cacheData = sp.getString(Constants.SPK_REMINDER_CALENDARS_DATA, null);
if (cacheData == null) {
// Force update
forceUpdate = true;
}
}
byte forceUpdateByte = (byte)(forceUpdate ? 0x01 : 0x00);
Command reminderCommand = new Command(ALSConstants.SERVICE_UUID, ALSConstants.CHARACTERISTIC_REMINDERS_ACTION, new byte[] {
(byte) 0x01,
forceUpdateByte
});
reminderCommand.setFailureBlock(failure);
mServiceUtils.addCommandToQueue(reminderCommand);
}
public void requestRemindersUpdate(boolean forceUpdate, Runnable failure) {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext);
String selectedCalendar = sp.getString(Constants.SPK_REMINDER_SELECTED_CALENDAR, null);
if (selectedCalendar == null) {
// Error
return;
}
if (!forceUpdate) {
String cacheData = sp.getString(Constants.SPK_REMINDER_ITEMS_DATA + selectedCalendar, null);
if (cacheData == null) {
// Force update
forceUpdate = true;
}
}
char forceUpdateByte = (char)(forceUpdate ? 0x01 : 0x00);
String dataString = (char)0x02 + Character.toString(forceUpdateByte) + selectedCalendar;
Command reminderCommand = new Command(ALSConstants.SERVICE_UUID, ALSConstants.CHARACTERISTIC_REMINDERS_ACTION, dataString.getBytes());
reminderCommand.setFailureBlock(failure);
mServiceUtils.addCommandToQueue(reminderCommand);
}
public void setReminderCompleted(final ReminderItem reminderItem, Runnable success, Runnable failure) {
final char completed = (char)(reminderItem.isCompleted() ? 0x01 : 0x00);
String dataString = (char)0x03 + Character.toString(completed) + reminderItem.getIdentifier();
Command reminderCommand = new Command(ALSConstants.SERVICE_UUID, ALSConstants.CHARACTERISTIC_REMINDERS_ACTION, dataString.getBytes());
reminderCommand.setSuccessBlock(success);
reminderCommand.setFailureBlock(failure);
mServiceUtils.addCommandToQueue(reminderCommand);
}
public void updateCachedData(String calendarIdentifier, ReminderItem item) {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext);
String remindersData = sp.getString(Constants.SPK_REMINDER_ITEMS_DATA + calendarIdentifier, null);
if (remindersData != null) {
String identifier = ",\"i\":\"" + item.getIdentifier();
if (item.isCompleted()) {
remindersData = remindersData.replace("0"+identifier, "1"+identifier);
}
else {
remindersData = remindersData.replace("1"+identifier, "0"+identifier);
}
sp.edit().putString(Constants.SPK_REMINDER_ITEMS_DATA + calendarIdentifier, remindersData).apply();
}
}
public void setRemindersCallback(RemindersCallback remindersCallback) {
this.remindersCallback = remindersCallback;
}
public void setCalendarsCallback(CalendarsCallback calendarsCallback) {
this.calendarsCallback = calendarsCallback;
}
@Override
public void reset() {
mPacketProcessor = null;
}
@Override
public UUID getServiceUUID() {
return ALSConstants.SERVICE_UUID;
}
@Override
public List<String> getCharacteristicsToSubscribe() {
List<String> characteristics = new ArrayList<>();
characteristics.add(ALSConstants.CHARACTERISTIC_REMINDERS_DATA);
return characteristics;
}
@Override
public boolean canHandleCharacteristic(BluetoothGattCharacteristic characteristic) {
String characteristicUUID = characteristic.getUuid().toString().toLowerCase();
return characteristicUUID.equals(ALSConstants.CHARACTERISTIC_REMINDERS_DATA);
}
@Override
public void handleCharacteristic(BluetoothGattCharacteristic characteristic) {
byte[] packet = characteristic.getValue();
if (mPacketProcessor == null) {
mPacketProcessor = new PacketProcessor(packet);
if (!mPacketProcessor.isFinished()) {
switch (mPacketProcessor.getAction()) {
case 0x01:
if (calendarsCallback != null) {
calendarsCallback.onDataTransferStarted();
}
break;
case 0x02:
if (remindersCallback != null) {
remindersCallback.onDataTransferStarted();
}
break;
}
}
}
else {
mPacketProcessor.process(packet);
}
if (mPacketProcessor == null || !mPacketProcessor.isFinished()) {
return;
}
switch (mPacketProcessor.getAction()) {
case 0x01:
processCalendarsData(mPacketProcessor);
break;
case 0x02:
processRemindersData(mPacketProcessor);
break;
}
mPacketProcessor = null;
}
private void processCalendarsData(PacketProcessor packetProcessor) {
switch (packetProcessor.getStatus()) {
case 0x00:
Log.i(LOG_TAG, "Error with calendar data");
// Error
break;
case 0x01:
Log.i(LOG_TAG, "Calendar regular update");
// Regular update
String calendarsData = packetProcessor.getStringValue();
if (calendarsData != null) {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext);
sp.edit().putString(Constants.SPK_REMINDER_CALENDARS_DATA, calendarsData).apply();
if (calendarsCallback != null) {
convertCalendarsData(calendarsData);
}
}
break;
case 0x02:
Log.i(LOG_TAG, "Calendar cache update");
// No update needed, cache is valid
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext);
String cacheData = sp.getString(Constants.SPK_REMINDER_CALENDARS_DATA, null);
if (cacheData == null) {
// Force update
Log.i(LOG_TAG, "Calendar cache update failed, forcing update");
requestCalendarsUpdate(true, null);
}
else if (calendarsCallback != null) {
convertCalendarsData(cacheData);
}
}
}
private void convertCalendarsData(String calendarsData) {
try {
JSONArray jsonItems = new JSONArray(calendarsData);
List<ReminderCalendar> calendars = new ArrayList<>(jsonItems.length());
for (int i = 0; i < jsonItems.length(); i++) {
ReminderCalendar calendar = new ReminderCalendar(jsonItems.getJSONObject(i).get("t").toString(), jsonItems.getJSONObject(i).get("i").toString(), jsonItems.getJSONObject(i).get("c").toString());
calendars.add(calendar);
}
if (calendarsCallback != null) {
calendarsCallback.onCalendarsUpdated(calendars);
}
}
catch (Exception e) {
e.printStackTrace();
if (calendarsCallback != null) {
calendarsCallback.onCalendarsUpdated(null);
}
}
}
private void processRemindersData(PacketProcessor packetProcessor) {
switch (packetProcessor.getStatus()) {
case 0x00:
// Error
break;
case 0x01: {
// Regular update
String remindersData = packetProcessor.getStringValue();
if (remindersData != null) {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext);
String selectedCalendar = sp.getString(Constants.SPK_REMINDER_SELECTED_CALENDAR, null);
if (selectedCalendar == null) {
// Error
return;
}
sp.edit().putString(Constants.SPK_REMINDER_ITEMS_DATA + selectedCalendar, remindersData).apply();
if (remindersCallback != null) {
convertRemindersData(remindersData, selectedCalendar);
}
}
break;
}
case 0x02: {
// No update needed, cache is valid
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext);
String selectedCalendar = sp.getString(Constants.SPK_REMINDER_SELECTED_CALENDAR, null);
if (selectedCalendar == null) {
// Error
return;
}
String cacheData = sp.getString(Constants.SPK_REMINDER_ITEMS_DATA + selectedCalendar, null);
if (cacheData == null) {
// Force update
requestRemindersUpdate(true, null);
}
else if (remindersCallback != null) {
convertRemindersData(cacheData, selectedCalendar);
}
}
}
}
private void convertRemindersData(String remindersData, String selectedCalendar) {
try {
JSONArray jsonItems = new JSONArray(remindersData);
String calendarIdentifier = jsonItems.getJSONObject(0).getString("i");
if (calendarIdentifier.equals(selectedCalendar)) {
return;
}
List<ReminderItem> items = new ArrayList<>(jsonItems.length());
int uncompleted = 0;
for (int i = 1; i < jsonItems.length(); i++) {
ReminderItem item = new ReminderItem(jsonItems.getJSONObject(i).getInt("c"), jsonItems.getJSONObject(i).getString("t"), jsonItems.getJSONObject(i).getString("i"));
if (item.isCompleted()) {
items.add(item);
}
else {
items.add(uncompleted, item);
uncompleted++;
}
}
if (remindersCallback != null) {
remindersCallback.onRemindersUpdated(items);
}
}
catch (Exception e) {
e.printStackTrace();
if (remindersCallback != null) {
remindersCallback.onRemindersUpdated(null);
}
}
}
}