diff --git a/webui/src/main/js/search.js b/webui/src/main/js/search.js
new file mode 100644
index 00000000..52298f8c
--- /dev/null
+++ b/webui/src/main/js/search.js
@@ -0,0 +1,286 @@
+class SearchBySender {
+ constructor(xmlNode) {
+ this.uuid = xmlNode.getElementsByTagName("uuid")[0].childNodes[0].nodeValue;
+ this.query = xmlNode.getElementsByTagName("Query")[0].childNodes[0].nodeValue;
+ this.resultBatches = new Map();
+
+ var resultsBySender = xmlNode.getElementsByTagName("ResultsBySender")[0];
+ var resultsFromSenders = resultsBySender.getElementsByTagName("ResultsFromSender");
+ var i;
+ for (i = 0; i < resultsFromSenders.length; i++) {
+ var results = new ResultsBySender(resultsFromSenders[i]);
+ this.resultBatches.set(results.sender, results);
+ }
+ }
+}
+
+class SearchByFile {
+ constructor(xmlNode) {
+ this.uuid = xmlNode.getElementsByTagName("uuid")[0].childNodes[0].nodeValue;
+ this.query = xmlNode.getElementsByTagName("Query")[0].childNodes[0].nodeValue;
+ this.resultBatches = new Map();
+
+ var resultsByFile = xmlNode.getElementsByTagName("ResultsByFile")[0];
+ var resultsForFile = resultsByFile.getElementsByTagName("ResultsForFile");
+ var i;
+ for (i = 0; i < resultsForFile.length; i++) {
+ var results = new ResultsByFile(resultsForFile[i]);
+ this.resultBatches.set(results.infoHash, results);
+ }
+ }
+}
+
+class ResultsBySender {
+ constructor(xmlNode) {
+ this.sender = xmlNode.getElementsByTagName("Sender")[0].childNodes[0].nodeValue;
+ this.results = [];
+ var resultNodes = xmlNode.getElementsByTagName("Result");
+ var i;
+ for (i = 0 ; i < resultNodes.length; i ++) {
+ var result = new ResultBySender(resultNodes[i]);
+ this.results.push(result);
+ }
+ }
+}
+
+class ResultsByFile {
+ constructor(xmlNode) {
+ this.name = xmlNode.getElementsByTagName("Name")[0].childNodes[0].nodeValue;
+ this.infoHash = xmlNode.getElementsByTagName("InfoHash")[0].childNodes[0].nodeValue;
+ this.size = xmlNode.getElementsByTagName("Size")[0].childNodes[0].nodeValue;
+ this.results = [];
+ var resultNodes = xmlNode.getElementsByTagName("Result");
+ var i;
+ for (i = 0; i < resultNodes.length; i++) {
+ var result = new ResultByFile(resultNodes[i]);
+ this.results.push(result);
+ }
+ }
+}
+
+class ResultBySender {
+ constructor(xmlNode) {
+ this.name = xmlNode.getElementsByTagName("Name")[0].childNodes[0].nodeValue;
+ this.size = xmlNode.getElementsByTagName("Size")[0].childNodes[0].nodeValue;
+ this.infoHash = xmlNode.getElementsByTagName("InfoHash")[0].childNodes[0].nodeValue;
+ }
+}
+
+class ResultByFile {
+ constructor(xmlNode) {
+ this.sender = xmlNode.getElementsByTagName("Sender")[0].childNodes[0].nodeValue;
+ }
+}
+
+var searches = new Map();
+
+var uuid = null;
+var sender = null;
+var lastXML = null;
+var infoHash = null;
+
+function updateSender(senderName) {
+ sender = senderName;
+
+ var resultsFromSpan = document.getElementById("resultsFrom");
+ resultsFromSpan.innerHTML = "Results From "+sender;
+
+ var resultsDiv = document.getElementById("bottomTable");
+ var table = "
| Name | Size | Download |
"
+ var x = searches.get(uuid)
+ x = x.resultBatches.get(sender).results;
+ var i;
+ for (i = 0; i < x.length; i++) {
+ table += "";
+ table += "| ";
+ table += x[i].name;
+ table += " | ";
+ table += "";
+ table += x[i].size;
+ table += " | ";
+ table += "";
+ table += "";
+ table += " | ";
+ table += "
";
+ }
+ table += "
";
+ if (x.length > 0)
+ resultsDiv.innerHTML = table;
+}
+
+function updateFile(fileInfoHash) {
+ infoHash = fileInfoHash;
+
+ var searchResults = searches.get(uuid).resultBatches.get(infoHash);
+
+ var resultsFromSpan = document.getElementById("resultsFrom");
+ resultsFromSpan.innerHTML = "Results For "+searchResults.name;
+
+ var resultsDiv = document.getElementById("bottomTable");
+ var table = "| Sender |
";
+ var i;
+ for (i = 0; i < searchResults.results.length; i++) {
+ table += "";
+ table += "| ";
+ table += searchResults.results[i].sender;
+ table += " | ";
+ table += "
";
+ }
+ table += "
";
+ if (searchResults.results.length > 0)
+ resultsDiv.innerHTML = table;
+}
+
+function updateUUIDBySender(resultUUID) {
+ uuid = resultUUID;
+
+ var currentSearchSpan = document.getElementById("currentSearch");
+ currentSearchSpan.innerHTML = searches.get(uuid).query + " Results";
+
+ var sendersDiv = document.getElementById("topTable");
+ var table = "";
+ if (x.size > 0)
+ sendersDiv.innerHTML = table;
+ if (sender != null)
+ updateSender(sender);
+}
+
+function updateUUIDByFile(resultUUID) {
+ uuid = resultUUID;
+
+ var currentSearchSpan = document.getElementById("currentSearch");
+ currentSearchSpan.innerHTML = searches.get(uuid).query + " Results";
+
+ var topTableDiv = document.getElementById("topTable");
+ var table = "| Name | Size | Download |
";
+ var x = searches.get(uuid).resultBatches;
+ for (var [fileInfoHash, file] of x) {
+ table += "| ";
+ table += file.name;
+ table += " | ";
+ table += "";
+ table += file.size;
+ table += " | ";
+ table += "";
+ table += "";
+ table += " |
";
+ }
+ table += "
";
+ if (x.size > 0)
+ topTableDiv.innerHTML = table;
+ if (infoHash != null)
+ updateFile(infoHash);
+}
+
+function refreshGroupBySender() {
+ var xmlhttp = new XMLHttpRequest();
+ xmlhttp.onreadystatechange = function () {
+ if (this.readyState == 4 && this.status == 200) {
+ var xmlDoc = this.responseXML;
+ lastXML = xmlDoc;
+ searches.clear();
+ var i;
+ var x = xmlDoc.getElementsByTagName("Search");
+ for (i = 0; i < x.length; i++) {
+ var search = new SearchBySender(x[i]);
+ searches.set(search.uuid, search);
+ }
+
+ var table = "| Search | Senders | Results |
";
+ var activeSearchesDiv = document.getElementById("activeSearches");
+ for (var [resultsUUID, search] of searches) {
+ table += "| "
+ table += search.query;
+ table += " | ";
+ table += ""
+ table += search.resultBatches.size;
+ table += " | ";
+
+ var map = new Map();
+ for ( var [sender, results] of search.resultBatches ) {
+ results.results.forEach(result => map.set(result.infoHash, 1));
+ }
+ table += "";
+ table += map.size;
+ table += " | "
+ table += "
"
+ }
+ table += "
"
+ if (x.length > 0)
+ activeSearchesDiv.innerHTML = table;
+ if (uuid != null)
+ updateUUIDBySender(uuid);
+
+ }
+ }
+ xmlhttp.open("GET", "/MuWire/Search?section=groupBySender", true);
+ xmlhttp.send();
+}
+
+function refreshGroupByFile() {
+ var xmlhttp = new XMLHttpRequest();
+ xmlhttp.onreadystatechange = function () {
+ if (this.readyState == 4 && this.status == 200) {
+ var xmlDoc = this.responseXML;
+ lastXML = xmlDoc;
+ searches.clear();
+ var i;
+ var x = xmlDoc.getElementsByTagName("Search");
+ for (i = 0; i < x.length; i++) {
+ var search = new SearchByFile(x[i]);
+ searches.set(search.uuid, search);
+ }
+
+ var table = "| Search | Senders | Results |
";
+ var activeSearchesDiv = document.getElementById("activeSearches");
+ for (var [resultsUUID, search] of searches) {
+ table += "| "
+ table += search.query;
+ table += " | ";
+
+ var map = new Map()
+ for (var [fileInfoHash, result] of search.resultBatches) {
+ result.results.forEach(sender => map.set(sender.sender, 1));
+ }
+ table += ""
+ table += map.size;
+ table += " | ";
+
+
+ table += "";
+ table += search.resultBatches.size;
+ table += " | "
+ table += "
"
+ }
+ table += "
"
+ if (x.length > 0)
+ activeSearchesDiv.innerHTML = table;
+ if (uuid != null)
+ updateUUIDByFile(uuid);
+
+ }
+ }
+ xmlhttp.open("GET", "/MuWire/Search?section=groupByFile", true);
+ xmlhttp.send();
+}
+
+function initGroupBySender() {
+ setInterval(refreshGroupBySender, 3000);
+ setTimeout(refreshGroupBySender, 1);
+}
+
+function initGroupByFile() {
+ setInterval(refreshGroupByFile, 3000);
+ setTimeout(refreshGroupByFile, 1);
+}
\ No newline at end of file
diff --git a/webui/src/main/webapp/Home.jsp b/webui/src/main/webapp/Home.jsp
index 59734f0f..6619e779 100644
--- a/webui/src/main/webapp/Home.jsp
+++ b/webui/src/main/webapp/Home.jsp
@@ -20,11 +20,13 @@
<%@include file="css.jsi"%>
-
+
<%@include file="header.jsi"%>
<% if (groupBy.equals("sender")) { %>
+
Group By File
<% } else { %>
+
Group By Sender
<% } %>
-
-