com.maplescot.loggerbill.misc.Profile.java Source code

Java tutorial

Introduction

Here is the source code for com.maplescot.loggerbill.misc.Profile.java

Source

/*
 * (C) Copyright 2014 MapleScot Development
 * This file licensed under a Creative Commons 3.0 by attribution licence
 * https://creativecommons.org/licenses/by/3.0/
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * https://github.com/duriej/LoggerBill
 */
package com.maplescot.loggerbill.misc;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Preferences;
import com.badlogic.gdx.utils.Json;
import com.badlogic.gdx.utils.JsonValue;
import com.maplescot.loggerbill.gpg.Achievement;
import com.maplescot.loggerbill.gpg.GPG;
import com.maplescot.loggerbill.gpg.Leaderboard;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;

/**
 * This class represents an individual profile.
 * Created by james on 23/07/14.
 */
public class Profile implements Json.Serializable {
    private final static String TAG = Profile.class.toString();

    private final static String soundOnStr = "soundOn";
    private final static String musicOnStr = "musicOn";
    private final static String totalPlaysStr = "totalPlays";
    private final static String totalChunksStr = "totalChunks";
    private final static String totalTimeStr = "totalTime";
    private final static String bestChunksStr = "bestChunks";
    private final static String bestCPSStr = "bestCPS";
    private final static String achievementsStr = "achievements";
    private final static String gplusStr = "gplus";
    private static final String CKSUM = "profile_id";
    private static final String CKSUMV = "profile_id_v";
    private final static String tweetedStr = "_tweeted";
    private boolean soundOn = true;
    private boolean musicOn;

    private long totalPlays = 0l;
    private long totalChunks = 0l;
    private long totalTime = 0l;
    private long bestChunks = 0l;
    private float bestCPS = 0f;
    private String ckSum;
    private long ckSumV;
    private static final long ckVersion = 1;
    private String gplusId = "";
    private Map<String, Boolean> achievementsMap = new HashMap<String, Boolean>();

    public boolean isSoundOn() {
        return soundOn;
    }

    public void setSoundOn(boolean soundOn) {
        this.soundOn = soundOn;
    }

    public boolean isMusicOn() {
        return musicOn;
    }

    public void setMusicOn(boolean musicOn) {
        this.musicOn = musicOn;
    }

    public long getTotalPlays() {
        return totalPlays;
    }

    public void setTotalPlays(long totalPlays) {
        this.totalPlays = totalPlays;
    }

    public long getTotalChunks() {
        return totalChunks;
    }

    public void setTotalChunks(long totalChunks) {
        this.totalChunks = totalChunks;
    }

    public long getTotalTime() {
        return totalTime;
    }

    public void setTotalTime(long totalTime) {
        this.totalTime = totalTime;
    }

    public long getBestChunks() {
        return bestChunks;
    }

    public void setBestChunks(long bestChunks) {
        this.bestChunks = bestChunks;
    }

    public float getBestCPS() {
        return bestCPS;
    }

    public void setBestCPS(float bestCPS) {
        this.bestCPS = bestCPS;
    }

    public String getGplusId() {
        return gplusId;
    }

    public void setGplusId(String gplusId) {
        this.gplusId = gplusId;
    }

    public BigDecimal getBestCPSFormatted() {
        return new BigDecimal(bestCPS).setScale(2, RoundingMode.HALF_UP);
    }

    public BigDecimal getAvgChunksFormatted() {
        if (totalPlays > 0)
            return new BigDecimal((float) totalChunks / totalPlays).setScale(2, RoundingMode.HALF_UP);
        else
            return new BigDecimal(0);
    }

    public void init(Preferences prefs) {
        ckSumV = prefs.getLong(CKSUMV, 0);
        soundOn = prefs.getBoolean(soundOnStr, true);
        musicOn = prefs.getBoolean(musicOnStr, true);
        totalPlays = prefs.getLong(totalPlaysStr, 0l);
        totalChunks = prefs.getLong(totalChunksStr, 0l);
        totalTime = prefs.getLong(totalTimeStr, 0l);
        bestChunks = prefs.getLong(bestChunksStr, 0l);
        bestCPS = prefs.getFloat(bestCPSStr, 0f);
        gplusId = prefs.getString(gplusStr, "");
        ckSum = prefs.getString(CKSUM, null);

        loadAchievements(prefs.getString(achievementsStr, ""));
        if (totalPlays == 0 && totalChunks == 0 && bestCPS == 0f && bestChunks == 0 && totalTime == 0) {
            ckSum = makeCkSum();
            ckSumV = ckVersion;
        }

        if (!isCkSumValid())
            reset();
    }

    private void reset() {
        soundOn = true;
        musicOn = true;
        totalPlays = 0l;
        totalChunks = 0l;
        totalTime = 0l;
        bestChunks = 0l;
        bestCPS = 0f;
        gplusId = "";
        loadAchievements("");
        ckSum = makeCkSum();
        ckSumV = ckVersion;
    }

    private String makeCkSum() {
        double value = totalPlays * totalChunks * totalTime * bestChunks * bestCPS;

        StringBuilder b = new StringBuilder();
        b.append(value);
        for (Achievement a : ProfileManager.getAchievementManager().getAchievements()) {
            b.append(isAchieved(a));
            b.append(isTweeted(a));
        }
        b.append(gplusId);
        return getMD5EncryptedString(b.toString());
    }

    public boolean isCkSumValid() {
        return ckSumV == ckVersion && makeCkSum().equals(ckSum);
    }

    private void loadAchievements(String achievements) {
        achievementsMap = new HashMap<String, Boolean>();
        for (String s : achievements.split("[|]")) {
            if (!s.isEmpty()) {
                String[] pair = s.split(":");
                achievementsMap.put(pair[0], Boolean.valueOf(pair[1]));
            }
        }
    }

    private String saveAchievements() {
        StringBuilder result = new StringBuilder();
        for (String key : achievementsMap.keySet()) {
            result.append(key).append(":").append(achievementsMap.get(key).booleanValue()).append("|");
        }
        if (result.length() == 0)
            return "";
        return result.substring(0, result.lastIndexOf("|"));
    }

    public void save(Preferences prefs) {
        ckSum = makeCkSum();
        ckSumV = ckVersion;
        prefs.putBoolean(soundOnStr, soundOn);
        prefs.putBoolean(musicOnStr, musicOn);
        prefs.putLong(totalPlaysStr, totalPlays);
        prefs.putLong(totalChunksStr, totalChunks);
        prefs.putLong(totalTimeStr, totalTime);
        prefs.putLong(bestChunksStr, bestChunks);
        prefs.putFloat(bestCPSStr, bestCPS);
        prefs.putString(gplusStr, gplusId);
        prefs.putString(CKSUM, ckSum);
        prefs.putLong(CKSUMV, ckSumV);

        prefs.putString(achievementsStr, saveAchievements());
    }

    public void addPlay(int chunk_counter, float totalTime) {
        // calculate stats
        // CPS only counts if we have a minimum number of chunks chunked
        float cps = chunk_counter > Constants.MIN_CHUNKS_FOR_CPS ? ((float) chunk_counter) / totalTime : 0.01f;

        totalPlays += 1;
        totalChunks += chunk_counter;
        this.totalTime += totalTime;

        if (chunk_counter > bestChunks)
            bestChunks = chunk_counter;

        if (cps > bestCPS)
            bestCPS = cps;

        // test our achievements
        for (Achievement a : ProfileManager.getAchievementManager().getAchievements()) {
            if (a.isIncremental()) {
                GPG.getInstance().setAchievementIncrement(a.getId(), (int) totalChunks, (long) a.getValue());
            }
            if (a.test(chunk_counter, cps, totalPlays, totalChunks, bestChunks, bestCPS)) {
                achievementsMap.put(a.getId(), true);
                GPG.getInstance().unlockAchievement(a.getId());
            }
        }

        // push our scores to the leaderboards
        for (Leaderboard l : ProfileManager.getLeaderboardManager().getLeaderboards()) {
            if (l.getName().equals(bestChunksStr))
                GPG.getInstance().submitScore(l.getId(), (int) bestChunks);

            if (l.getName().equals(totalChunksStr))
                GPG.getInstance().submitScore(l.getId(), (int) totalChunks);

            if (l.getName().equals(totalTimeStr))
                GPG.getInstance().submitScore(l.getId(), (int) (this.totalTime * 1000));

            if (l.getName().equals("bestChunksPerSecond"))
                GPG.getInstance().submitScore(l.getId(), (int) (bestCPS * 1000f));
        }
    }

    public boolean isAchieved(Achievement a) {
        Boolean done = achievementsMap.get(a.getId());
        return done == null ? false : done;
    }

    public boolean isTweeted(Achievement a) {
        Boolean done = achievementsMap.get(a.getId() + tweetedStr);
        return done == null ? false : done;
    }

    public void setTweeted(Achievement a) {
        achievementsMap.put(a.getId() + tweetedStr, true);
    }

    public boolean hasUntweetedAchievements() {
        for (String a : achievementsMap.keySet()) {
            if (a.contains(tweetedStr))
                continue;
            if (achievementsMap.get(a)
                    && (!achievementsMap.containsKey(a + tweetedStr) || !achievementsMap.get(a + tweetedStr)))
                return true;
        }
        return false;
    }

    public byte[] serialize() {
        ckSum = makeCkSum();
        ckSumV = ckVersion;
        Json json = new Json();

        String out = json.prettyPrint(this);

        Gdx.app.debug(TAG, out);
        return out.getBytes();
    }

    public Profile deserialize(byte[] profile) {
        if (profile == null)
            return null;

        String in = new String(profile);
        Gdx.app.debug(TAG, in);
        Json json = new Json();
        try {
            Profile p = json.fromJson(Profile.class, in);
            return !p.isCkSumValid() ? null : p;
        } catch (Exception e) {
            Gdx.app.error(TAG, "Failed to parse json profile", e);
        }
        return null;
    }

    public boolean selectConflictedProfile(String account, Profile p1, Profile p2) {
        if (p1 == null)
            return false;
        if (p2 == null)
            return true;

        // If the gplus account has changed then switch to that profile
        if (!account.equals(p2.gplusId))
            return true;

        if (p1.totalPlays == p2.totalPlays)
            return p1.bestChunks > p2.bestChunks;
        else
            return p1.totalPlays > p2.totalPlays;
    }

    public static String getMD5EncryptedString(String encTarget) {
        MessageDigest mdEnc = null;
        try {
            mdEnc = MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException e) {
            System.out.println("Exception while encrypting to md5");
            e.printStackTrace();
        } // Encryption algorithm
        mdEnc.update(encTarget.getBytes(), 0, encTarget.length());
        String md5 = new BigInteger(1, mdEnc.digest()).toString(16);
        while (md5.length() < 32) {
            md5 = "0" + md5;
        }
        return md5;
    }

    /*
     * As we use Proguard on Android its best to do this explicitly via an interface override
     * than implicitly through reflection. Works better with GWT too.
     */
    @Override
    public void write(Json json) {
        json.writeValue(soundOnStr, soundOn);
        json.writeValue(musicOnStr, musicOn);
        json.writeValue(totalPlaysStr, totalPlays);
        json.writeValue(totalChunksStr, totalChunks);
        json.writeValue(totalTimeStr, totalTime);
        json.writeValue(bestChunksStr, bestChunks);
        json.writeValue(bestCPSStr, bestCPS);
        json.writeValue(gplusStr, gplusId);
        json.writeValue(CKSUM, ckSum);
        json.writeValue(CKSUMV, ckSumV);

        json.writeValue(achievementsStr, saveAchievements());
    }

    @Override
    public void read(Json json, JsonValue jsonData) {
        soundOn = jsonData.get(soundOnStr).asBoolean();
        musicOn = jsonData.get(musicOnStr).asBoolean();
        totalPlays = jsonData.get(totalPlaysStr).asLong();
        totalChunks = jsonData.get(totalChunksStr).asLong();
        totalTime = jsonData.get(totalTimeStr).asLong();
        bestChunks = jsonData.get(bestChunksStr).asLong();
        bestCPS = jsonData.get(bestCPSStr).asFloat();
        gplusId = jsonData.get(gplusStr).asString();
        ckSum = jsonData.get(CKSUM).asString();
        ckSumV = jsonData.get(CKSUMV).asLong();

        loadAchievements(jsonData.get(achievementsStr).asString());
    }
}