fr.outadev.splatcompanion.StageRotationUpdater.java Source code

Java tutorial

Introduction

Here is the source code for fr.outadev.splatcompanion.StageRotationUpdater.java

Source

/*
 * Splat Companion - Stage rotation schedule viewer for Splatoon(tm)
 * Copyright (C) 2015 - 2016  Baptiste Candellier
 *
 * 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/>.
 */

package fr.outadev.splatcompanion;

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

import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.Response;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import fr.outadev.splatcompanion.model.GameMode;
import fr.outadev.splatcompanion.model.GameModeFactory;
import fr.outadev.splatcompanion.model.GameModeRanked;
import fr.outadev.splatcompanion.model.GameModeRegular;
import fr.outadev.splatcompanion.model.RulesFactory;
import fr.outadev.splatcompanion.model.Schedule;
import fr.outadev.splatcompanion.model.Stage;
import fr.outadev.splatcompanion.model.StageFactory;

/**
 * Manages the retrieval of stage rotation schedules from the API.
 */
public class StageRotationUpdater {

    public static final String SCHEDULE_ENDPOINT_URL = "https://splatoon.ink/schedule.json";
    public static final String KEY_LAST_CACHED_DATA = "cached_response_schedule";

    protected static final OkHttpClient client = new OkHttpClient();

    /**
     * Fetches the freshest schedules available (from cache or from the API).
     *
     * @param context A context
     * @return A list of schedules containing the data
     * @throws IOException
     * @throws JSONException
     */
    public static List<Schedule> getFreshestData(Context context) throws IOException, JSONException {
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
        String cache = prefs.getString(KEY_LAST_CACHED_DATA, null);

        if (cache != null) {
            try {
                List<Schedule> cachedSchedules = parseSchedules(cache);

                // If the cached schedules aren't empty
                if (cachedSchedules != null && !cachedSchedules.isEmpty()) {

                    // If the cached schedules are still fresh
                    if (cachedSchedules.get(0).getEndTime() > System.currentTimeMillis()) {
                        Log.d(StageRotationUpdater.class.getName(), "Using cached data");
                        return cachedSchedules;
                    }
                }
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }

        Log.d(StageRotationUpdater.class.getName(), "Fetching fresh data");

        String freshData = getScheduleDataFromAPI();
        prefs.edit().putString(KEY_LAST_CACHED_DATA, freshData).apply();

        return parseSchedules(freshData);
    }

    /**
     * Retrieves the freshest schedule from the API
     *
     * @return The raw response from the API
     * @throws IOException
     */
    protected static String getScheduleDataFromAPI() throws IOException {
        Request request = new Request.Builder().url(SCHEDULE_ENDPOINT_URL).build();

        Response response = client.newCall(request).execute();
        return response.body().string();
    }

    /**
     * Parses the schedules of the current and next Splatoon map rotations.
     * This method parses the JSON data and creates the required objects corresponding to the data.
     *
     * @param rawJson The raw JSON data returned by the API
     * @return A list of schedules containing the parsed data
     * @throws JSONException
     */
    protected static List<Schedule> parseSchedules(String rawJson) throws JSONException {
        List<Schedule> schedules = new ArrayList<>();
        boolean isSplatfesting = false;

        JSONObject baseObject = new JSONObject(rawJson);
        JSONArray scheduleArray = baseObject.getJSONArray("schedule");

        if (baseObject.has("splatfest") && baseObject.getBoolean("splatfest")) {
            isSplatfesting = true;
        }

        // For each schedule in the array
        for (int i = 0; i < scheduleArray.length(); i++) {
            JSONObject scheduleObject = scheduleArray.getJSONObject(i);
            Schedule schedule = new Schedule(scheduleObject.getLong("startTime"),
                    scheduleObject.getLong("endTime"));

            // Parse Regular game mode
            schedule.setRegularMode((GameModeRegular) parseGameMode(scheduleObject, "regular"));

            // Parse Ranked game mode
            schedule.setRankedMode((GameModeRanked) parseGameMode(scheduleObject, "ranked"));

            schedule.setSplatfesting(isSplatfesting);
            schedules.add(schedule);
            //schedule.setEndTime(System.currentTimeMillis() + 5000); // testing
        }

        return schedules;
    }

    /**
     * Parses a game mode with all its dependant properties.
     *
     * @param scheduleObject The JSON object to parse, containing the game mode
     * @param gameModeId     The identifier of the game mode to parse. Typically "regular", "ranked"...
     * @return The game mode
     * @throws JSONException
     */
    private static GameMode parseGameMode(JSONObject scheduleObject, String gameModeId) throws JSONException {
        GameMode gameMode = GameModeFactory.create(gameModeId);

        if (gameMode == null) {
            return null;
        }

        if (scheduleObject.has(gameModeId)) {
            JSONObject gameModeObject = scheduleObject.getJSONObject(gameModeId);

            if (gameModeObject.has("rules") && gameModeObject.getJSONObject("rules").has("en")) {
                gameMode.setGameRules(RulesFactory.create(gameModeObject.getJSONObject("rules").getString("en")));
            }

            gameMode.getStages().addAll(parseStages(gameModeObject));
            gameMode.getSplatfestTeams().addAll(parseTeams(gameModeObject));
        }

        return gameMode;
    }

    /**
     * Get the stages for a JSON object containing maps
     * "regular":{ "maps":[{...
     */
    protected static List<Stage> parseStages(JSONObject gameModeObject) throws JSONException {
        List<Stage> stages = new ArrayList<>();

        if (!gameModeObject.has("maps")) {
            return stages;
        }

        JSONArray mapsArray = gameModeObject.getJSONArray("maps");

        for (int i = 0; i < mapsArray.length(); i++) {
            JSONObject mapObject = mapsArray.getJSONObject(i);
            Stage stage = StageFactory.create(mapObject.getString("nameEN"));
            stages.add(stage);
        }

        return stages;
    }

    /**
     * Get the Splatfest teams for a JSON object containing teams
     * "regular":{ "teams":[ "team 1", "team 2"...]...
     */
    protected static List<String> parseTeams(JSONObject gameModeObject) throws JSONException {
        List<String> teams = new ArrayList<>(2);

        if (!gameModeObject.has("teams")) {
            return teams;
        }

        JSONArray teamsArray = gameModeObject.getJSONArray("teams");

        for (int i = 0; i < teamsArray.length(); i++) {
            String team = teamsArray.getString(i);
            teams.add(team);
        }

        return teams;
    }
}