package ui; import model.html.ElementNode; import model.html.HtmlParser; import model.html.TextNode; import model.util.Node; import org.json.JSONArray; import org.json.JSONObject; import persistance.JsonUtils; import java.io.File; import java.nio.file.*; import java.util.*; /** * The console interface to Apus. */ public class BrowserApp { private Scanner input; private static final String border = "==============================================="; private static final String storagePath = "data/apus.cache"; private String pathString; private ArrayList parsed; private ArrayDeque tabs; /** * EFFECTS: Renders an arbitrary HTML page and arbitrary HTML input. */ public BrowserApp() { println("apus: currently a barebones html/css renderer"); this.input = new Scanner(System.in); this.tabs = new ArrayDeque<>(); askToRestoreTabs(); mainLoop(); } /** * EFFECTS: Asks the user if they'd like to restore previously closed tabs. */ private void askToRestoreTabs() { if (new File(storagePath).length() > 2) { println("Would you like to restore your previously closed tabs? (Y/N)"); String answer; while (true) { answer = this.input.next(); if (answer.equalsIgnoreCase("y")) { restoreClosedTabs(); break; } else if (answer.equalsIgnoreCase("n")) { JsonUtils.writeToFile(new JSONArray(), storagePath); println("please provide a path to a file (examples located in data/*):"); pathString = this.input.next(); break; } else { println("Sorry, I didn't quite get that. Please try again."); } } } else { println("please provide a path to a file (examples located in data/*):"); pathString = this.input.next(); } } /** * EFFECTS: Runs the main loop */ private void mainLoop() { while (true) { try { Path path = Paths.get(pathString); String file = new String(Files.readAllBytes(path)); HtmlParser parser = new HtmlParser(); parsed = parser.parseHtml(file); println(border); renderHtml(parsed); println(border); println("Page rendered. Input additional commands if desired."); println("Impemented commands: newuri, newtab, nexttab, quit"); handleInput(this.input.next()); println(border); } catch (Exception e) { println("Reading from the file failed with " + e.toString()); println("Please try again."); } } } /** * EFFECTS: restores previous closed tabs from a cache file. */ private void restoreClosedTabs() { try { JSONArray state = JsonUtils.readFromFile(storagePath); for (int i = 0; i < state.length(); i++) { println(state.get(i).getClass().getName()); tabs.add((String) state.get(i)); } pathString = tabs.removeLast(); } catch (Exception e) { println("Restoring state from disk failed with " + e.toString()); System.exit(0); } } /* private void mainLoopII(ArrayList rawHtml, String border, HtmlParser parser) { while (true) { println("Page rendered. Input additional raw HTML if desired."); rawHtml.add(input.next()); println(border); for (String s : rawHtml) { parser = new HtmlParser(); renderHtml(parser.parseHtml(s)); } println(border); } }*/ /** * EFFECTS: Barebones HTML rendering. Iterates through a list of Nodes and their children and prints any text. */ private void renderHtml(ArrayList html) { for (Node node: html) { if (node instanceof TextNode) { println(node.getData()); } else { renderHtml(((ElementNode) node).getChildren()); } } } /** * EFFECTS: Handles user input after rendering an initial site */ private void handleInput(String input) { switch (input) { case "newuri": println("please provide a path to a file (examples located in data/*):"); pathString = this.input.next(); break; case "newtab": this.tabs.add(pathString); println("please provide a path to a file (examples located in data/*):"); pathString = this.input.next(); break; case "nexttab": this.tabs.add(pathString); pathString = this.tabs.removeFirst(); break; case "quit": handleQuit(); System.exit(0); break; default: println("Sorry, I didn't quite get that. Please try again."); break; } } /** * Helper function for the quit() case. * EFFECTS: Asks a user whether they'd like to save their tabs, and exists the program. */ private void handleQuit() { println("Would you like to save your currently opened tabs to disk? (Y/N)"); String answer; while (true) { answer = this.input.next(); if (answer.equalsIgnoreCase("y")) { this.tabs.add(pathString); JsonUtils.writeToFile(new JSONArray(tabs), storagePath); break; } else if (answer.equalsIgnoreCase("n")) { JsonUtils.writeToFile(new JSONArray(), storagePath); break; } else { println("Sorry, I didn't quite get that. Please try again."); } } } /** * EFFECTS: writes the current program configuration to the disk */ private void writeToDisk() { ArrayList> jsonArray = new ArrayList<>(); for (String p : tabs) { ArrayList jsonArrayII = new ArrayList<>(); try { Path path = Paths.get(pathString); String file = new String(Files.readAllBytes(path)); HtmlParser parser = new HtmlParser(); for (Node n : parser.parseHtml(file)) { jsonArrayII.add(n.serialize()); } } catch (Exception e) { System.out.printf("Failed to write to disk with %s", e); } jsonArray.add(jsonArrayII); } JsonUtils.writeToFile(new JSONArray(jsonArray), storagePath); } /** * EFFECTS: restores program state from a last written to state */ private void restoreFromDisk(JSONArray state) { for (int i = 0; i < state.length(); i++) { Object tab = state.get(i); if (tab instanceof JSONArray) { for (int j = 0; j < ((JSONArray) tab).length(); j++) { tabs.add(((JSONArray) tab).toString()); } } } } private void print(String toPrint) { System.out.print(toPrint); } private void println(String toPrint) { System.out.println(toPrint); } }