package com.jonathan.survivor.managers; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.files.FileHandle; import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.Json; import com.jonathan.survivor.Profile; /* * Manages the profiles used by the user. Used to load profiles from the hard drive, create them and save them. Also used to access the current profile used by the * user, or any other profile the user has. */ public class ProfileManager { /** Stores the local file path for the profiles. Note that it ends with an underscore as it will be proceeded by "[id].json" */ private static final String FILE_PATH = "data/profile_"; /** Stores the amount of profiles created by the player in order to determine how many should be loaded from the hard drive. */ private int numProfiles; /** Stores an array of every profile that has been read by the ProfileManager to avoid re-reading JSON files. Note that the index into the profiles array for a * given profile is the same as to the profile's id.*/ private Array<Profile> profiles; /** Stores the current profile being used by the user. */ private Profile currentProfile; /** Creates a profile manager, specifying the maximum amount of profiles the user can hold. * @param amountProfiles Specifies how many profiles the manager will retrieve from the hard drive. Should correspond to amount of profiles the user has saved. */ public ProfileManager(int numProfiles) { //Stores the amount of profiles the manager has to load from the hard drive. this.numProfiles = numProfiles; //Creates a new container for the player's profiles, where each index corresponds to the ID of the profile. profiles = new Array<Profile>(); } /** Loads the profiles existing in the hard drive and populates the profiles:Profile[] array. */ public void loadProfiles() { //Cycles through the profiles array and populates it with any profiles which have already been created on the hard drive. for(int i = 0; i < numProfiles; i++) { //Retrieves the profile for the current index. Second argument specifies that we don't want to create a new profile if it doesn't //already exist on the hard drive. We only want to retrieve an already created profile. profiles.set(i, getProfile(i, false)); } } /** Returns the current profile being used by the user. The current profile is the last one that was retrieved from getProfile(profileId):Profile. * By default, if that method was never called, the last profile will be retrieved. */ public Profile getCurrentProfile() { //If there is no current profile, throw an exception. if(currentProfile == null) throw new IllegalArgumentException("No profile has been retrieved from the hard drive. Thus, cannot retrieve a profile using ProfileManager.getCurrentProfile()."); //Return the current profile being used by the user. return currentProfile; } /** Gets the profile with the given id, ranging from 0 to MAX_PROFILES-1. If the profile doesn't exist, it is not created nor saved to the hard drive. */ public Profile getProfile(int profileId) { //Returns the profile with the given id. Second argument specifies that we don't want to create a new profile and if it doesn't exist. return getProfile(profileId, false); } /** Gets the profile with the given id, ranging from 0 to MAX_PROFILES-1. Should be called after loadProfiles() to ensure that profiles have been loaded from * the hard drive. * * @param profileId The id of the profile, ranging from 0 to ProfileManager.MAX_PROFILES-1. * @param createNew If true, a new profile will be created if it doesn't exist on the hard drive. * @return The profile with the given ID */ public Profile getProfile(int profileId, boolean createNew) { //If the profile id is less than zero if(profileId < 0) throw new IllegalArgumentException("The profile with profileId: " + profileId + " cannot be retrieved because it is less than zero"); //If the profile id is greater than the last index of the profiles:Array<Profile> array, and the user doesn't want to create a new profile, throw an exception if(profileId >= numProfiles && !createNew) throw new IllegalArgumentException("The profile with profileId: " + profileId + " cannot be retrieved because it is greater than or equal to " + numProfiles); //If the profile has already been saved inside the profiles:Profile[] array if(profileId < profiles.size && profiles.get(profileId) != null) { //Get the profile from the profile array, and set it as the current profile being used by the user, since it was the last one read. currentProfile = profiles.get(profileId); //Return the profile with the given id passed as an argument. return currentProfile; } //Creates a fileHandle pointing to the path of the profile with the given ID. The profile will be saved in a .json file with a path of "FILE_PATH[id].json". FileHandle profileFile = Gdx.files.local(FILE_PATH + profileId + ".json"); //If the profile already exists on the hard drive, retrieve it and return it. if(profileFile.exists()) { try { //Creates a new Json object to convert the file into an object. Json json = new Json(); //Converts the entire profile file into a string. String text = profileFile.readString().trim(); //Converts the text into a Profile object using Json.fromJson(class, fileText):Profile. Stores the new profile as the current profile. currentProfile = json.fromJson(Profile.class, text); //Add the profile just created into the profiles array. profiles.insert(profileId, currentProfile); } catch(Exception ex) { ex.printStackTrace(); //If an exception arises, the profile's JSON file couldn't be read. So, create a new profile, effectively erasing the old one. createProfile(profileId); } } //Else, if the profile file doesn't not exist on the hard drive, we check 'createNew'. If this parameter is true, we want to create a new profile if it doesn't exist. else if(createNew) { //Create a new profile with the given ID which starts at the beginning of the game. createProfile(profileId); } //Returns the profile we either retrieved from the hard drive or created from scratch. return profiles.get(profileId); } /** Creates a profile with the given profile ID, and saves it to the hard drive. Also sets the created profile to be the current user profile. */ public Profile createProfile(int profileId) { //Create a new profile with the given id passed as a parameter. Sets it as the current profile being used by the user. currentProfile = new Profile(profileId); //Adds the created profile to the list of all profiles profiles.add(currentProfile); //Saves the profile we just created to the hard drive as a JSON file. saveProfile(profiles.get(profileId)); //Increments the amount of profiles the user has created. Note that this must be done since the user has created a new profile on the hard drive. numProfiles++; //Returns the created profile. return currentProfile; } /** Saves the profile to the hard drive. The file name depends on the ID of the profile passed as a parameter. */ public void saveProfile(Profile profile) { //If the profile we want to save is null, throw an exception. if(profile == null) throw new IllegalArgumentException("Attempting to save null Profile"); //Create a fileHandle pointing the file path containing the profile. This file path is: "FILE_PATH[id].json". We will write the profile to this path. FileHandle profileFile = Gdx.files.local(FILE_PATH + profile.getProfileId() + ".json"); //Creates a new Json object to convert a Profile object into JSON text. Json json = new Json(); //Converts the profile object into a string readable by JSON using Json.toJson(Serializable). String text = json.toJson(profile); //Writes the String containing the Profile object's information into the profile's JSON file, contained by profileFile:FileHandle. profileFile.writeString(text, false); } /** Saves the current profile to the hard drive as a JSON file. */ public void saveCurrentProfile() { //Saves the current profile to the hard drive as a JSON file. saveProfile(currentProfile); } /** Deletes a profile with the given ID from the hard drive. */ public void deleteProfile(int profileId) { //Get a file handle to the profile's JSON file. This is found under the path "FILE_PATH[profileId].json" FileHandle profileFile = Gdx.files.local(FILE_PATH + profileId + ".json"); //Delete the profile from the hard drive. profileFile.delete(); //Shifts the profiles from [profileId+1,numProfiles] to [profileId,numProfiles-1] to ensure that the empty spot from the deleted profile is filled. shiftProfiles(profileId); //Decrements the number of profiles stored in the ProfileManager. numProfiles--; } /** Shifts all the saved profiles from indices [profileId+1,numProfiles] to indices [profileId,numProfiles-1]. Called when the profile with the given * id is deleted to ensure that the empty spot from the deleted profile is filled. */ private void shiftProfiles(int profileId) { //Cycles from profileId+1 to numProfiles and rotates them to indices [profileId, numProfiles-1]. for(int i = profileId+1; i < numProfiles; i++) { //Get a file handle to the JSON file of profile with index i. We want to move it to the index i-1 to shift it to the left FileHandle oldProfileFile = Gdx.files.local(FILE_PATH + i + ".json"); //Stores the file path where profile i-1 should be saved. We want to move the profile with index i to this target file. FileHandle targetProfileFile = Gdx.files.local(FILE_PATH + (i-1) + ".json"); //Move the profile to its new target file, effectively shifting the profiles to the left on the hard drive. oldProfileFile.copyTo(targetProfileFile); //Delete the old profile which was shifted to the left by one file. oldProfileFile.delete(); //Retrieves the profile that has been shifted back one index Profile profile = profiles.get(i); //Update the profileId of the profile so that it shifts one value down. profile.setProfileId(i-1); //Shift the profile one index to the left in order to fill up the spot of the deleted profile. profiles.set(i-1, profile); //Save the profile on the hard drive, so that the profileId change gets recorded on the JSON file. saveProfile(profile); } //Remove the last profile in the profile array, since it contains a duplicate profile which was shifted to index 'numProfiles-2'. profiles.removeIndex(numProfiles-1); } /** Deletes all profiles from the hard drive, if they exist. */ public void deleteAllProfiles() { //Cycles through the profiles saved in the ProfileManager for(int id = 0; id < numProfiles; id++) { //Deletes the profiles deleteProfile(id); } } /** Returns true if the ProfileManager does not have any loaded profiles. */ public boolean isEmpty() { //Returns true if there are no profiles saved in the ProfileManager. return numProfiles == 0; } /** Gets the number of profiles the user has saved on the hard drive. */ public int getNumProfiles() { return numProfiles; } }