com.master.aluca.fitnessmd.common.webserver.WebserverManager.java Source code

Java tutorial

Introduction

Here is the source code for com.master.aluca.fitnessmd.common.webserver.WebserverManager.java

Source

/*********************************************************
 *
 * Copyright (c) 2017 Andrei Luca
 * All rights reserved. You may not copy, distribute, publicly display,
 * create derivative works from or otherwise use or modify this
 * software without first obtaining a license from Andrei Luca
 *
 *********************************************************/

package com.master.aluca.fitnessmd.common.webserver;

import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
import android.widget.EditText;
import android.widget.Toast;

import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.master.aluca.fitnessmd.R;
import com.master.aluca.fitnessmd.common.Constants;
import com.master.aluca.fitnessmd.common.datatypes.AdviceDetails;
import com.master.aluca.fitnessmd.common.datatypes.ChallengeDetails;
import com.master.aluca.fitnessmd.common.datatypes.User;
import com.master.aluca.fitnessmd.common.util.IStatsChanged;
import com.master.aluca.fitnessmd.common.util.UsersDB;
import com.master.aluca.fitnessmd.library.FitnessMDMeteor;
import com.master.aluca.fitnessmd.library.MeteorCallback;
import com.master.aluca.fitnessmd.library.db.memory.InMemoryCollection;
import com.master.aluca.fitnessmd.library.db.memory.InMemoryDocument;
import com.master.aluca.fitnessmd.library.listeners.ResultListener;
import com.master.aluca.fitnessmd.library.listeners.SubscribeListener;
import com.master.aluca.fitnessmd.library.listeners.UnsubscribeListener;
import com.master.aluca.fitnessmd.ui.AdvicesActivity;
import com.master.aluca.fitnessmd.ui.auth.AuthenticationLogic;
import com.master.aluca.fitnessmd.ui.challenges.ChallengesActivity;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;

public class WebserverManager implements MeteorCallback {
    private static final String LOG_TAG = "Fitness_WebserverMgr";
    AuthenticationLogic mAuthLogicInstance;

    private Context mContext;

    private AtomicBoolean isMeteorClientConnected = new AtomicBoolean(false);

    private static WebserverManager sWebserverManager = null;

    private ArrayList<Handler> handlerList = new ArrayList<>();
    private ArrayList<IStatsChanged> statsCallbackList = new ArrayList<>();

    private UsersDB mDB;
    private static String userLoggingInEmail;
    private boolean successfullySubscribedToChallenges = false;
    private boolean successfullySubscribedToAdvices = false;

    LinkedHashMap<Long, Integer> savedStats = new LinkedHashMap<>();

    public static WebserverManager getInstance(Context context) {
        Log.d(LOG_TAG, "WebserverManager getInstance :" + String.valueOf(sWebserverManager));
        if (sWebserverManager == null) {
            sWebserverManager = new WebserverManager(context);
        }
        return sWebserverManager;
    }

    private WebserverManager(Context context) {
        Log.d(LOG_TAG, "private WebserverManager");
        mAuthLogicInstance = AuthenticationLogic.getInstance();
        mContext = context;
        mDB = UsersDB.getInstance(context);

        // create a new instance
        FitnessMDMeteor.createInstance(context, "ws://192.168.X.X:3000/websocket");
        // register the callback that will handle events and receive messages
        FitnessMDMeteor.getInstance().addCallback(this);

        // establish the connection
        Log.d(LOG_TAG,
                "FitnessMDMeteor.getInstance().isConnected() : " + FitnessMDMeteor.getInstance().isConnected());
        if (!FitnessMDMeteor.getInstance().isConnected()) {
            Log.d(LOG_TAG, "FitnessMDMeteor connect");
            FitnessMDMeteor.getInstance().connect();
        }
    }

    public void requestLogin(final EditText emailText, final EditText passwordText) {
        Log.d(LOG_TAG, "requestLogin");
        if (!mAuthLogicInstance.isInputValid(null, emailText, passwordText)) {
            Log.d(LOG_TAG, "Login failed");
            dispatchMessageToHandlers(Constants.LOGIN_RESULT_INTENT, false, "Input is not valid");
        } else {
            final String email = emailText.getText().toString();
            String password = passwordText.getText().toString();

            boolean isEmailRegistered = mDB.isEmailRegistered(email);
            if (isEmailRegistered) {
                String hashedPassword = Constants.getHashedPassword(password);
                boolean isPasswordCorrect = mDB.isPasswordCorrect(email, hashedPassword);
                if (isPasswordCorrect) {

                    Log.d(LOG_TAG, "try to connect to web server");
                    if (FitnessMDMeteor.getInstance().isConnected()) {
                        Log.d(LOG_TAG, "FitnessMDMeteor.getInstance().isConnected()");
                        if (!FitnessMDMeteor.getInstance().isLoggedIn()) {
                            doLogin(email, password);
                        } else {
                            mDB.setUserConnected(email, true);
                            dispatchMessageToHandlers(Constants.LOGIN_RESULT_INTENT, true,
                                    "Log in successful, already logged in on server");
                        }
                    } else {
                        Log.d(LOG_TAG, "FitnessMDMeteor.getInstance().isConnected() false");
                        dispatchMessageToHandlers(Constants.LOGIN_RESULT_INTENT, false,
                                "Server is not up and running");
                    }
                } else {
                    dispatchMessageToHandlers(Constants.LOGIN_RESULT_INTENT, false, "Password not correct");
                }
            } else {
                dispatchMessageToHandlers(Constants.LOGIN_RESULT_INTENT, false, "Email not registered");
            }
        }
    }

    public void requestSignup(final EditText nameText, final EditText emailText, final EditText passwordText) {
        Log.d(LOG_TAG, "requestSignup");
        if (!mAuthLogicInstance.isInputValid(nameText, emailText, passwordText)) {
            Log.d(LOG_TAG, "input not valid");
            dispatchMessageToHandlers(Constants.SIGNUP_RESULT_INTENT, false, "Input is not valid");
        } else {
            if (FitnessMDMeteor.getInstance().isConnected()) {
                String name = nameText.getText().toString();
                String email = emailText.getText().toString();
                String hashedPassword = Constants.getHashedPassword(passwordText.getText().toString());

                boolean isEmailRegistered = mDB.isEmailRegistered(email);
                if (!isEmailRegistered) {
                    boolean addSuccess = mDB.addUser(name, email, hashedPassword);
                    if (addSuccess) {
                        Log.d(LOG_TAG, "addSuccess : " + addSuccess);
                        // connect only if the webserver is up and running
                        Log.d(LOG_TAG, "try to connect to web server");

                        Log.d(LOG_TAG, "Meteor client connected");
                        doSignup(name, email, hashedPassword);
                    } else {
                        dispatchMessageToHandlers(Constants.SIGNUP_RESULT_INTENT, false, "Could not add user");
                    }
                } else {
                    dispatchMessageToHandlers(Constants.SIGNUP_RESULT_INTENT, false, "Email already registered");
                }
            } else {
                dispatchMessageToHandlers(Constants.SIGNUP_RESULT_INTENT, false, "Server is not up and running");
            }
        }
    }

    private void doLogin(final String email, String normalPassword) {
        Log.d(LOG_TAG, "doLogin : " + normalPassword);
        userLoggingInEmail = email;
        FitnessMDMeteor.getInstance().loginWithEmail(email, normalPassword, new ResultListener() {
            @Override
            public void onSuccess(String s) {
                Log.d(LOG_TAG, "Meteor Login SUCCESS : " + s);
                mDB.setUserConnected(email, true);
                dispatchMessageToHandlers(Constants.LOGIN_RESULT_INTENT, true,
                        "Login successfully + server success");
            }

            @Override
            public void onError(String error, String reason, String details) {
                Log.d(LOG_TAG, "Meteor Login ERROR");
                dispatchMessageToHandlers(Constants.LOGIN_RESULT_INTENT, false, reason);
            }
        });
    }

    private void doSignup(String name, final String email, String hashedPassword) {
        Log.d(LOG_TAG, "doSignup");
        userLoggingInEmail = email;
        FitnessMDMeteor.getInstance().registerAndLogin(name, email, hashedPassword, new ResultListener() {
            @Override
            public void onSuccess(String s) {
                Log.d(LOG_TAG, "Meteor Login after Signup SUCCESS");
                mDB.setUserConnected(email, true);
                dispatchMessageToHandlers(Constants.SIGNUP_RESULT_INTENT, true, "Signup successfully");
            }

            @Override
            public void onError(String error, String reason, String details) {
                Log.d(LOG_TAG, "Meteor Login after signup ERROR");
                Log.d(LOG_TAG, "error : " + error + " >>> reason : " + reason + " >>> details : " + details);
                dispatchMessageToHandlers(Constants.SIGNUP_RESULT_INTENT, false, reason);
            }
        });
    }

    public void requestLogout() {
        Log.d(LOG_TAG, "requestLogout");
        final User connectedUser = mDB.getConnectedUser();
        if (connectedUser != null) {
            Log.d(LOG_TAG, "try to connect to web server");
            if (FitnessMDMeteor.getInstance().isConnected()) {
                Log.d(LOG_TAG, "Meteor client connected");
                if (FitnessMDMeteor.getInstance().isLoggedIn()) {
                    Log.d(LOG_TAG, "Meteor user already logged in. Logging out ...");
                    FitnessMDMeteor.getInstance().logout(new ResultListener() {
                        @Override
                        public void onSuccess(String result) {
                            Log.d(LOG_TAG, "requestLogout onSuccess");
                            if (mDB.setUserConnected(connectedUser.getEmail(), false)) {
                                Intent intentFinishActivity = new Intent(Constants.FINISH_ACTIVITY_INTENT);
                                intentFinishActivity.putExtra(Constants.FINISH_ACTIVITY_BUNDLE_KEY, false);
                                mContext.sendBroadcast(intentFinishActivity);
                            }
                        }

                        @Override
                        public void onError(String error, String reason, String details) {
                            Log.d(LOG_TAG, "requestLogout onError");
                            Toast.makeText(mContext, reason, Toast.LENGTH_LONG).show();
                        }
                    });
                } else {
                    Log.d(LOG_TAG, "Meteor user NOT logged in");
                    /* somehow the user is still connected in the app although it's not connected to the server
                     force finish the activity and disconnect user
                     ?????????? */
                }
            } else {
                Log.d(LOG_TAG, "Meteor not connected. problem with server");
                /* the server is down
                   force finish the activity and disconnect user
                   ?????????? */
            }
            // no internet but still the user can click the logout button ?!?!?!?
            // force finish the activity and disconnect user
            // ??????????
            if (mDB.setUserConnected(connectedUser.getEmail(), false)) {
                Intent intentFinishActivity = new Intent(Constants.FINISH_ACTIVITY_INTENT);
                intentFinishActivity.putExtra(Constants.FINISH_ACTIVITY_BUNDLE_KEY, false);
                mContext.sendBroadcast(intentFinishActivity);
            }

        } else {
            Log.d(LOG_TAG, "user not even logged in. how did this call got here?");
        }
    }

    public boolean sendPedometerData(long day, int steps, long timeActive) {
        int Hours = (int) (timeActive / (1000 * 60 * 60));
        int Mins = (int) (timeActive / (1000 * 60)) % 60;
        String diffTimeActive = Hours + ":" + Mins;
        Log.d(LOG_TAG, "sendPedometerData day: " + (new Date(day)) + " >>> steps : " + steps + " >>> timeActive : "
                + diffTimeActive);
        boolean oRet = false;
        if (day < 1 || steps < 0)
            return oRet;
        oRet = true;
        Log.d(LOG_TAG, "put pedometer data success");
        Date date = new Date(day);
        Log.d(LOG_TAG, "date : " + date);
        return oRet;
    }

    @Override
    public void onConnect(boolean shouldSignIn) {
        Log.d(LOG_TAG, "Meteor DDP onConnect");
        isMeteorClientConnected.set(true);
        dispatchMessageToHandlers(Constants.METEOR_CLIENT_STATE, shouldSignIn);
        //subscribeToStats();
    }

    private void dispatchMessageToHandlers(int what, boolean b) {
        dispatchMessageToHandlers(what, b ? 1 : 0, 0, null);
    }

    private void dispatchMessageToHandlers(int what, boolean b, String reason) {
        dispatchMessageToHandlers(what, b ? 1 : 0, 0, reason);
    }

    private void dispatchMessageToHandlers(int what, int arg1, int arg2, Object obj) {

        Log.d(LOG_TAG, "dispatchMessageToHandlers handlerList.size : " + handlerList.size());
        if (handlerList.size() > 0) {
            for (Handler handler : handlerList) {
                if (handler != null) {
                    handler.obtainMessage(what, arg1, arg2, obj).sendToTarget();
                }
            }
        }
    }

    @Override
    public void onDisconnect() {
        Log.d(LOG_TAG, "Meteor DDP onDisconnect");
        dispatchMessageToHandlers(Constants.METEOR_CLIENT_STATE, false);
        requestLogout();
        /*mDB.setUserConnected(connectedUser.getEmail(), false)
        Intent intentFinishActivity = new Intent(Constants.FINISH_ACTIVITY_INTENT);
        intentFinishActivity.putExtra(Constants.FINISH_ACTIVITY_BUNDLE_KEY, true);
        mContext.sendBroadcast(intentFinishActivity);*/
    }

    @Override
    public void onException(Exception e) {
        Log.d(LOG_TAG, "Meteor DDP onException : ");
        e.printStackTrace();

    }

    @Override
    public void onDataAdded(String collectionName, String documentID, String fieldsJson) {
        Log.d(LOG_TAG, "Meteor DDP onDataAdded " + "Data added to <" + collectionName + "> in document <"
                + documentID + ">\n" + "    Added: " + fieldsJson);
        if (collectionName.equalsIgnoreCase("users")) {
            String[] userDocIds = FitnessMDMeteor.getInstance().getDatabase().getCollection(collectionName)
                    .getDocumentIds();
            Log.d(LOG_TAG, "userdocIds.length : " + userDocIds.length);
            for (int i = 0; i < userDocIds.length; i++) {
                InMemoryDocument userdoc = FitnessMDMeteor.getInstance().getDatabase().getCollection(collectionName)
                        .getDocument(userDocIds[i]);
                Log.d(LOG_TAG, "field emails : " + userdoc.getField("emails").toString());
                Gson gson = new Gson();
                String json = gson.toJson(userdoc.getField("emails"));
                JsonParser parser = new JsonParser();
                JsonElement element = parser.parse(json);
                JsonArray obj = element.getAsJsonArray();
                for (int t = 0; t < obj.size(); t++) {
                    JsonObject elem = obj.get(t).getAsJsonObject();
                    if (elem.has("address")
                            && elem.get("address").getAsString().equalsIgnoreCase(userLoggingInEmail)) {
                        mDB.updateUserID(userLoggingInEmail, documentID);
                    }
                }
            }
        } else if (collectionName.equalsIgnoreCase("challenges")) {
            Log.d(LOG_TAG, "successfullySubscribedToChallenges : " + successfullySubscribedToChallenges);
            if (successfullySubscribedToChallenges) {
                InMemoryDocument challengeDoc = FitnessMDMeteor.getInstance().getDatabase()
                        .getCollection(collectionName).getDocument(documentID);
                Intent sendChallenge = new Intent(Constants.NEW_CHALLENGE_INTENT);
                mContext.sendBroadcast(sendChallenge);
                Intent intent = new Intent(mContext, ChallengesActivity.class);
                intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
                PendingIntent pIntent = PendingIntent.getActivity(mContext, 0, intent,
                        PendingIntent.FLAG_UPDATE_CURRENT);
                NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(mContext);
                mBuilder.setSmallIcon(R.drawable.icon_sm);
                mBuilder.setContentTitle(
                        "New " + challengeDoc.getField(ChallengeDetails.TYPE).toString() + " challenge !");
                mBuilder.setContentText("Difficulty : " + challengeDoc.getField(ChallengeDetails.DIFFICULTY));
                mBuilder.setSubText("Description : " + challengeDoc.getField(ChallengeDetails.TEXT));
                mBuilder.addAction(R.drawable.icon_sm, "Take it", pIntent);
                mBuilder.setContentIntent(pIntent);
                mBuilder.setAutoCancel(true);
                NotificationManager mNotificationManager = (NotificationManager) mContext
                        .getSystemService(Context.NOTIFICATION_SERVICE);
                mNotificationManager.notify(0, mBuilder.build());
            }
        } else if (collectionName.equalsIgnoreCase("advices")) {
            Log.d(LOG_TAG, "successfullySubscribedToAdvices : " + successfullySubscribedToAdvices);
            if (successfullySubscribedToAdvices) {
                InMemoryDocument adviceDoc = FitnessMDMeteor.getInstance().getDatabase()
                        .getCollection(collectionName).getDocument(documentID);
                Intent sendAdvice = new Intent(Constants.NEW_ADVICE_INTENT);
                mContext.sendBroadcast(sendAdvice);
                Intent intent = new Intent(mContext, AdvicesActivity.class);
                intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
                PendingIntent pIntent = PendingIntent.getActivity(mContext, 0, intent,
                        PendingIntent.FLAG_UPDATE_CURRENT);
                NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(mContext);
                mBuilder.setSmallIcon(R.drawable.icon_sm);
                mBuilder.setContentTitle(
                        "Advice from " + adviceDoc.getField(AdviceDetails.OWNER).toString() + " !");
                mBuilder.setContentText(adviceDoc.getField(AdviceDetails.MESSAGE).toString());
                mBuilder.setSubText(adviceDoc.getField(AdviceDetails.TIMESTAMP).toString());
                mBuilder.setContentIntent(pIntent);
                mBuilder.setAutoCancel(true);
                NotificationManager mNotificationManager = (NotificationManager) mContext
                        .getSystemService(Context.NOTIFICATION_SERVICE);
                mNotificationManager.notify(0, mBuilder.build());
            }
        }
    }

    @Override
    public void onDataChanged(String collectionName, String documentID, String updatedValuesJson,
            String removedValuesJson) {
        Log.d(LOG_TAG,
                "Meteor DDP onDataChanged Data changed in <" + collectionName + "> in document <" + documentID
                        + "> \n" + "    Updated: " + updatedValuesJson + "\n    Removed: " + removedValuesJson);

        if (collectionName.equalsIgnoreCase("users")) {
            parseStatisticsData();
        }

    }

    private synchronized void parseStatisticsData() {
        if (mDB.getConnectedUser() != null) {
            InMemoryDocument userdoc = FitnessMDMeteor.getInstance().getDatabase().getCollection("users")
                    .getDocument(mDB.getConnectedUser().getDocId());
            if (userdoc != null) {
                Gson gson = new Gson();
                String json = gson.toJson(userdoc.getField("pedometerData"));
                if (json != null) {
                    JsonParser parser = new JsonParser();
                    JsonElement element = parser.parse(json);
                    JsonArray arr = element.getAsJsonArray();

                    LinkedHashMap<Long, Integer> map = new LinkedHashMap<>();
                    LinkedHashMap<Long, Integer> stats = new LinkedHashMap<>();
                    long startOfCurrentDay = Constants.getStartOfCurrentDay();
                    int totalSteps = 0;
                    long[] daysAgo = new long[7];

                    for (int k = 7; k >= 1; k--) {
                        daysAgo[k - 1] = startOfCurrentDay - (k * 24 * 60 * 60 * 1000);
                    }
                    // data is separated by hour index. concatenate data per day
                    //Log.d(LOG_TAG,"map.size : " + map.size() + " entrySet.size : " + map.entrySet().size());
                    for (int t = 0; t < arr.size(); t++) {
                        JsonObject elem = arr.get(t).getAsJsonObject();
                        JsonElement dayElement = elem.get("day");
                        if (dayElement != null) {
                            Integer stepsForDay = map.get(dayElement.getAsLong());
                            //Log.d(LOG_TAG,"day : " + dayElement.getAsLong() + " steps : " + elem.get("steps").getAsInt() + " stepsForDay : " + stepsForDay);
                            if (stepsForDay != null) {
                                int steps = map.get(elem.get("day").getAsLong());
                                steps += elem.get("steps").getAsInt();
                                map.put(elem.get("day").getAsLong(), steps);
                            } else {
                                map.put(elem.get("day").getAsLong(), elem.get("steps").getAsInt());
                            }
                        }
                        totalSteps += elem.get("steps").getAsInt();
                    }
                    int maxSteps = -1;
                    long dayForMaxSteps = -1;
                    AtomicBoolean valueInStatsChanged = new AtomicBoolean(false);
                    Log.d(LOG_TAG, "savedStats.entrySet.size : " + savedStats.entrySet().size());
                    for (Map.Entry<Long, Integer> entry : map.entrySet()) {

                        for (int l = 0; l < daysAgo.length; l++) {
                            //Log.d(LOG_TAG,entry.getKey() + " : " + entry.getValue() + " daysAgo : " + daysAgo[l]);
                            if (entry.getKey().longValue() == daysAgo[l]) {
                                if (savedStats.entrySet().size() == 0) {
                                    valueInStatsChanged.set(true);
                                }
                                if (savedStats.containsKey(entry.getKey())) {
                                    Log.d(LOG_TAG, entry.getKey() + " : " + entry.getValue() + " savedStats : "
                                            + savedStats.get(entry.getKey().longValue()));
                                    if (savedStats.get(entry.getKey().longValue()) != entry.getValue()
                                            .longValue()) {
                                        Log.d(LOG_TAG, "values not equal : " + entry.getValue() + " savedStats : "
                                                + savedStats.get(entry.getKey().longValue()));
                                        valueInStatsChanged.set(true);
                                    }
                                } else {
                                    savedStats.put(entry.getKey(), entry.getValue());
                                }
                                stats.put(entry.getKey(), entry.getValue());
                            }
                        }
                        if (entry.getValue() > maxSteps) {
                            maxSteps = entry.getValue();
                            dayForMaxSteps = entry.getKey();
                            mDB.updateBestSteps(entry.getKey(), entry.getValue());
                        }
                    }

                    for (IStatsChanged callback : statsCallbackList) {
                        callback.onTotalStepsChanged(totalSteps);
                        callback.onAverageStepsChanged(totalSteps / (arr.size() / 8));
                        callback.onMaxStepsChanged(dayForMaxSteps, maxSteps);
                        if (valueInStatsChanged.get()) {
                            Log.d(LOG_TAG, "stats values CHANGED");
                            callback.onLast7DaysStats(stats);
                        } else {
                            Log.d(LOG_TAG, "stats values not changed");
                        }
                    }
                }

            }

        }
    }

    @Override
    public void onDataRemoved(String collectionName, String documentID) {
        Log.d(LOG_TAG, "Meteor DDP onDataRemoved Data removed from <" + collectionName + "> in document <"
                + documentID + ">");

    }

    public void destroyMeteor() {
        Log.d(LOG_TAG, "destroyMeteor");
        FitnessMDMeteor.getInstance().unsubscribe("messages", new UnsubscribeListener() {
            @Override
            public void onSuccess() {
                Log.d(LOG_TAG, "unsubscribe onSuccess");
            }
        });
        FitnessMDMeteor.destroyInstance();
        sWebserverManager = null;
        savedStats.clear();
    }

    public void subscribeToStats() {
        if (mDB.getConnectedUser() != null) {
            Log.d(LOG_TAG, "subscribeToStats : " + mDB.getConnectedUser().getDocId());
            Map<String, String> insertMessage = new HashMap<String, String>();
            insertMessage.put("_id", mDB.getConnectedUser().getDocId());

            FitnessMDMeteor.getInstance().subscribe("userDataByUserId", new Object[] { insertMessage },
                    new SubscribeListener() {
                        @Override
                        public void onSuccess() {
                            Log.d(LOG_TAG, "onSuccess stats");
                            parseStatisticsData();
                        }

                        @Override
                        public void onError(String error, String reason, String details) {
                            Log.d(LOG_TAG,
                                    "onError subscriptionId : " + error + " >>> " + reason + " >>> " + details);
                        }
                    });
        }
    }

    public void subscribeToChallenges() {
        Log.d(LOG_TAG, "subscribeToChallenges ");
        if (mDB.getConnectedUser() != null) {
            Log.d(LOG_TAG, "subscribeToChallenges : " + mDB.getConnectedUser().getDocId());
            Map<String, String> insertMessage = new HashMap<String, String>();
            insertMessage.put("_id", mDB.getConnectedUser().getDocId());

            FitnessMDMeteor.getInstance().subscribe("challenges_all", new Object[] { insertMessage },
                    new SubscribeListener() {
                        @Override
                        public void onSuccess() {
                            Log.d(LOG_TAG, "onSuccess challenges");
                            successfullySubscribedToChallenges = true;
                        }

                        @Override
                        public void onError(String error, String reason, String details) {
                            Log.d(LOG_TAG,
                                    "onError subscriptionId : " + error + " >>> " + reason + " >>> " + details);
                        }
                    });
        }
    }

    public void subscribeToAdvices() {
        Log.d(LOG_TAG, "subscribeToAdvices ");
        if (mDB.getConnectedUser() != null) {
            Log.d(LOG_TAG, "subscribeToAdvices : " + mDB.getConnectedUser().getDocId());
            Map<String, String> insertMessage = new HashMap<String, String>();
            insertMessage.put("_id", mDB.getConnectedUser().getDocId());

            FitnessMDMeteor.getInstance().subscribe("advices_all", new Object[] { insertMessage },
                    new SubscribeListener() {
                        @Override
                        public void onSuccess() {
                            Log.d(LOG_TAG, "onSuccess advices");
                            successfullySubscribedToAdvices = true;
                        }

                        @Override
                        public void onError(String error, String reason, String details) {
                            Log.d(LOG_TAG,
                                    "onError subscriptionId : " + error + " >>> " + reason + " >>> " + details);
                        }
                    });
        }
    }

    public InMemoryCollection getAdvices() {
        String[] collectionNames = FitnessMDMeteor.getInstance().getDatabase().getCollectionNames();
        Log.d(LOG_TAG, "collectionNames.length : " + collectionNames.length);
        for (int i = 0; i < collectionNames.length; i++) {
            Log.d(LOG_TAG, "collectionNames[" + i + "] : " + collectionNames[i]);
            if (collectionNames[i].equalsIgnoreCase("advices")) {
                return FitnessMDMeteor.getInstance().getDatabase().getCollection(collectionNames[i]);
            }
        }
        return null;
    }

    public void registerCallback(Handler mActivityHandler) {
        handlerList.add(mActivityHandler);
    }

    public void removeCallback() {
        handlerList.remove(0);
    }

    public void registerStatsCallback(IStatsChanged callback) {
        statsCallbackList.add(callback);
    }

    public void sendStepsToServer(long startOfCurrentDay, int totalSteps, int hourIndex) {
        if (FitnessMDMeteor.getInstance().isConnected()) {
            if (mDB.getConnectedUser() != null) {
                FitnessMDMeteor.getInstance().sendStepsToServer(mDB.getConnectedUser().getDocId(),
                        startOfCurrentDay, totalSteps, hourIndex, new ResultListener() {
                            @Override
                            public void onSuccess(String s) {
                                Log.d(LOG_TAG, "Send steps to server -- SUCCESS");

                            }

                            @Override
                            public void onError(String error, String reason, String details) {
                                Log.d(LOG_TAG, "Send steps to server -- ERROR");
                            }
                        });
            } else {
                Log.d(LOG_TAG, "sendStepsToServer connectedUser is null");
            }
        } else {
            Log.d(LOG_TAG, "Meteor not connected ERROR -- send steps to server");
        }
    }

    public void registerToChallenge(String challengeID, boolean isRegistering) {
        if (FitnessMDMeteor.getInstance().isConnected()) {
            if (mDB.getConnectedUser() != null) {
                FitnessMDMeteor.getInstance().registerToChallenge(mDB.getConnectedUser().getDocId(), challengeID,
                        isRegistering, new ResultListener() {
                            @Override
                            public void onSuccess(String s) {
                                Log.d(LOG_TAG, "registerToChallenge -- SUCCESS");

                            }

                            @Override
                            public void onError(String error, String reason, String details) {
                                Log.d(LOG_TAG, "registerToChallenge -- ERROR");
                            }
                        });
            } else {
                Log.d(LOG_TAG, "registerToChallenge connectedUser is null");
            }
        } else {
            Log.d(LOG_TAG, "Meteor not connected ERROR -- registerToChallenge");
        }
    }
}