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;
}
}