de.skubware.opentraining.activity.settings.sync.WgerJSONParser.java Source code

Java tutorial

Introduction

Here is the source code for de.skubware.opentraining.activity.settings.sync.WgerJSONParser.java

Source

/**
 * 
 * This is OpenTraining, an Android application for planning your your fitness training.
 * Copyright (C) 2012-2014 Christian Skubich
 * 
 * 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 de.skubware.opentraining.activity.settings.sync;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.SortedSet;
import java.util.TreeSet;

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

import android.util.Log;
import android.util.SparseArray;

import de.skubware.opentraining.basic.ExerciseType;
import de.skubware.opentraining.basic.ExerciseType.ExerciseSource;
import de.skubware.opentraining.basic.License.LicenseType;
import de.skubware.opentraining.basic.Muscle;
import de.skubware.opentraining.basic.SportsEquipment;
import de.skubware.opentraining.db.IDataProvider;

/**
 * A class for parsing the JSON-data from wger.
 *
 */
public class WgerJSONParser {

    private List<ExerciseType> mNewExerciseList = new ArrayList<ExerciseType>();
    /* The exercise builder objects, for modifying the exercises after parsing (e.g. changing image) */
    private List<ExerciseType.Builder> mNewExerciseBuilderList = new ArrayList<ExerciseType.Builder>();

    //TODO Find better solution, remove static methods and fields
    private static IDataProvider mDataProvider;

    /** Tag for logging */
    private static final String TAG = "WgerJSONParser";

    /**
     * Constructor. Will start download immediately.
     * 
     * @param exerciseJSONString
     *            The exercises as JSON-String
     * @param languageJSONString
     *            The languages as JSON-String
     * @param muscleJSONString
     *            The muscles as JSON-String
     * @param dataProvider
     * @throws JSONException
     */
    public WgerJSONParser(String exerciseJSONString, String languageJSONString, String muscleJSONString,
            String equipmentJSONString, String licenseJSONString, IDataProvider dataProvider) throws JSONException {
        mDataProvider = dataProvider;

        // parse languages
        SparseArray<Locale> localeSparseArray = parseLanguages(languageJSONString);
        // parse muscles
        SparseArray<Muscle> muscleSparseArray = parseMuscles(muscleJSONString);
        // parse licenses
        SparseArray<LicenseType> licenseSparseArray = parseLicenses(licenseJSONString);

        // parse equipment (not required until REST-API supports this)
        // SparseArray<SportsEquipment> equipmentSparseArray = parseEquipment(equipmentJSONString);

        JSONObject mainObject = new JSONObject(exerciseJSONString);
        Log.d(TAG, mainObject.toString());
        JSONArray exerciseArray = mainObject.getJSONArray("objects");

        // parse each exercise of the JSON Array
        for (int i = 0; i < exerciseArray.length(); i++) {

            JSONObject jsonExercise = exerciseArray.getJSONObject(i);
            // get name and check if exercise already exists
            String name = jsonExercise.getString("name");
            if (dataProvider.exerciseExists(name))
                continue;

            ExerciseType.Builder builder = new ExerciseType.Builder(name, ExerciseSource.SYNCED);

            // category (unused)
            // String category = jsonExercise.getString("category");

            // comments (unused)
            // JSONArray commentArray = jsonExercise.getJSONArray("comments");
            // for (int k = 0; k < commentArray.length(); k++) {
            //   String comment = commentArray.getString(k);
            //}

            // description
            String description = jsonExercise.getString("description");
            builder.description(description);

            // id (unused)
            //String id = jsonExercise.getString("id");

            // language
            // the json-language String might look like this:
            // '/api/v1/language/1/'
            // only the number at the end is required
            String language = jsonExercise.getString("language");
            int languageNumber = getLastNumberOfJson(language);

            Map<Locale, String> translationMap = new HashMap<Locale, String>();
            translationMap.put(localeSparseArray.get(languageNumber), name);
            builder.translationMap(translationMap);

            // resource_uri (unused)
            //String resource_uri = jsonExercise.getString("resource_uri");

            // muscles
            SortedSet<Muscle> muscleSet = new TreeSet<Muscle>();
            JSONArray muscleArray = jsonExercise.getJSONArray("muscles");
            for (int l = 0; l < muscleArray.length(); l++) {
                String muscleString = muscleArray.getString(l);
                Muscle muscle = muscleSparseArray.get(getLastNumberOfJson(muscleString));
                muscleSet.add(muscle);
            }
            builder.activatedMuscles(muscleSet);

            // licenses
            // the json-language String might look like this:
            // '/api/v1/license/1/'
            // only the number at the end is required

            if (jsonExercise.has("license")) {
                int licenseNumber = getLastNumberOfJson(jsonExercise.getString("license"));
                LicenseType licenseType = licenseSparseArray.get(licenseNumber);
                String license_author = jsonExercise.getString("license_author");
                Log.v(TAG, "license=" + licenseType + " license_author=" + license_author);
            }

            // equipment
            // not yet supported by REST-API
            /*SortedSet<SportsEquipment> equipmentSet = new TreeSet<SportsEquipment>();
            JSONArray equipmentArray = jsonExercise.getJSONArray("equipment");
            for (int l = 0; l < equipmentArray.length(); l++) {
               String equipmentString = equipmentArray.getString(l);
               SportsEquipment equipment = equipmentSparseArray.get(getLastNumberOfJson(equipmentString));
               equipmentSet.add(equipment);
            }*/

            builder.activatedMuscles(muscleSet);
            // images
            List<File> imageList = new ArrayList<File>();
            JSONArray imageArray = jsonExercise.getJSONArray("images");
            for (int l = 0; l < imageArray.length(); l++) {
                String imageString = imageArray.getString(l);
                imageList.add(new File(imageString));
            }
            builder.imagePath(imageList);

            mNewExerciseList.add(builder.build());
            mNewExerciseBuilderList.add(builder);
        }

    }

    /**
     * Returns the last number of a JSON-String.
     * 
     * E.g.: for '/api/v1/something/1/' '1' will be returned.
     * 
     * @param jsonString
     * 
     * @return the last number of a JSON-String
     */
    public static int getLastNumberOfJson(String jsonString) {
        String[] split = jsonString.split("/");
        return Integer.parseInt(split[split.length - 1]);
    }

    /**
     * Parses the JSON-language(locale)-String and returns an SparseArray that maps the
     * language numbers to {@link Locale} objects
     */
    private SparseArray<Locale> parseLanguages(String languagesJSONString) throws JSONException {
        return parse(languagesJSONString, Locale.class);
    }

    /**
     * Parses the JSON-muscle-String and returns an SparseArray that maps the
     * muscle numbers to {@link Muscle} objects
     * 
     * Example for muscle JSON:
     * 
     * {"meta": {"limit": 20, "next": null, "offset": 0, "previous": null,
     * "total_count": 15}, "objects": [{"id": 2, "is_front": true, "name":
     * "Anterior deltoid", "resource_uri": "/api/v1/muscle/2/"}]}
     * 
     */
    private SparseArray<Muscle> parseMuscles(String musclesJSONString) throws JSONException {
        return parse(musclesJSONString, Muscle.class);
    }

    public static SparseArray<LicenseType> parseLicenses(String licenseJSONString) throws JSONException {
        return parse(licenseJSONString, LicenseType.class);
    }

    private SparseArray<SportsEquipment> parseEquipment(String equipmentJSONString) throws JSONException {
        return parse(equipmentJSONString, SportsEquipment.class);
    }

    /**
     * A generic parsing method for parsing JSON to SportsEquipment, Muscle or Locale.
     */
    private static <T> SparseArray<T> parse(String jsonString, Class<T> c) throws JSONException {
        JSONObject mainObject = new JSONObject(jsonString);
        Log.d(TAG, "jsonString: " + mainObject.toString());
        JSONArray mainArray = mainObject.getJSONArray("objects");

        SparseArray<T> sparseArray = new SparseArray<T>();

        // parse each exercise of the JSON Array
        for (int i = 0; i < mainArray.length(); i++) {
            JSONObject singleObject = mainArray.getJSONObject(i);

            Integer id = singleObject.getInt("id");
            Object parsedObject;
            if (c.equals(Muscle.class)) {
                // handle Muscles
                String name = singleObject.getString("name");
                parsedObject = mDataProvider.getMuscleByName(name);

                if (parsedObject == null)
                    Log.e(TAG, "Could not find Muscle: " + name);

            } else if (c.equals(SportsEquipment.class)) {
                // handle SportsEquipment
                String name = singleObject.getString("name");
                parsedObject = mDataProvider.getEquipmentByName(name);

                if (parsedObject == null)
                    Log.e(TAG, "Could not find SportsEquipment: " + name);

            } else if (c.equals(Locale.class)) {
                // handle Locales
                String short_name = singleObject.getString("short_name");
                parsedObject = new Locale(short_name);

                if (short_name == null || short_name.equals(""))
                    Log.e(TAG, "Error, no short_name=" + short_name);

            } else if (c.equals(LicenseType.class)) {
                // handle licenses
                String short_name = singleObject.getString("short_name");

                parsedObject = mDataProvider.getLicenseTypeByName(short_name);

                if (short_name == null || short_name.equals(""))
                    Log.e(TAG, "Error, no short_name=" + short_name);

            } else {
                throw new IllegalStateException(
                        "parse(String, Class<T>) cannot be applied for class: " + c.toString());
            }

            sparseArray.put(id, (T) parsedObject);

        }

        return sparseArray;
    }

    /**
     * Returns the list with the new exercises.
     * 
     * 
     * @return A list containing all new exercises.
     */
    public ArrayList<ExerciseType> getNewExercises() {
        return new ArrayList<ExerciseType>(mNewExerciseList);
    }

    /**
     * Returns the list with the builder objects for the new exercises
     * 
     * 
     * @return A list containing all builder objects for the new exercises
     */
    public ArrayList<ExerciseType.Builder> getNewExercisesBuilder() {
        return new ArrayList<ExerciseType.Builder>(mNewExerciseBuilderList);
    }

}