# CertificateDetailsView.java

    /*
    ** Module   : CertificateDetailsView.java
    ** Abstract : CertificateDetailsView represents a certificate fields view.
    **
    ** Copyright (c) 2017, Golden Code Development Corporation.
    **
    ** -#- -I- --Date-- ----------------Description----------------------
    ** 001 SBI 20170601 Created initial version.
    ** 002 EVL 20170926 Javadoc fixes.
    */
    /*
    ** This program is free software: you can redistribute it and/or modify
    ** it under the terms of the GNU Affero General Public License as
    ** published by the Free Software Foundation, either version 3 of the
    ** License, or (at your option) any later version.
    **
    ** This program is distributed in the hope that it will be useful,
    ** but WITHOUT ANY WARRANTY; without even the implied warranty of
    ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    ** GNU Affero General Public License for more details.
    **
    ** You may find a copy of the GNU Affero GPL version 3 at the following
    ** location: https://www.gnu.org/licenses/agpl-3.0.en.html
    **
    ** Additional terms under GNU Affero GPL version 3 section 7:
    **
    **   Under Section 7 of the GNU Affero GPL version 3, the following additional
    **   terms apply to the works covered under the License.  These additional terms
    **   are non-permissive additional terms allowed under Section 7 of the GNU
    **   Affero GPL version 3 and may not be removed by you.
    **
    **   0. Attribution Requirement.
    **
    **     You must preserve all legal notices or author attributions in the covered
    **     work or Appropriate Legal Notices displayed by works containing the covered
    **     work.  You may not remove from the covered work any author or developer
    **     credit already included within the covered work.
    **
    **   1. No License To Use Trademarks.
    **
    **     This license does not grant any license or rights to use the trademarks
    **     Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
    **     of Golden Code Development Corporation. You are not authorized to use the
    **     name Golden Code, FWD, or the names of any author or contributor, for
    **     publicity purposes without written authorization.
    **
    **   2. No Misrepresentation of Affiliation.
    **
    **     You may not represent yourself as Golden Code Development Corporation or FWD.
    **
    **     You may not represent yourself for publicity purposes as associated with
    **     Golden Code Development Corporation, FWD, or any author or contributor to
    **     the covered work, without written authorization.
    **
    **   3. No Misrepresentation of Source or Origin.
    **
    **     You may not represent the covered work as solely your work.  All modified
    **     versions of the covered work must be marked in a reasonable way to make it
    **     clear that the modified work is not originating from Golden Code Development
    **     Corporation or FWD.  All modified versions must contain the notices of
    **     attribution required in this license.
    */

    package com.goldencode.p2j.admin.client.application.home.accounts.certificates;

    import java.util.Arrays;
    import java.util.Map;
    import java.util.Map.Entry;

    import org.gwtbootstrap3.client.ui.Modal;

    import com.goldencode.p2j.admin.TaggedName;
    import com.goldencode.p2j.admin.client.widget.dialog.ModalViewWithUiHandlers;
    import com.google.gwt.cell.client.AbstractCell;
    import com.google.gwt.core.client.GWT;
    import com.google.gwt.safehtml.client.SafeHtmlTemplates;
    import com.google.gwt.safehtml.shared.SafeHtml;
    import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
    import com.google.gwt.safehtml.shared.SafeHtmlUtils;
    import com.google.gwt.text.shared.AbstractSafeHtmlRenderer;
    import com.google.gwt.uibinder.client.UiBinder;
    import com.google.gwt.uibinder.client.UiField;
    import com.google.gwt.user.cellview.client.CellTree;
    import com.google.gwt.user.client.ui.Widget;
    import com.google.gwt.view.client.ListDataProvider;
    import com.google.gwt.view.client.TreeViewModel;
    import com.google.inject.Inject;

    /**
     * CertificateDetailsView represents a certificate fields view.
     */
    public class CertificateDetailsView
    extends ModalViewWithUiHandlers<CertificatesUIHandlers>
    {
       /**
        * GWT UI creator
        */
       interface Binder
       extends UiBinder<Widget, CertificateDetailsView>
       {}

       /** The target modal dialog */
       @UiField
       Modal modal;

       /** The tree view to display the certificate data */
       @UiField(provided = true)
       CellTree detailsTree;

       /** The certificate tree data provider */
       private final ListDataProvider<Map.Entry<TaggedName, TaggedName[]>> treeProvider =
                new ListDataProvider<Map.Entry<TaggedName,TaggedName[]>>();

       /** The target tree model */
       private Map<TaggedName, TaggedName[]> treeValues;

       /**
        * Builds a certificate details view by injecting GWT binder as its parameter
        *
        * @param    binder
        *           GWT UI Binder
        */
       @Inject
       public CertificateDetailsView(Binder binder)
       {
          CertTreeModel treeModel = new CertTreeModel();
          detailsTree = new CellTree(treeModel, null);
          initWidget(binder.createAndBindUi(this));
       }

       /**
        * Sets the certificate data for the certificate tree view.
        *
        * @param    data
        *           The tree model that maps the parent node to its children nodes
        */
       public void setCertDetailsTree(Map<TaggedName, TaggedName[]> data)
       {
          treeValues = data;
          treeProvider.getList().clear();
          treeProvider.getList().addAll(data.entrySet());
       }

       /**
        * Provides an access to the target modal dialog.
        *
        * @return   The underlined modal dialog
        */
       @Override
       protected Modal getModal()
       {
          return modal;
       }

       /**
        * The tree node html template
        */
       interface TreeNodeTemplate
       extends SafeHtmlTemplates
       {
          /**
           * Builds the target leaf node.
           *
           * @param    label
           *           The node label
           * @param    value
           *           The node value
           *
           * @return   The node safe html.
           */
          @SafeHtmlTemplates.Template("<div class='col-xs-6'>{0}</div><div class='col-xs-6'>{1}</div>")
          SafeHtml buildLeafNode(SafeHtml label, SafeHtml value);

          /**
           * Builds the target root node.
           *
           * @param    value
           *           The node value
           *
           * @return   The node safe html.
           */
          @SafeHtmlTemplates.Template("<div class='col-xs-4'>{0}</div>")
          SafeHtml buildRootNode(SafeHtml value);
       }

       /** Tree node template instance */
       private static final TreeNodeTemplate TEMPLATE = GWT.create(TreeNodeTemplate.class);

       /** Tree cell renderer instance */
       private static final TreeCellRenderer RENDERER = new TreeCellRenderer();

       /**
        * The tree html render.
        */
       static class TreeCellRenderer
       extends AbstractSafeHtmlRenderer<Map.Entry<TaggedName, TaggedName[]>>
       {

          /**
           * Renders a tree node of Map.Entry&lt;TaggedName, TaggedName[]&gt; type.
           *
           * @param    object
           *           The target node
           *
           * @return   The safe html of tree cell.
           */
          @Override
          public SafeHtml render(Entry<TaggedName, TaggedName[]> object)
          {
             //leaf node if childs are null
             TaggedName[] childs = object.getValue();
             if (childs == null || childs.length == 0)
             {
                return TEMPLATE.buildLeafNode(SafeHtmlUtils.fromString(object.getKey().getName()),
                         SafeHtmlUtils.fromString(object.getKey().getTag()));
             }
             else
             {
                return TEMPLATE.buildRootNode(SafeHtmlUtils.fromString(object.getKey().getName()));
             }
          }
       }

       /**
        * Renders an internal non-leaf node.
        */
       class TreeCell
       extends AbstractCell<Map.Entry<TaggedName, TaggedName[]>>
       {

          /**
           * Renders a non-leaf node of Map.Entry&lt;TaggedName, TaggedName[]&gt; type.
           *
           * @param    context
           *           The current context
           * @param    value
           *           The target non-leaf node
           * @param    sb
           *           The safe html builder to accumulate html.
           */
          @Override
          public void render(com.google.gwt.cell.client.Cell.Context context,
                   Map.Entry<TaggedName, TaggedName[]> value, SafeHtmlBuilder sb)
          {
             sb.append(RENDERER.render(value));
          }

       };

       /**
        * Renders a leaf node.
        *
        */
       class LeafTreeCell
       extends AbstractCell<TaggedName>
       {
          /**
           * Renders a leaf value of TaggedName type.
           *
           * @param    context
           *           The current context
           * @param    value
           *           The target leaf value
           * @param    sb
           *           The safe html builder to accumulate html.
           */
          @Override
          public void render(com.google.gwt.cell.client.Cell.Context context,
                   TaggedName value, SafeHtmlBuilder sb)
          {
             sb.append(RENDERER.render(new Map.Entry<TaggedName, TaggedName[]>()
             {

                @Override
                public TaggedName getKey()
                {
                   return value;
                }

                @Override
                public TaggedName[] getValue()
                {
                   return null;
                }

                @Override
                public TaggedName[] setValue(TaggedName[] value)
                {
                   return null;
                }
             }));
          }

       };

       /**
        * Implements tree view model.
        */
       class CertTreeModel
       implements TreeViewModel
       {
          /**
           * Gets a tree node data.
           *
           * @param    <T>
           *           The node type
           * @param    value
           *           The node
           *
           * @return   The tree node data.
           */
          @Override
          public <T> NodeInfo<?> getNodeInfo(T value)
          {
             if (value == null)
             {
                return new DefaultNodeInfo<Map.Entry<TaggedName, TaggedName[]>>(treeProvider, new TreeCell());
             }

             if (value instanceof Map.Entry)
             {
                Object treeNodeValue = ((Map.Entry) value).getKey();
                Object childNodes = ((Map.Entry) value).getValue();
                ListDataProvider<TaggedName> childsProvider = new ListDataProvider<TaggedName>();
                if (childNodes instanceof TaggedName[])
                {
                   TaggedName[] childs = (TaggedName[]) childNodes;
                   childsProvider.getList().addAll(Arrays.asList(childs));
                }

                return new DefaultNodeInfo<TaggedName>(childsProvider, new LeafTreeCell());
             }
             else if (value instanceof TaggedName)
             {
                TaggedName nodeValue = (TaggedName) value;
                TaggedName[] childNodes = treeValues.get(nodeValue);
                ListDataProvider<TaggedName> childsProvider = new ListDataProvider<TaggedName>();
                if (childNodes != null)
                {
                   childsProvider.getList().addAll(Arrays.asList(childNodes));
                }
                return new DefaultNodeInfo<TaggedName>(childsProvider, new LeafTreeCell());
             }

             // Unhandled type.
             String type = value.getClass().getName();

             throw new IllegalArgumentException("Unsupported object type: " + type);
          }

          /**
           * Tests if the target tree node is a leaf or not.
           *
           * @param    value
           *           The target tree node
           *
           * @return   True iff the node is a leaf tree node.
           */
          @Override
          public boolean isLeaf(Object value)
          {
             if (value instanceof TaggedName)
             {
                TaggedName[] childNodes = treeValues.get(value);
                if (childNodes == null || childNodes.length == 0)
                {
                   return true;
                }
             }
             else if (value instanceof Map.Entry)
             {
                Object treeNodeValue = ((Map.Entry) value).getKey();
                Object childNodes = ((Map.Entry) value).getValue();
                if (childNodes == null ||
                   (childNodes instanceof TaggedName[] &&
                            ((TaggedName[]) childNodes).length == 0))
                {
                   return true;
                }
             }

             return false;
          }
       }
    }