Enhancing YANG GUI with information on YANG models.

Change-Id: I0441279cd3fdc97d55bc2874055fcc621ef07382
diff --git a/apps/yang-gui/src/main/java/org/onosproject/yang/gui/YangModelMessageHandler.java b/apps/yang-gui/src/main/java/org/onosproject/yang/gui/YangModelMessageHandler.java
index 5639903..d315c22 100644
--- a/apps/yang-gui/src/main/java/org/onosproject/yang/gui/YangModelMessageHandler.java
+++ b/apps/yang-gui/src/main/java/org/onosproject/yang/gui/YangModelMessageHandler.java
@@ -16,6 +16,7 @@
 
 package org.onosproject.yang.gui;
 
+import com.fasterxml.jackson.databind.node.ArrayNode;
 import com.fasterxml.jackson.databind.node.ObjectNode;
 import com.google.common.collect.ImmutableSet;
 import org.onlab.osgi.ServiceDirectory;
@@ -82,7 +83,6 @@
         );
     }
 
-
     // Handler for table requests
     private final class TableDataHandler extends TableRequestHandler {
         private static final String NO_ROWS_MESSAGE = "No YANG Models found";
@@ -126,20 +126,32 @@
         @Override
         public void process(ObjectNode payload) {
             String id = string(payload, ID);
-
-            // TODO: retrieve the appropriate model from ymsService and create
-            //       a detail record to send back to the client.
+            YangModel model = getModel(id);
 
             ObjectNode data = objectNode();
-
             data.put(ID, id);
-            data.put(MODULES, "some-type");
-            data.put("todo", "fill out with appropriate date attributes");
+
+            if (model != null) {
+                ArrayNode modules = arrayNode();
+                model.getYangModulesId().forEach(mid -> {
+                    ObjectNode module = objectNode();
+                    module.put("name", mid.moduleName());
+                    module.put("revision", mid.revision());
+                    modules.add(module);
+                });
+                data.set(MODULES, modules);
+            }
 
             ObjectNode rootNode = objectNode();
             rootNode.set(DETAILS, data);
-
             sendMessage(DETAILS_RESP, rootNode);
         }
     }
+
+    private YangModel getModel(String id) {
+        int nid = Integer.parseInt(id);
+        return modelRegistry.getModels().stream()
+                .filter(m -> m.getYangModulesId().hashCode() == nid)
+                .findFirst().orElse(null);
+    }
 }
diff --git a/apps/yang-gui/src/main/resources/app/view/yangModel/yangModel.css b/apps/yang-gui/src/main/resources/app/view/yangModel/yangModel.css
index f8e9d01..18a60e6 100644
--- a/apps/yang-gui/src/main/resources/app/view/yangModel/yangModel.css
+++ b/apps/yang-gui/src/main/resources/app/view/yangModel/yangModel.css
@@ -40,13 +40,28 @@
     cursor: pointer;
 }
 
+#yang-model-details-panel .dev-icon {
+    display: inline-block;
+    padding: 0 6px 0 0;
+    vertical-align: middle;
+}
+
 #yang-model-details-panel h2 {
     display: inline-block;
     margin: 8px 0;
 }
 
-
-#yang-model-details-panel .data {
+#yang-model-details-panel .top-content table {
     font-size: 12pt;
 }
 
+#yang-model-details-panel td.label {
+    font-weight: bold;
+    padding-right: 6px;
+    text-align: left;
+}
+
+#yang-model-details-panel th {
+    text-align: left;
+    padding-right: 16px;
+}
diff --git a/apps/yang-gui/src/main/resources/app/view/yangModel/yangModel.js b/apps/yang-gui/src/main/resources/app/view/yangModel/yangModel.js
index 930dc6d..a8a4ac1 100644
--- a/apps/yang-gui/src/main/resources/app/view/yangModel/yangModel.js
+++ b/apps/yang-gui/src/main/resources/app/view/yangModel/yangModel.js
@@ -26,7 +26,10 @@
 
     // constants
     var topPdg = 28,
-        pWidth = 800;
+        ctnrPdg = 24,
+        pWidth = 800,
+        scrollSize = 17,
+        tblPdg = 50;
 
     // internal state
     var detailsPanel,
@@ -35,13 +38,26 @@
         pHeight,
         wSize,
         top,
+        topTable,
+        bottom,
         iconDiv;
 
     // constants
     var pName = 'yang-model-details-panel',
         detailsReq = 'yangModelDetailsRequest',
-        detailsResp = 'yangModelDetailsResponse';
+        detailsResp = 'yangModelDetailsResponse',
 
+        propOrder = [
+        ],
+        friendlyProps = [
+        ],
+
+        moduleCols = [
+            'name', 'revision'
+        ],
+        friendlyModuleCols = [
+            'Module Name', 'Revision'
+        ];
 
 
     function createDetailsPanel() {
@@ -55,11 +71,13 @@
     }
 
     function populateDetails(details) {
-        var topData;
-
         setUpPanel();
-        topData = top.select('.top-data');
-        populateTop(topData, details);
+
+        populateTop(details);
+        populateBottom(details.modules);
+
+        // topData = top.select('.top-data');
+        // populateTop(topData, details);
         detailsPanel.height(pHeight);
     }
 
@@ -74,16 +92,73 @@
         addCloseBtn(closeBtn);
         iconDiv = top.append('div').classed('dev-icon', true);
         top.append('h2');
+        topTable = top.append('div').classed('top-content', true)
+            .append('table');
+        top.append('hr');
 
-        dataDiv = top.append('div').classed('top-data', true);
-        dataDiv.append('p').text('fill out properties here');
+        bottom = container.append('div').classed('bottom', true);
+        bottom.append('h2').classed('modules-title', true).html('Modules');
+        bottom.append('table');
     }
 
-    function populateTop(dataDiv, details) {
-        top.select('h2').html('ID:' + details.id);
-        // TODO: format data from 'details' into the dataDiv
-        dataDiv.append('p').html('type: ' + details.type);
+    function addProp(tbody, index, value) {
+        var tr = tbody.append('tr');
 
+        function addCell(cls, txt) {
+            tr.append('td').attr('class', cls).html(txt);
+        }
+        addCell('label', friendlyProps[index] + ' :');
+        addCell('value', value);
+    }
+
+    function populateTop(details) {
+        is.loadEmbeddedIcon(iconDiv, 'nav_yang', 40);
+        top.select('h2').html('Model ID ' + details.id);
+
+        var tbody = topTable.append('tbody');
+
+        propOrder.forEach(function (prop, i) {
+            addProp(tbody, i, details[prop]);
+        });
+    }
+
+    function addModuleRow(tbody, module) {
+        var tr = tbody.append('tr');
+        moduleCols.forEach(function (col) {
+            tr.append('td').attr('width', 160)
+                .html('<a href="/v1/yang/modules/' + module.name + '" target="_model">' + module[col] + "</a>");
+        });
+    }
+
+    function populateBottom(modules) {
+        var table = bottom.select('table'),
+            theader = table.append('thead').append('tr'),
+            tbody = table.append('tbody'),
+            tbWidth, tbHeight;
+
+        friendlyModuleCols.forEach(function (col) {
+            theader.append('th').html(col);
+        });
+        modules.forEach(function (module) {
+            addModuleRow(tbody, module);
+        });
+
+        tbWidth = fs.noPxStyle(tbody, 'width') + scrollSize;
+        tbHeight = pHeight
+            - (fs.noPxStyle(detailsPanel.el()
+                .select('.top'), 'height')
+            + fs.noPxStyle(detailsPanel.el()
+                .select('.modules-title'), 'height')
+            + tblPdg);
+
+        table.style({
+            height: tbHeight + 'px',
+            width: tbWidth + 'px',
+            overflow: 'auto',
+            display: 'block'
+        });
+
+        detailsPanel.width(tbWidth + ctnrPdg);
     }
 
     function closePanel() {