Adding ability to view YANG source in the details pane.

Change-Id: I9bc6dd4afbfc02cc27ef989063b28cd3510a6e84
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 d315c22..3be5dd2 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
@@ -26,11 +26,17 @@
 import org.onosproject.ui.table.TableModel;
 import org.onosproject.ui.table.TableRequestHandler;
 import org.onosproject.yang.model.YangModel;
+import org.onosproject.yang.model.YangModule;
 import org.onosproject.yang.model.YangModuleId;
 import org.onosproject.yang.runtime.YangModelRegistry;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URLEncoder;
 import java.util.Collection;
 import java.util.Set;
 
@@ -49,13 +55,18 @@
 
     // Table Column IDs
     private static final String ID = "id";
-    private static final String MODULES = "modules";
+    private static final String MODULE = "module";
+    private static final String REVISION = "revision";
     // TODO: fill out table columns as needed
 
+    private static final String SOURCE = "source";
+
     private static final String[] COL_IDS = {
-            ID, MODULES
+            ID, MODULE, REVISION
     };
 
+    private static final String UTF8 = "UTF-8";
+
     private final Logger log = LoggerFactory.getLogger(getClass());
 
     private YangModelRegistry modelRegistry;
@@ -104,15 +115,16 @@
         @Override
         protected void populateTable(TableModel tm, ObjectNode payload) {
             for (YangModel model : modelRegistry.getModels()) {
-                populateRow(tm.addRow(), model.getYangModulesId());
+                for (YangModuleId id : model.getYangModulesId()) {
+                    populateRow(tm.addRow(), model.hashCode(), id);
+                }
             }
         }
 
-        private void populateRow(TableModel.Row row, Set<YangModuleId> moduleIds) {
-            StringBuilder sb = new StringBuilder();
-            moduleIds.forEach(i -> sb.append(", ").append(i.moduleName())
-                    .append("(").append(i.revision()).append(")"));
-            row.cell(ID, moduleIds.hashCode()).cell(MODULES, sb.toString().substring(2));
+        private void populateRow(TableModel.Row row, int modelId, YangModuleId moduleId) {
+            row.cell(ID, "YM" + modelId)
+                    .cell(MODULE, moduleId.moduleName())
+                    .cell(REVISION, moduleId.revision());
         }
     }
 
@@ -126,32 +138,54 @@
         @Override
         public void process(ObjectNode payload) {
             String id = string(payload, ID);
-            YangModel model = getModel(id);
+            String name = string(payload, MODULE);
+            YangModule module = getModule(id, name);
 
             ObjectNode data = objectNode();
             data.put(ID, id);
+            if (module != null) {
+                data.put(MODULE, module.getYangModuleId().moduleName());
+                data.put(REVISION, module.getYangModuleId().revision());
 
-            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);
+                ArrayNode source = arrayNode();
+                data.set(SOURCE, source);
+
+                addSource(source, module.getYangSource());
             }
 
             ObjectNode rootNode = objectNode();
             rootNode.set(DETAILS, data);
             sendMessage(DETAILS_RESP, rootNode);
         }
+
+        private void addSource(ArrayNode source, InputStream yangSource) {
+            try (InputStreamReader isr = new InputStreamReader(yangSource);
+                 BufferedReader br = new BufferedReader(isr)) {
+                String line;
+                while ((line = br.readLine()) != null) {
+                    source.add(line);
+                }
+
+            } catch (IOException e) {
+                log.warn("Unable to read YANG source", e);
+                return;
+            }
+        }
     }
 
-    private YangModel getModel(String id) {
-        int nid = Integer.parseInt(id);
-        return modelRegistry.getModels().stream()
-                .filter(m -> m.getYangModulesId().hashCode() == nid)
+
+    private YangModule getModule(String id, String name) {
+        int nid = Integer.parseInt(id.substring(2));
+        log.info("Got {}; {}", id, nid);
+        YangModel model = modelRegistry.getModels().stream()
+                .filter(m -> m.hashCode() == nid)
                 .findFirst().orElse(null);
+        if (model != null) {
+            log.info("Got model");
+            return model.getYangModules().stream()
+                    .filter(m -> m.getYangModuleId().moduleName().contentEquals(name))
+                    .findFirst().orElse(null);
+        }
+        return 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 18a60e6..798cf51 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
@@ -55,13 +55,8 @@
     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;
+#yang-model-details-panel .model-source {
+    display: block;
+    overflow: scroll;
+    font-family: "Courier New", serif;
 }
diff --git a/apps/yang-gui/src/main/resources/app/view/yangModel/yangModel.html b/apps/yang-gui/src/main/resources/app/view/yangModel/yangModel.html
index 82dc19e..b83f3ce 100644
--- a/apps/yang-gui/src/main/resources/app/view/yangModel/yangModel.html
+++ b/apps/yang-gui/src/main/resources/app/view/yangModel/yangModel.html
@@ -15,8 +15,9 @@
         <div class="table-header" onos-sortable-header>
             <table>
                 <tr>
-                    <td colId="id" col-width="130px" sortable>ID</td>
-                    <td colId="modules" sortable>Modules</td>
+                    <td colId="module" sortable>Module</td>
+                    <td colId="revision" sortable>Revision</td>
+                    <td colId="id" col-width="130px" sortable>Model ID</td>
                     <!-- TODO: More columns to be added -->
                 </tr>
             </table>
@@ -35,8 +36,9 @@
                     ng-click="selectCallback($event, ymodel)"
                     ng-class="{selected: ymodel.id === selId}"
                     ng-repeat-complete row-id="{{ymodel.id}}">
+                    <td>{{ymodel.module}}</td>
+                    <td>{{ymodel.revision}}</td>
                     <td>{{ymodel.id}}</td>
-                    <td>{{ymodel.modules}}</td>
                     <!-- TODO: add more columns here -->
                 </tr>
             </table>
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 a8a4ac1..7de8c2c 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
@@ -50,16 +50,8 @@
         propOrder = [
         ],
         friendlyProps = [
-        ],
-
-        moduleCols = [
-            'name', 'revision'
-        ],
-        friendlyModuleCols = [
-            'Module Name', 'Revision'
         ];
 
-
     function createDetailsPanel() {
         detailsPanel = ps.createPanel(pName, {
             width: pWidth,
@@ -72,13 +64,8 @@
 
     function populateDetails(details) {
         setUpPanel();
-
         populateTop(details);
-        populateBottom(details.modules);
-
-        // topData = top.select('.top-data');
-        // populateTop(topData, details);
-        detailsPanel.height(pHeight);
+        populateBottom(details.source);
     }
 
     function setUpPanel() {
@@ -97,8 +84,9 @@
         top.append('hr');
 
         bottom = container.append('div').classed('bottom', true);
-        bottom.append('h2').classed('modules-title', true).html('Modules');
-        bottom.append('table');
+        bottom.append('h2').classed('modules-title', true).html('YANG Source');
+        bottom.append('div').classed('module-source');
+        bottom.select('div').append('pre');
     }
 
     function addProp(tbody, index, value) {
@@ -113,7 +101,7 @@
 
     function populateTop(details) {
         is.loadEmbeddedIcon(iconDiv, 'nav_yang', 40);
-        top.select('h2').html('Model ID ' + details.id);
+        top.select('h2').html('Module ' + details.module + " (" + details.revision + ")");
 
         var tbody = topTable.append('tbody');
 
@@ -130,35 +118,9 @@
         });
     }
 
-    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 populateBottom(source) {
+        var src = bottom.select('pre');
+        src.html(source.join('\n'));
     }
 
     function closePanel() {
@@ -217,7 +179,7 @@
             // row selection callback
             function selCb($event, row) {
                 if ($scope.selId) {
-                    wss.sendEvent(detailsReq, { id: row.id });
+                    wss.sendEvent(detailsReq, { id: row.id, module: row.module });
                 } else {
                     $scope.hidePanel();
                 }