Newer
Older

Karsch Lukas
committed
package mi.hdm.filesystem;

Karsch Lukas
committed
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

Karsch Lukas
committed
import mi.hdm.TastyPages;

Karsch Lukas
committed
import mi.hdm.mealPlan.MealPlan;
import mi.hdm.recipes.*;
import mi.hdm.shoppingList.ShoppingList;
import mi.hdm.typeAdapters.CategoryManagerTypeAdapter;
import mi.hdm.typeAdapters.MealPlanTypeAdapter;

Karsch Lukas
committed
import mi.hdm.typeAdapters.RecipeTypeAdapter;

Karsch Lukas
committed
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

Karsch Lukas
committed

Karsch Lukas
committed
import java.io.IOException;
import java.math.BigDecimal;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.Map;

Karsch Lukas
committed
import java.util.stream.Stream;
/**
* Containing methods to serialize and deserialize parts of the app content for saving to / loading from the filesystem
*/

Karsch Lukas
committed
public class FileManager {

Karsch Lukas
committed
private final static String PATH_TO_DEFAULT_INGREDIENTS = "/data/nutrition.csv";
private final static String PATH_TO_USER_DATA = System.getProperty("user.home") + "\\AppData\\Roaming\\TastyPages";
private final static Logger log = LogManager.getLogger(FileManager.class);
public static void serializeToFile(TastyPages app) {

Karsch Lukas
committed
}
@SuppressWarnings("ResultOfMethodCallIgnored")
public static TastyPages deserializeFromFilesystem() throws IOException, URISyntaxException { //TODO: if this fails, log.fatal and System.exit

Karsch Lukas
committed
log.info("Trying to read {}", PATH_TO_USER_DATA);
Path userPath = Path.of(PATH_TO_USER_DATA);
if (userPath.toFile().mkdirs()) { //If .mkdirs() returns true, that means the folder has not existed before -> in this case, only load default ingredients!
log.info("TastyPages folder has been created at {}", userPath);
IngredientManager deserializedIngredientManager = deserializeIngredientManager(getAbsolutePathFromResourceFolder());

Karsch Lukas
committed
return new TastyPages(deserializedIngredientManager);
} else { //otherwise, read user data
log.info("Found TastyPages folder at {}, loading user data from there.", userPath);
IngredientManager ingredientManager;
RecipeManager recipeManager;
CategoryManager categoryManager;
MealPlan mealPlan;
ShoppingList shoppingList;
//TODO: turn these paths into static variables?
Path toIngredients = Path.of(userPath + "/ingredients.csv");
if (Files.exists(toIngredients)) {
log.info("Loading ingredients from {}", toIngredients);

Karsch Lukas
committed
ingredientManager = deserializeIngredientManager(PATH_TO_USER_DATA);
} else {
log.info("Could not find /ingredients.csv, falling back to default ingredients.");
ingredientManager = deserializeIngredientManager(getAbsolutePathFromResourceFolder());

Karsch Lukas
committed
}
Path recipeFolder = Path.of(userPath + "/recipes");
if (Files.exists(recipeFolder) && Files.isDirectory(recipeFolder)) {

Karsch Lukas
committed
recipeManager = deserializeRecipeManager(PATH_TO_USER_DATA + "/recipes", ingredientManager);
} else {
log.info("Could not find recipe folder, creating empty instance of RecipeManger");

Karsch Lukas
committed
recipeFolder.toFile().mkdir();
recipeManager = new RecipeManager();
}
Path toCategoryJson = Path.of(userPath + "/categories.json");
if (Files.exists(toCategoryJson) && Files.isRegularFile(toCategoryJson)) {
categoryManager = deserializeCategoryManager(toCategoryJson);
} else {
log.info("Could not find /categories.json, creating empty instance of CategoryManager");
toCategoryJson.toFile().createNewFile();
categoryManager = new CategoryManager();
}
Path toMealPlanJson = Path.of(userPath + "/mealplan.json");
if (Files.exists(toMealPlanJson) && Files.isRegularFile(toMealPlanJson)) {
mealPlan = deserializeMealPlan(toMealPlanJson, recipeManager);
} else {
log.info("Could not find /mealplan.json, creating empty instance of MealPlan");
toMealPlanJson.toFile().createNewFile();
Path toShoppingListJson = Path.of(userPath + "/shoppingList.json");
if (Files.exists(toShoppingListJson) && Files.isRegularFile(toShoppingListJson)) {
shoppingList = deserializeShoppingList(toShoppingListJson);
} else {
log.info("Could not find /shoppingList.json, creating empty shopping list");
toShoppingListJson.toFile().createNewFile();
return new TastyPages(recipeManager, ingredientManager, categoryManager, mealPlan, shoppingList);

Karsch Lukas
committed
}

Karsch Lukas
committed
}

Karsch Lukas
committed
private static IngredientManager deserializeIngredientManager(String path) throws IOException {
CSVParser parser = new CSVParser();
List<Ingredient> ingredients = parser.getIngredientsFromCSV(
path,
',',
"name", "calories", "carbohydrate", "fat", "protein", "fiber", "sodium"
);
return new IngredientManager(ingredients);
}
private static RecipeManager deserializeRecipeManager(String path, IngredientManager ingredientManager) throws IOException {

Karsch Lukas
committed
Path recipePath = Path.of(path);
List<Path> recipePaths;

Karsch Lukas
committed
try (Stream<Path> stream = Files.list(recipePath)) { //TODO: catch clause
recipePaths = stream.toList();
}

Karsch Lukas
committed
.map(p -> {
try {
return Files.readString(p);
} catch (IOException e) {
e.printStackTrace();
log.error("Could not read file contents for {}. Check file permissions and content", p);

Karsch Lukas
committed
}
})
.filter(Objects::nonNull)
.map(json -> JSONtoRecipe(json, ingredientManager))

Karsch Lukas
committed
.toList();
return new RecipeManager(recipes);
}
private static CategoryManager deserializeCategoryManager(Path path) throws IOException {
log.info("Reading categories from {}", path);
Gson gson = new GsonBuilder().registerTypeAdapter(CategoryManager.class, new CategoryManagerTypeAdapter()).create();
String fileContent = Files.readString(path);
return gson.fromJson(fileContent, CategoryManager.class);

Karsch Lukas
committed
}
private static MealPlan deserializeMealPlan(Path filepath, RecipeManager recipeManager) throws IOException {
Gson gson = new GsonBuilder()
.registerTypeAdapter(MealPlan.class, new MealPlanTypeAdapter(recipeManager))
.create();
String fileContent = Files.readString(filepath);
return gson.fromJson(fileContent, MealPlan.class);

Karsch Lukas
committed
}
private static ShoppingList deserializeShoppingList(Path filepath) throws IOException {
Gson gson = new GsonBuilder()
.registerTypeAdapter(ShoppingList.class, new ShoppingListTypeAdapter())
.create();
String fileContent = Files.readString(filepath);

Karsch Lukas
committed
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
}
private static String recipeToJSON(Recipe recipe, IngredientManager ingredientManager) {
Gson gson = new GsonBuilder()
.registerTypeAdapter(Recipe.class, new RecipeTypeAdapter(ingredientManager))
.create();
return gson.toJson(recipe);
}
/**
* Used to convert an ingredient into a CSV String seperated by comma
*
* @return a comma seperated String containing the name of the ingredient as well as the contents of its nutrition table
*/
private static String ingredientToCSV(Ingredient ingredient) {
//"name", "calories", "carbohydrate", "fat", "protein", "fiber", "sodium"
Map<Nutrition, BigDecimal> map = ingredient.getNutritionTable().getTable();
return String.format(
"%s, %f, %f, %f, %f, %f, %f%n",
ingredient.getName(),
map.get(Nutrition.CALORIES).doubleValue(),
map.get(Nutrition.CARBS).doubleValue(),
map.get(Nutrition.FAT).doubleValue(),
map.get(Nutrition.PROTEINS).doubleValue(),
map.get(Nutrition.FIBERS).doubleValue(),
map.get(Nutrition.SALT).doubleValue()
);
}
private static Recipe JSONtoRecipe(String json, IngredientManager ingredientManager) {
Gson gson = new GsonBuilder().registerTypeAdapter(Recipe.class, new RecipeTypeAdapter(ingredientManager)).create();
return gson.fromJson(json, Recipe.class);

Karsch Lukas
committed
}
private static String getAbsolutePathFromResourceFolder() throws URISyntaxException {
URL resourceUrl = FileManager.class.getResource(FileManager.PATH_TO_DEFAULT_INGREDIENTS);

Karsch Lukas
committed
assert resourceUrl != null;
Path path = Paths.get(resourceUrl.toURI());
return path.toFile().getAbsolutePath();