aboutsummaryrefslogtreecommitdiff
path: root/src/main/ui/BrowserApp.java
blob: c4bbf998605c9a5d09c788373b5133de808b3a07 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
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
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
package ui;

import model.html.ElementNode;
import model.html.HtmlParser;
import model.html.TextNode;
import model.html.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<Node> parsed;
    private ArrayDeque<String> 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);
        }
    }

    /**
     * EFFECTS: Barebones HTML rendering. Iterates through a list of Nodes and their children and prints any text.
     */
    private void renderHtml(ArrayList<Node> 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<ArrayList<JSONObject>> jsonArray = new ArrayList<>();
        for (String p : tabs) {
            ArrayList<JSONObject> 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);
    }

}