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)) {
recipeManager = deserializeRecipeManager(recipeFolder, ingredientManager);

Karsch Lukas
committed
} 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)) {
String fileContentCategories = Files.readString(toCategoryJson);
categoryManager = deserializeCategoryManager(fileContentCategories);
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)) {
String fileContentMealPlan = Files.readString(toMealPlanJson);
mealPlan = deserializeMealPlan(fileContentMealPlan, recipeManager);
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)) {
String fileContentShoppingList = Files.readString(toShoppingListJson);
shoppingList = deserializeShoppingList(fileContentShoppingList);
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(Path path, IngredientManager ingredientManager) throws IOException {

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

Karsch Lukas
committed
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(String json) {
if (json.isBlank()) return new CategoryManager();
Gson gson = new GsonBuilder().registerTypeAdapter(CategoryManager.class, new CategoryManagerTypeAdapter()).create();
return gson.fromJson(json, CategoryManager.class);

Karsch Lukas
committed
}
private static MealPlan deserializeMealPlan(String json, RecipeManager recipeManager) {
if (json.isBlank()) return new MealPlan(recipeManager);
Gson gson = new GsonBuilder()
.registerTypeAdapter(MealPlan.class, new MealPlanTypeAdapter(recipeManager))
.create();
return gson.fromJson(json, MealPlan.class);

Karsch Lukas
committed
}
private static ShoppingList deserializeShoppingList(String json) {
if (json.isBlank()) return new ShoppingList();
Gson gson = new GsonBuilder()
.registerTypeAdapter(ShoppingList.class, new ShoppingListTypeAdapter())
.create();
return gson.fromJson(json, ShoppingList.class);

Karsch Lukas
committed
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
196
}
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();