More work on GUI

Change-Id: I824bf8f431117b404ea351f47aeb136db10d902a
diff --git a/gui/html/chronoshare.js b/gui/html/chronoshare.js
index c8b8ae0..fcd0bd4 100644
--- a/gui/html/chronoshare.js
+++ b/gui/html/chronoshare.js
@@ -1,5 +1,77 @@
+// var PAGE = "fileList";
+// var PARAMS = [ ];
+// var URIPARAMS = "";
+
+// $(document).ready (function () {
+//     function nav_anchor (aurl) {
+//         aurl = aurl.split('#');
+//         if (aurl[1])
+//         {
+//             aurl_split = aurl[1].split ('?');
+//             page = aurl_split[0];
+
+//             vars = [ ];
+//             if (aurl_split[1]) {
+//                 var hashes = aurl_split[1].slice (aurl_split[1].indexOf ('?') + 1).split ('&');
+//                 for(var i = 0; i < hashes.length; i++)
+//                 {
+//                     hash = hashes[i].split('=');
+//                     vars.push(hash[0]);
+//                     vars[hash[0]] = hash[1];
+//                 }
+//             }
+
+//                 // alert (aurl_split[1]);
+
+//             if (page != PAGE)
+//             {
+//                 alert (page);
+//                 PAGE = page;
+//                 PARAMS = vars;
+//                 URIPARAMS = aurl_split[1];
+//                 alert (URIPARAMS);
+//             }
+//             else if (aurl_split[1] != URIPARAMS)
+//             {
+//                 alert (aurl_split[1]);
+//             }
+//         }
+//     }
+
+//     nav_anchor (window.location.href);
+
+//     $("a").click (function(){
+//         nav_anchor (this.href)
+//     });
+// });
+
+/**
+ * @brief Convert binary data represented as non-escaped hex string to Uint8Array
+ * @param str String like ba0cb43e4b9639c114a0487d5faa7c70452533963fc8beb37d1b67c09a48a21d
+ *
+ * Note that if string length is odd, null will be returned
+ */
+StringHashToUint8Array = function (str) {
+    if (str.length % 2 != 0) {
+        return null;
+    }
+
+    var buf = new Uint8Array (str.length / 2);
+
+    for (var i = 0; i < str.length; i+=2) {
+        value = parseInt (str.substring (i, i+2), 16);
+        buf[i/2] = value;
+    }
+
+    return buf;
+};
+
 
 $.Class ("FilesClosure", {}, {
+    init: function (chronoshare) {
+        this.chronoshare = chronoshare;
+    },
+
     upcall: function(kind, upcallInfo) {
         $("#loader").fadeOut (500); // ("hidden");
         if (kind == Closure.UPCALL_CONTENT) {
@@ -9,21 +81,36 @@
             data = JSON.parse (convertedData);
 
             // error handling?
-            // if (data.files instanceof Array) {
-            //     alert (data.files);
-            // }
 
             var html = $("tbody#files");
             for (var i = 0; i < data.files.length; i++) {
                 file = data.files[i];
-                html = html.append ([
-                    "<tr"+(i%2?" class=\"odd\"":"")+">",
-                    "<td class=\"border-left\">" + file.filename + "</td>",
-                    "<td>" + file.version + "</td>",
-                    "<td>" + file.timestamp + "</td>",
-                    "<td class=\"border-right\">" + "</td>",
-                    "</tr>"
-                ].join());
+
+		row = $("<tr />");
+		if (i%2) { row.addClass ("odd"); }
+
+                row.bind('mouseenter mouseleave', function() {
+                    $(this).toggleClass('highlighted');
+                });
+
+                fileHistoryUrl = new Name ()
+                    .add (this.chronoshare.actions)
+                    .add (file.filename)
+                    .add ("nonce")
+                    .addSegment (0);
+                // row.attr ("history", fileHistoryUrl.to_uri ());
+                row.bind('click', function () {
+                    // alert (fileHistoryUrl.to_uri ());
+                });
+
+		row.append ($("<td />", {"class": "border-left"}).text (file.filename));
+		row.append ($("<td />").text (file.version));
+		row.append ($("<td />").text (new Date (file.timestamp)));
+		row.append ($("<td />")
+			    .append ($("<userName />").text (file.owner.userName))
+			    .append ($("<seqNo> /").text (file.owner.seqNo)));
+
+		html = html.append (row);
             }
         }
         else if (kind == Closure.UPCALL_INTEREST_TIMED_OUT) {
@@ -33,7 +120,6 @@
         else {
             $("#error").html ("Unknown error happened");
             $("#error").removeClass ("hidden");
-            // some kind of error
         }
     }
 });
@@ -45,117 +131,22 @@
          this.username = new Name (username);
          this.files = new Name ("/localhost").add (this.username).add ("chronoshare").add (foldername).add ("info").add ("files").add ("folder");
 
-         this.actions = new Name ("/localhost").add (this.username).add ("chronoshare").add (foldername).add ("info").add ("actions").add ("folder");
+         this.actions = new Name ("/localhost").add (this.username).add ("chronoshare").add (foldername).add ("info").add ("actions").add ("file");
 
          this.restore = new Name ("/localhost").add (this.username).add ("chronoshare").add (foldername).add ("cmd").add ("restore").add ("file");
 
-         this.ndn = new NDN ({host:"127.0.0.1", getHostAndPort: function() { return {host: "127.0.0.1", port: 9696}}});
-         // this.ndn.transport.connect (this.ndn);
+         // this.ndn = new NDN ({host:"127.0.0.1", getHostAndPort: function() { return {host: "127.0.0.1", port: 9696}}});
+         this.ndn = new NDN ({host:"127.0.0.1"});
      },
 
+
      run: function () {
          request = new Name ().add (this.files)./*add (folder_in_question).*/add ("nonce").addSegment (0);
          console.log (request.to_uri ());
          $("#files").empty ();
-         // $("#loader").removeClass ("hidden");
          $("#loader").fadeIn (500);
-         this.ndn.expressInterest (request, new FilesClosure ());
+         this.ndn.expressInterest (request, new FilesClosure (this));
      }
-// ,
-
-     // sendRequest: function () {
-     //     alert ('bla');
-     // }
  });
 
 
-// $.Class ("onFiles",
-//  {
-//  },
-
-//  {
-//      upcall: function(kind, upcallInfo, tmp) {
-//          if (kind
-//      }
-//  });
-
-// var AsyncGetClosure = function AsyncGetClosure() {
-//     Closure.call(this);
-// };
-
-// AsyncGetClosure.prototype.upcall = function(kind, upcallInfo, tmp) {
-//     if (kind == Closure.UPCALL_FINAL) {
-//         // Do nothing.
-//     } else if (kind == Closure.UPCALL_CONTENT) {
-//         var content = upcallInfo.contentObject;
-// 	var nameStr = content.name.getName().split("/").slice(5,6);
-
-// 	if (nameStr == "prefix") {
-// 	    document.getElementById('prefixcontent').innerHTML = DataUtils.toString(content.content);
-// 	    prefix();
-// 	} else if (nameStr == "link") {
-// 	    document.getElementById('linkcontent').innerHTML = DataUtils.toString(content.content);
-// 	    link();
-// 	} else {
-// 	    var data = DataUtils.toString(content.content);
-// 	    var obj = jQuery.parseJSON(data);
-// 	    document.getElementById("lastupdated").innerHTML = obj.lastupdated;
-// 	    document.getElementById("lastlog").innerHTML = obj.lastlog;
-// 	    document.getElementById("lasttimestamp").innerHTML = obj.lasttimestamp;
-// 	}
-//     } else if (kind == Closure.UPCALL_INTEREST_TIMED_OUT) {
-//         console.log("Closure.upcall called with interest time out.");
-//     }
-//     return Closure.RESULT_OK;
-// };
-
-// function getStatus(name) {
-//     // Template interest to get the latest content.
-//     var interest = new Interest("/tmp/");
-//     interest.childSelector = 1;
-//     interest.interestLifetime = 4000;
-
-//     ndn.expressInterest(new Name("/ndn/memphis.edu/netlab/status/" + name), new AsyncGetClosure(), interest);
-// }
-
-// // Calls to get the content data.
-// function begin() {
-//     getStatus("metadata");
-//     getStatus("prefix");
-//     getStatus("link");
-// }
-
-// var ndn;
-// $(document).ready(function() {
-//     $("#all").fadeIn(500);
-//     var res = detect();
-
-//     if (!res) {
-// 	$("#base").fadeOut(50);
-// 	$("#nosupport").fadeIn(500);
-//     } else {
-//         //$("#all").fadeIn(500);
-
-//         $.get("test.php", function() {
-// 	    openHandle = function() { begin() };
-//             ndn = new NDN({host:hostip, onopen:openHandle});
-//             ndn.transport.connectWebSocket(ndn);
-// 	    $("#base").fadeOut(500, function () {
-//                 $("#status").fadeIn(1000);
-//             });
-//         });
-//     }
-// });
-
-// $("#continue").click(function() {
-//     $("#nosupport").fadeOut(50);
-//     $("#base").fadeIn(500);
-//     $.get("test.php", function() {
-//         openHandle = function() { begin() };
-//         ndn = new NDN({host:hostip, onopen:openHandle});
-//         ndn.transport.connectWebSocket(ndn);
-//         $("#base").fadeOut(500, function () {
-//             $("#status").fadeIn(1000);
-//         });
-//     });
-// });
diff --git a/gui/html/index.html b/gui/html/index.html
index 21842a8..66f039f 100644
--- a/gui/html/index.html
+++ b/gui/html/index.html
@@ -22,8 +22,8 @@
 
       <nav>
         <ul>
-          <li><a href="#files">File list</a></li>
-          <li><a href="#history">History</a></li>
+          <li><a href="#fileList">File list</a></li>
+          <li><a href="#fileHistory?x=1">History</a></li>
         </ul>
       </nav>
     </header>
diff --git a/gui/html/style.css b/gui/html/style.css
index 198e2ef..a4a4a03 100644
--- a/gui/html/style.css
+++ b/gui/html/style.css
@@ -181,6 +181,11 @@
     background-color: #eeeeee;

 }

 

+.highlighted {

+    background-color: #cccccc;

+    cursor: pointer;

+}

+

 .filename {

     width: 50%;

 }

@@ -207,3 +212,13 @@
     margin-top: -64px; /* Half the height */

     margin-left: -64px; /* Half the width */

 }

+

+userName {

+    display: inline-block;

+    /* ? how format user name? */

+}

+

+seqNo {

+    display: inline-block;

+    margin-left: 5px;

+}
\ No newline at end of file
diff --git a/server/mime_types.cpp b/server/mime_types.cpp
index eb86fdf..a2d0b15 100644
--- a/server/mime_types.cpp
+++ b/server/mime_types.cpp
@@ -24,6 +24,7 @@
   { "htm", "text/html" },
   { "html", "text/html" },
   { "css", "text/css" },
+  { "js", "text/javascript" },
   { "jpg", "image/jpeg" },
   { "png", "image/png" },
   { 0, 0 } // Marks end of list.
diff --git a/src/state-server.cc b/src/state-server.cc
index e70b891..48b63de 100644
--- a/src/state-server.cc
+++ b/src/state-server.cc
@@ -164,7 +164,7 @@
 
   json.push_back (Pair ("id", id));
 
-  json.push_back (Pair ("timestamp", to_iso_string (from_time_t (action.timestamp ()))));
+  json.push_back (Pair ("timestamp", to_iso_extended_string (from_time_t (action.timestamp ()))));
   json.push_back (Pair ("filename",  action.filename ()));
   json.push_back (Pair ("action", (action.action () == 0) ? "UPDATE" : "DELETE"));
 
@@ -172,7 +172,7 @@
     {
       Object update;
       update.push_back (Pair ("hash", boost::lexical_cast<string> (Hash (action.file_hash ().c_str (), action.file_hash ().size ()))));
-      update.push_back (Pair ("timestamp", to_iso_string (from_time_t (action.mtime ()))));
+      update.push_back (Pair ("timestamp", to_iso_extended_string (from_time_t (action.mtime ()))));
 
       ostringstream chmod;
       chmod << setbase (8) << setfill ('0') << setw (4) << action.mode ();
@@ -304,7 +304,7 @@
   }
 
   json.push_back (Pair ("hash", boost::lexical_cast<string> (Hash (file.file_hash ().c_str (), file.file_hash ().size ()))));
-  json.push_back (Pair ("timestamp", to_iso_string (from_time_t (file.mtime ()))));
+  json.push_back (Pair ("timestamp", to_iso_extended_string (from_time_t (file.mtime ()))));
 
   ostringstream chmod;
   chmod << setbase (8) << setfill ('0') << setw (4) << file.mode ();