org.zoumbox.mh_dla_notifier.profile.v1.ProfileProxyV1.java Source code

Java tutorial

Introduction

Here is the source code for org.zoumbox.mh_dla_notifier.profile.v1.ProfileProxyV1.java

Source

/*
 * #%L
 * MountyHall DLA Notifier
 * $Id$
 * $HeadURL$
 * %%
 * Copyright (C) 2012 - 2014 Zoumbox.org
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as
 * published by the Free Software Foundation, either version 3 of the 
 * License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public 
 * License along with this program.  If not, see
 * <http://www.gnu.org/licenses/gpl-3.0.html>.
 * #L%
 */
package org.zoumbox.mh_dla_notifier.profile.v1;

import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.zoumbox.mh_dla_notifier.MhDlaNotifierConstants;
import org.zoumbox.mh_dla_notifier.MhDlaNotifierUtils;
import org.zoumbox.mh_dla_notifier.Pair;
import org.zoumbox.mh_dla_notifier.PreferencesHolder;
import org.zoumbox.mh_dla_notifier.profile.AbstractProfileProxy;
import org.zoumbox.mh_dla_notifier.profile.MissingLoginPasswordException;
import org.zoumbox.mh_dla_notifier.profile.ProfileProxy;
import org.zoumbox.mh_dla_notifier.profile.UpdateRequestType;
import org.zoumbox.mh_dla_notifier.sp.HighUpdateRateException;
import org.zoumbox.mh_dla_notifier.sp.NetworkUnavailableException;
import org.zoumbox.mh_dla_notifier.sp.PublicScript;
import org.zoumbox.mh_dla_notifier.sp.PublicScriptException;
import org.zoumbox.mh_dla_notifier.sp.PublicScriptsProxy;
import org.zoumbox.mh_dla_notifier.sp.QuotaExceededException;
import org.zoumbox.mh_dla_notifier.troll.Race;
import org.zoumbox.mh_dla_notifier.troll.Troll;

import com.google.common.base.Predicate;
import com.google.common.base.Strings;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;

import android.content.Context;
import android.content.SharedPreferences;
import android.util.Log;

/**
 * @author Arno <arno@zoumbox.org>
 */
public class ProfileProxyV1 extends AbstractProfileProxy implements ProfileProxy {

    private static final String TAG = MhDlaNotifierConstants.LOG_PREFIX + ProfileProxyV1.class.getSimpleName();

    public static boolean shouldUpdate(Context context, PublicScript script, String trollNumber) {
        Date lastUpdate = PublicScriptsProxy.geLastUpdate(context, script, trollNumber);
        if (lastUpdate == null) {
            return true;
        } else {
            int dailyQuota = GET_USABLE_QUOTA.apply(script.getCategory());
            int minutesDelay = 24 * 60 / dailyQuota;
            Calendar calendar = Calendar.getInstance();
            calendar.add(Calendar.MINUTE, -minutesDelay);
            Date delay = calendar.getTime();
            boolean result = lastUpdate.before(delay);
            return result;
        }
    }

    protected String getTrollNumber(Context context) {
        SharedPreferences preferences = context.getSharedPreferences(PREFS_NAME, 0);

        String trollNumber = preferences.getString(PROPERTY_TROLL_ID, null);
        return trollNumber;
    }

    public static final String PREFS_NAME = "org.zoumbox.mh.dla.notifier.preferences";

    protected static final String PROPERTY_TROLL_ID = "trollId";
    protected static final String PROPERTY_TROLL_PASSWORD = "trollPassword";

    public Set<String> getTrollIds(Context context) {

        String trollId = getTrollNumber(context);
        Set<String> result = new LinkedHashSet<String>();
        if (!Strings.isNullOrEmpty(trollId)) {
            result.add(trollId); // TODO AThimel 06/08/13 manage several trolls
        }
        return result;
    }

    public void saveIdPassword(Context context, String trollId, String trollPassword) {

        SharedPreferences preferences = context.getSharedPreferences(PREFS_NAME, 0);
        SharedPreferences.Editor editor = preferences.edit();
        editor.putString(PROPERTY_TROLL_ID, trollId);
        editor.putString(PROPERTY_TROLL_PASSWORD, trollPassword);
        editor.commit();

        SharedPreferences preferences2 = context.getSharedPreferences("org.zoumbox.mh.dla.notifier.preferences.v2",
                0);
        SharedPreferences.Editor edit = preferences2.edit();
        edit.clear();
        edit.commit();
    }

    public boolean isPasswordDefined(Context context, String trollId) {

        SharedPreferences preferences = context.getSharedPreferences(PREFS_NAME, 0);
        Pair<String, String> pair = loadIdPassword0(preferences);

        boolean result = Strings.isNullOrEmpty(pair.left());
        result |= Strings.isNullOrEmpty(pair.right());
        return result;
    }

    protected static Pair<String, String> loadIdPassword0(SharedPreferences preferences) {

        final String trollNumber = preferences.getString(PROPERTY_TROLL_ID, null);
        String trollPassword = preferences.getString(PROPERTY_TROLL_PASSWORD, null);

        Pair<String, String> result = Pair.of(trollNumber, trollPassword);
        return result;
    }

    protected Pair<String, String> loadIdPassword(SharedPreferences preferences)
            throws MissingLoginPasswordException {

        Pair<String, String> pair = loadIdPassword0(preferences);

        if (Strings.isNullOrEmpty(pair.left()) || Strings.isNullOrEmpty(pair.right())) {
            throw new MissingLoginPasswordException();
        }

        return pair;
    }

    public Pair<String, String> loadIdPassword(Context context) {

        SharedPreferences preferences = context.getSharedPreferences(PREFS_NAME, 0);
        Pair<String, String> pair = loadIdPassword0(preferences);

        return pair;
    }

    public Pair<Troll, Boolean> fetchTroll(final Context context, String trollId, UpdateRequestType updateRequest)
            throws QuotaExceededException, MissingLoginPasswordException, PublicScriptException,
            NetworkUnavailableException {

        // TODO AThimel 06/08/13 use trollId

        Troll result = new Troll();

        List<String> requestedProperties = Arrays.asList("NOM", "RACE", "NIVAL", "GUILDE", "CARACT", "BLASON",
                "NB_KILLS", "NB_MORTS", "DATE_INSCRIPTION", "PV", "PV_MAX", "FATIGUE", "POS_X", "POS_Y", "POS_N",
                "DUREE_DU_TOUR", "DLA", "PA_RESTANT", "CAMOU", "INVISIBLE", "INTANGIBLE", "IMMOBILE", "A_TERRE",
                "EN_COURSE", "LEVITATION");
        Map<String, String> properties = fetchProperties(context, updateRequest, requestedProperties);

        result.setNumero(getTrollNumber(context));

        result.setNom(properties.get("NOM"));
        result.setRace(Race.valueOf(properties.get("RACE")));
        result.setNival(Integer.parseInt(properties.get("NIVAL")));
        result.setDateInscription(MhDlaNotifierUtils.parseSpDate(properties.get("DATE_INSCRIPTION")));

        result.setPvActuelsCar(Integer.parseInt(properties.get("PV")));
        result.setPvVariation(Integer.parseInt(properties.get("PV_VARIATION")));
        result.setPvMaxCar(Integer.parseInt(properties.get("PV_MAX")));
        result.setFatigue(Integer.parseInt(properties.get("FATIGUE")));

        result.setPosX(Integer.parseInt(properties.get("POS_X")));
        result.setPosY(Integer.parseInt(properties.get("POS_Y")));
        result.setPosN(Integer.parseInt(properties.get("POS_N")));

        result.setCamou("1".equals(properties.get("CAMOU")));
        result.setInvisible("1".equals(properties.get("INVISIBLE")));
        result.setIntangible("1".equals(properties.get("INTANGIBLE")));
        result.setImmobile("1".equals(properties.get("IMMOBILE")));
        result.setATerre("1".equals(properties.get("A_TERRE")));
        result.setEnCourse("1".equals(properties.get("EN_COURSE")));
        result.setLevitation("1".equals(properties.get("LEVITATION")));

        result.setDureeDuTourCar(Integer.parseInt(properties.get("DUREE_DU_TOUR")));
        result.setDla(MhDlaNotifierUtils.parseSpDate(properties.get("DLA")));
        result.setPa(Integer.parseInt(properties.get("PA_RESTANT")));

        result.setBlason(properties.get("BLASON"));
        String guildeNumber = properties.get("GUILDE");
        if (!Strings.isNullOrEmpty(guildeNumber)) {
            result.setGuilde(Integer.parseInt(guildeNumber));
        }
        result.setNbKills(Integer.parseInt(properties.get("NB_KILLS")));
        result.setNbMorts(Integer.parseInt(properties.get("NB_MORTS")));

        //        result.mouches = Lists.newArrayList();
        //        List<String> moucheLines = Lists.newArrayList(Splitter.on("\n").omitEmptyStrings().trimResults().split(properties.get(MOUCHES)));
        //        for (String line : moucheLines) {
        //            List<String> fields = Lists.newArrayList(Splitter.on(";").split(line));
        //            Mouche mouche = new Mouche();
        //            mouche.id = fields.get(0);
        //            mouche.nom = fields.get(1);
        //            mouche.type = MoucheType.valueOf(fields.get(2));
        //            mouche.age = Integer.parseInt(fields.get(3));
        //            mouche.presente = "LA".equals(fields.get(4));
        //
        //            result.mouches.add(mouche);
        //        }

        //        result.equipements = Lists.newArrayList();
        //        List<String> equipementLines = Lists.newArrayList(Splitter.on("\n").omitEmptyStrings().trimResults().split(properties.get(EQUIPEMENT)));
        //        for (String line : equipementLines) {
        //            List<String> fields = Lists.newArrayList(Splitter.on(";").split(line));
        //            Equipement equipement = new Equipement();
        //            equipement.id = fields.get(0);
        //            equipement.emplacement = Integer.parseInt(fields.get(1));
        //            equipement.type = EquipementType.fromType(fields.get(2));
        //            equipement.identified = "1".equals(fields.get(3));
        //            equipement.nom = fields.get(4);
        //            equipement.magie = fields.get(5);
        //            equipement.description = fields.get(6);
        //            equipement.poids = Double.parseDouble(fields.get(7));
        //
        //            result.equipements.add(equipement);
        //        }

        //        List<String> caractLines = Lists.newArrayList(Splitter.on("\n").omitEmptyStrings().trimResults().split(properties.get("CARACT")));
        //        result.setPvBM(0);
        //        result.setDlaBM(0);
        //        result.setPoids(0);
        //        int pvBm = 0, dlaBm = 0, poids = 0;
        //        for (String line : caractLines) {
        //            List<String> fields = Lists.newArrayList(Splitter.on(";").trimResults().split(line));
        //            String type = fields.get(0);
        //            if ("BMM".equals(type) || "BMP".equals(type)) {
        //                pvBm += Integer.parseInt(fields.get(5));
        //                Double dlaBMDouble = Math.floor(Double.parseDouble(fields.get(11)));
        //                dlaBm += dlaBMDouble.intValue();
        //                Double poidsDouble = Math.floor(Double.parseDouble(fields.get(12)));
        //                poids += poidsDouble.intValue();
        //            }
        //        }
        //        result.setPvBM(pvBm);
        //        result.setDlaBM(dlaBm);
        //        result.setPoids(poids);

        boolean needsUpdate = UpdateRequestType.valueOf(properties.get("NEEDS_UPDATE")).needUpdate();
        Pair<Troll, Boolean> resultPair = Pair.of(result, needsUpdate);

        return resultPair;
    }

    protected static Predicate<PublicScript> noNeedToUpdate(final Context context, final String trollNumber) {
        return new Predicate<PublicScript>() {
            @Override
            public boolean apply(PublicScript script) {
                return !shouldUpdate(context, script, trollNumber);
            }
        };
    }

    public Map<String, String> fetchProperties(final Context context, UpdateRequestType updateRequest,
            List<String> requestedProperties) throws QuotaExceededException, MissingLoginPasswordException,
            PublicScriptException, NetworkUnavailableException {

        Log.i(TAG, "Fetching properties with updateRequest: " + updateRequest);
        SharedPreferences preferences = context.getSharedPreferences(PREFS_NAME, 0);

        Pair<String, String> idAndPassword = loadIdPassword(preferences);
        final String trollNumber = idAndPassword.left();

        // Iterate over requested properties to know which SP are concerned
        Set<PublicScript> scripts = new LinkedHashSet<PublicScript>();
        Log.i(TAG, "Requesting properties: " + requestedProperties);
        //        for (String property : requestedProperties) {
        //            PublicScript script = PublicScript.forProperty(property);
        //            scripts.add(script);
        //        }
        //        scripts.add(PublicScript.ProfilPublic2);
        //        scripts.add(PublicScript.Profil2);
        //        scripts.add(PublicScript.Caract);

        // Maybe no update is requested, but needed because of missing property
        UpdateRequestType updateRequestType = updateRequest;
        if (!updateRequestType.needUpdate()) {
            for (String property : requestedProperties) {
                String value = preferences.getString(property, null);
                if (value == null) {
                    updateRequestType = UpdateRequestType.FULL;
                    Log.i(TAG, "updateRequestType changed from " + updateRequest + " to " + updateRequestType);
                    break;
                }
            }
        }

        UpdateRequestType backgroundUpdate = UpdateRequestType.NONE;
        if (updateRequestType.needUpdate()) {

            if (UpdateRequestType.ONLY_NECESSARY.equals(updateRequestType)) {
                Predicate<PublicScript> noNeedToUpdatePredicate = noNeedToUpdate(context, trollNumber);
                Iterables.removeIf(scripts, noNeedToUpdatePredicate);
            }

            for (PublicScript script : scripts) {
                try {
                    Map<String, String> propertiesFetched = PublicScriptsProxy.fetchProperties(context, script,
                            idAndPassword);
                    saveProperties(preferences, propertiesFetched);
                } catch (HighUpdateRateException hure) {
                    // Nothing to do
                }
            }
        } else {
            Predicate<PublicScript> noNeedToUpdatePredicate = noNeedToUpdate(context, trollNumber);
            Iterables.removeIf(scripts, noNeedToUpdatePredicate);

            //            if (!scripts.isEmpty()) {
            if (scripts.contains(PublicScript.Profil2)) { // Ask for update only if profil2 needs an update
                backgroundUpdate = UpdateRequestType.ONLY_NECESSARY;
            }
        }

        Map<String, String> result = new LinkedHashMap<String, String>();
        Log.i(TAG, "Background update needed ? " + backgroundUpdate);
        result.put("NEEDS_UPDATE", backgroundUpdate.name());

        String pvVariation = preferences.getString("PV_VARIATION", "0");
        result.put("PV_VARIATION", pvVariation);

        for (String property : requestedProperties) {
            String value = preferences.getString(property, null);
            result.put(property, value);
        }

        return result;
    }

    public Date getLastUpdateSuccess(final Context context, String trollId) {

        SharedPreferences preferences = context.getSharedPreferences(PREFS_NAME, 0);

        long lastUpdate = preferences.getLong("LAST_UPDATE_SUCCESS", 0l);

        Date result = null;
        if (lastUpdate > 0l) {
            Calendar calendar = Calendar.getInstance();
            calendar.setTimeInMillis(lastUpdate);
            result = calendar.getTime();
        }
        return result;
    }

    public Long getElapsedSinceLastUpdateSuccess(final Context context, String trollId) {

        SharedPreferences preferences = context.getSharedPreferences(PREFS_NAME, 0);

        long lastUpdate = preferences.getLong("LAST_UPDATE_SUCCESS", 0l);

        Long result = System.currentTimeMillis() - lastUpdate;
        return result;
    }

    public String getLastUpdateResult(final Context context, String trollId) {

        SharedPreferences preferences = context.getSharedPreferences(PREFS_NAME, 0);

        String result = preferences.getString("LAST_UPDATE_RESULT", null);

        return result;
    }

    protected static void saveProperties(SharedPreferences preferences, Map<String, String> propertiesFetched) {
        SharedPreferences.Editor editor = preferences.edit();
        for (Map.Entry<String, String> prop : propertiesFetched.entrySet()) {
            String key = prop.getKey();
            String value = prop.getValue();

            checkForPvLoss(preferences, editor, key, value);

            editor.putString(key, value);
        }
        editor.commit();
    }

    protected static void checkForPvLoss(SharedPreferences preferences, SharedPreferences.Editor editor, String key,
            String value) {
        if (key.equals("PV")) {
            int actualPV = Integer.parseInt(preferences.getString("PV", "-1"));
            int newPV = Integer.parseInt(value);
            editor.putString("PV_VARIATION", Integer.toString(newPV - actualPV));
        }
    }

    public Troll refreshDLA(Context context, String trollId) throws MissingLoginPasswordException {

        PreferencesHolder preferences = PreferencesHolder.load(context);

        boolean performUpdate = preferences.enableAutomaticUpdates;

        if (performUpdate) {

            SharedPreferences sharedPreferences = context.getSharedPreferences(PREFS_NAME, 0);

            Pair<String, String> idAndPassword = loadIdPassword(sharedPreferences);

            Log.i(TAG, "Request for Profil2 fetch for refreshDLA()");
            // Force Profil2 fetch
            try {
                Map<String, String> propertiesFetched = PublicScriptsProxy.fetchProperties(context,
                        PublicScript.Profil2, idAndPassword);
                saveProperties(sharedPreferences, propertiesFetched);
            } catch (QuotaExceededException qee) {
                Log.w(TAG, "Quota exceeded, ignoring update", qee);
            } catch (NetworkUnavailableException qee) {
                Log.w(TAG, "Network failure, ignoring update", qee);
            } catch (PublicScriptException pse) {
                Log.w(TAG, "Script exception, ignoring update", pse);
            } catch (HighUpdateRateException hure) {
                Log.w(TAG, "Too much updates, ignoring update", hure);
            }
        }

        // Get updated (by the previous fetch) troll info
        Troll troll = fetchTrollWithoutUpdate(context, trollId).left();
        return troll;
    }

    @Override
    protected SharedPreferences getPreferences(Context context) {
        SharedPreferences preferences = context.getSharedPreferences(PREFS_NAME, 0);
        return preferences;
    }

    //    private static Date getDLA(SharedPreferences preferences) {
    //        String string = preferences.getString(DLA.name(), null);
    //        Date result = MhDlaNotifierUtils.parseSpDate(string);
    //        return result;
    //    }

    //    public static Date getDLA(Context context) {
    //        SharedPreferences preferences = context.getSharedPreferences(PREFS_NAME, 0);
    //        Date result = getDLA(preferences);
    //        return result;
    //    }
    //
    //    private static Integer getPA(SharedPreferences preferences) {
    //        String string = preferences.getString(PA_RESTANT.name(), null);
    //        Integer result = null;
    //        try {
    //            result = Integer.parseInt(string);
    //        } catch (Exception eee) {
    //            // Nothing to do
    //        }
    //        return result;
    //    }

}