001package org.nasdanika.html.flow;
002
003import java.nio.charset.StandardCharsets;
004import java.security.MessageDigest;
005import java.util.List;
006import java.util.function.BiConsumer;
007import java.util.stream.Collectors;
008
009import org.apache.commons.codec.binary.Hex;
010import org.eclipse.emf.common.util.URI;
011import org.eclipse.emf.ecore.EObject;
012import org.eclipse.emf.ecore.ETypedElement;
013import org.eclipse.emf.ecore.util.EcoreUtil;
014import org.nasdanika.common.BiSupplier;
015import org.nasdanika.common.Context;
016import org.nasdanika.common.DiagramGenerator;
017import org.nasdanika.common.ProgressMonitor;
018import org.nasdanika.common.Util;
019import org.nasdanika.diagram.Diagram;
020import org.nasdanika.diagram.gen.Generator;
021import org.nasdanika.flow.FlowPackage;
022import org.nasdanika.flow.PackageElement;
023import org.nasdanika.html.emf.EObjectActionBuilder;
024import org.nasdanika.html.model.app.Action;
025import org.nasdanika.html.model.app.AppFactory;
026import org.nasdanika.html.model.app.SectionStyle;
027import org.nasdanika.html.model.bootstrap.BootstrapFactory;
028import org.nasdanika.html.model.bootstrap.Table;
029import org.nasdanika.html.model.bootstrap.TableCell;
030import org.nasdanika.html.model.bootstrap.TableRow;
031import org.nasdanika.html.model.bootstrap.TableSection;
032import org.nasdanika.ncore.util.NamedElementComparator;
033import org.nasdanika.ncore.util.NcoreUtil;
034
035public class PackageElementActionBuilder<T extends PackageElement<?>> extends EObjectActionBuilder<T> {
036        
037        /**
038         * Descriptions shorter than this value are put on the top of the tabs, longer
039         * ones end up in their own tab. 
040         */
041        protected int descriptionTabLengthThreshold = 2500;
042                
043        public PackageElementActionBuilder(T value, Context context) {
044                super(value, context);          
045        }
046        
047        @Override
048        protected Action buildAction(
049                        Action action,
050                        BiConsumer<EObject,Action> registry, 
051                        java.util.function.Consumer<org.nasdanika.common.Consumer<org.nasdanika.html.emf.EObjectActionResolver.Context>> resolveConsumer, 
052                        ProgressMonitor progressMonitor) throws Exception {
053                Action ret = super.buildAction(action, registry, resolveConsumer, progressMonitor);             
054                T eObj = getTarget();
055                URI uri = NcoreUtil.getUri(eObj);
056                String id = uri == null ? eObj.getUuid() : uri.toString();
057                String digest = Hex.encodeHexString(MessageDigest.getInstance("SHA-256").digest(id.getBytes(StandardCharsets.UTF_8)));
058                ret.setId(digest);
059                
060                String description = eObj.getDescription();
061                addContent(ret, description);
062                ret.setDescription(description);
063
064                BiSupplier<EObject, String> cPath = NcoreUtil.containmentPath(eObj);
065                if (cPath == null || Util.isBlank(cPath.getSecond())) {
066                        ret.setLocation("${base-uri}index.html");
067                } else {
068                        ret.setLocation(cPath.getSecond() + "/index.html");
069                }
070                
071                ret.setText(eObj.getName()); // Escape?
072                ret.setSectionStyle(SectionStyle.HEADER);
073                return ret;
074        }
075
076        @Override
077        public String name() {
078                return getTarget().getName();
079        }
080        
081        @Override
082        protected List<ETypedElement> getProperties() {
083                List<ETypedElement> propertiew = super.getProperties();
084                propertiew.add(FlowPackage.Literals.PACKAGE_ELEMENT__EXTENDS);
085                propertiew.add(FlowPackage.Literals.PACKAGE_ELEMENT__EXTENSIONS);
086                propertiew.add(FlowPackage.Literals.PACKAGE_ELEMENT__MODIFIERS);
087                return propertiew;
088        }
089        
090        @Override
091        protected Table createPropertiesTable(
092                        Action action,
093                        org.nasdanika.html.emf.EObjectActionResolver.Context context,
094                        ProgressMonitor progressMonitor) throws Exception {
095                Table propertiesTable = super.createPropertiesTable(action, context, progressMonitor);
096                propertiesTable.getAttributes().put("style", createText("width:auto"));
097                return propertiesTable;
098        }
099        
100        @Override
101        protected void resolve(
102                        Action action, 
103                        org.nasdanika.html.emf.EObjectActionResolver.Context context,
104                        ProgressMonitor progressMonitor) throws Exception {
105
106                super.resolve(action, context, progressMonitor);
107                T semanticElement = getTarget();
108
109                // Representations
110                for (Diagram representation: semanticElement.getRepresentations().values().stream().sorted(NamedElementComparator.INSTANCE).collect(Collectors.toList())) {
111                        if (representation.getElements().isEmpty()) {
112                                populateRepresentation(representation, action, context, progressMonitor);
113                        }                       
114                        Action representationAction;
115                        if (Util.isBlank(representation.getName())) {
116                                representationAction = action;
117                        } else {
118                                representationAction = AppFactory.eINSTANCE.createAction();
119                                representationAction.setText(representation.getName());
120                                action.getSections().add(representationAction); // TODO - support of navigation/navigation-modal - get from properties.
121                        }
122                        String rDescr = representation.getDescription();
123                        if (Util.isBlank(rDescr)) {
124                                addContent(representationAction, createGenerator().generate(representation));                           
125                        } else {
126                                Table table = BootstrapFactory.eINSTANCE.createTable();
127                                representationAction.getContent().add(table);
128                                table.setBordered(true);
129                                TableSection body = BootstrapFactory.eINSTANCE.createTableSection();
130                                table.setBody(body);
131                                table.getAttributes().put("style", createText("width:auto"));                           
132                                
133                                TableRow diagramRow = BootstrapFactory.eINSTANCE.createTableRow();
134                                body.getRows().add(diagramRow);
135                                TableCell diagramCell = BootstrapFactory.eINSTANCE.createTableCell();
136                                diagramRow.getCells().add(diagramCell);                         
137                                diagramCell.getContent().add(createText(createGenerator().generate(representation)));
138                                
139                                TableRow descriptionRow = BootstrapFactory.eINSTANCE.createTableRow();
140                                body.getRows().add(descriptionRow);
141                                TableCell descriptionCell = BootstrapFactory.eINSTANCE.createTableCell();
142                                descriptionRow.getCells().add(descriptionCell);                         
143                                descriptionCell.getContent().add(createText(rDescr));                                                           
144                        }
145                }
146                
147                // Adding documentation here so it appears under the properties table
148                action.getContent().addAll(EcoreUtil.copyAll(semanticElement.getDocumentation()));                              
149        }
150        
151        /**
152         * Creates a diagram {@link Generator}.
153         * @return
154         */
155        protected Generator createGenerator() {
156                return new Generator() {
157                        
158                        @Override
159                        protected DiagramGenerator getDiagramGenerator() {
160                                return context == null ? super.getDiagramGenerator() : context.get(DiagramGenerator.class, super.getDiagramGenerator()); 
161                        }
162                        
163                };
164        }
165        
166        /**
167         * Populates empty representations. An empty representation indicates that it has to be auto-populated. 
168         * Non-empty representations indicate that they were pre-populated, e.g. manually, and should not be auto-populated. 
169         * @param representation
170         */
171        protected void populateRepresentation(
172                        Diagram representation, 
173                        Action action, 
174                        org.nasdanika.html.emf.EObjectActionResolver.Context context,
175                        ProgressMonitor progressMonitor) throws Exception {
176                
177        }
178        
179}