001package org.nasdanika.html.model.app.graph.emf;
002
003import java.util.Collection;
004
005import org.eclipse.emf.common.util.URI;
006import org.eclipse.emf.ecore.EClass;
007import org.eclipse.emf.ecore.EObject;
008import org.eclipse.emf.ecore.EOperation;
009import org.eclipse.emf.ecore.EReference;
010import org.nasdanika.common.ProgressMonitor;
011import org.nasdanika.common.Supplier;
012import org.nasdanika.graph.Node;
013import org.nasdanika.graph.emf.EObjectNode;
014import org.nasdanika.graph.emf.EOperationConnection;
015import org.nasdanika.graph.emf.EReferenceConnection;
016import org.nasdanika.graph.emf.QualifiedConnection;
017import org.nasdanika.graph.processor.ConnectionProcessorConfig;
018import org.nasdanika.html.model.app.Label;
019import org.nasdanika.html.model.app.Link;
020import org.nasdanika.html.model.app.graph.WidgetFactory;
021
022public class ConnectionProcessor {
023        
024        protected URI sourceURI;
025        protected URI targetURI;
026        protected ConnectionProcessorConfig<WidgetFactory, WidgetFactory> config;
027        private boolean compactPath;
028
029        /**
030         * 
031         * @param config
032         * @param compactPath if true then reference and operation paths are constructed using reference/operation id's and r or o prefix respectively. 
033         */
034        public ConnectionProcessor(ConnectionProcessorConfig<WidgetFactory, WidgetFactory> config, boolean compactPath) {               
035                this.config = config;           
036                this.compactPath = compactPath;
037                
038                config.getSourceEndpoint().thenAccept(se -> config.setTargetHandler(createTargetHandler(se)));
039                config.getTargetEndpoint().thenAccept(te -> config.setSourceHandler(createSourceHandler(te)));
040        }
041        
042        protected WidgetFactory createTargetHandler(WidgetFactory sourceEndpoint) {
043                return new WidgetFactory() {
044                        
045                        @Override
046                        public void resolve(URI base, ProgressMonitor progressMonitor) {
047                                targetURI = base;
048                        }
049                        
050                        private URI resolveBase(URI base) {
051                                if (base == null) {
052                                        return targetURI;
053                                }
054                                if (base.isRelative() && targetURI != null && !targetURI.isRelative()) {
055                                        return base.resolve(targetURI);                                         
056                                }
057                                return base;                            
058                        }
059                        
060                        @SuppressWarnings("unchecked")
061                        @Override
062                        public String selectString(Object selector, URI base, ProgressMonitor progressMonitor) {
063                                if (selector instanceof Selector) {
064                                        return select((Selector<String>) selector, base, progressMonitor);
065                                }
066                                return sourceEndpoint.selectString(selector, resolveBase(base), progressMonitor);                               
067                        }
068                        
069                        @Override
070                        public Object select(Object selector, URI base, ProgressMonitor progressMonitor) {
071                                if (selector instanceof Selector) {
072                                        return select((Selector<?>) selector, base, progressMonitor);
073                                }
074                                return sourceEndpoint.select(selector, resolveBase(base), progressMonitor);
075                        }
076                                                
077                        @Override
078                        public <T> T select(Selector<T> selector, URI base, ProgressMonitor progressMonitor) {
079                                if (selector instanceof ConnectionSelector) {
080                                        return selector.select(this, resolveBase(base), progressMonitor);
081                                }
082                                return sourceEndpoint.select(selector, resolveBase(base), progressMonitor);
083                        }       
084                        
085                        @Override
086                        public String createLinkString(URI base, ProgressMonitor progressMonitor) {
087                                return sourceEndpoint.createLinkString(resolveBase(base), progressMonitor);
088                        }
089                        
090                        @Override
091                        public Object createLink(URI base, ProgressMonitor progressMonitor) {
092                                return sourceEndpoint.createLink(resolveBase(base), progressMonitor);
093                        }
094                        
095                        @Override
096                        public Label createHelpDecorator(URI base, ProgressMonitor progressMonitor) {
097                                return sourceEndpoint.createHelpDecorator(resolveBase(base), progressMonitor);
098                        }
099                        
100                        @Override
101                        public Supplier<Collection<Label>> createLabelsSupplier() {
102                                return sourceEndpoint.createLabelsSupplier().then(labels -> {
103                                        for (Label label : labels) {
104                                                if (label instanceof Link) {
105                                                        ((Link) label).rebase(targetURI, sourceURI);
106                                                }
107                                        }
108                                        return labels;
109                                });
110                        }
111                        
112                        @Override
113                        public String createLabelString(ProgressMonitor progressMonitor) {
114                                return sourceEndpoint.createLabelString(progressMonitor);
115                        }
116                        
117                        @Override
118                        public Object createLabel(ProgressMonitor progressMonitor) {
119                                return sourceEndpoint.createLabel(progressMonitor);
120                        }
121                        
122                };
123                
124        }
125
126        protected WidgetFactory createSourceHandler(WidgetFactory targetEndpoint) {
127                return new WidgetFactory() {
128                        
129                        @Override
130                        public void resolve(URI base, ProgressMonitor progressMonitor) {
131                                sourceURI = base;                               
132                                QualifiedConnection<?> conn = (QualifiedConnection<?>) config.getElement();
133                                String path = conn.getPath();
134                                Node source = config.getElement().getSource();
135                                EClass eClass = null;
136                                if (source instanceof EObjectNode) {
137                                        EObject eObject = ((EObjectNode) source).get();
138                                        eClass = eObject == null ? null : eObject.eClass();
139                                }
140
141                                if (conn instanceof EReferenceConnection) {
142                                        EReference eRef = ((EReferenceConnection) conn).getReference();
143                                        if (eRef.isContainment()) {
144                                                String uriStr;
145                                                if (compactPath && eClass != null) {
146                                                        uriStr = "r" + Integer.toString(eClass.getFeatureID(eRef), Character.MAX_RADIX);                                                        
147                                                } else {
148                                                        uriStr = "references/" + eRef.getName();
149                                                }
150                                                if (path != null) {
151                                                        uriStr += "/" + path + "/";
152                                                }
153                                                URI refURI = URI.createURI(uriStr);
154                                                targetEndpoint.resolve(refURI.resolve(base), progressMonitor);
155                                        }
156                                } else if (conn instanceof EOperationConnection) {
157                                        EOperation eOp = ((EOperationConnection) conn).getOperation();
158                                        String uriStr;
159                                        if (compactPath && eClass != null) {
160                                                uriStr = "o" + Integer.toString(eClass.getOperationID(eOp), Character.MAX_RADIX);                                                       
161                                        } else {
162                                                uriStr = "operations/" + eOp.getName();
163                                        }
164                                        if (path != null) {
165                                                uriStr += "/" + path + "/";
166                                        }
167                                        URI refURI = URI.createURI(uriStr);
168                                        targetEndpoint.resolve(refURI.resolve(base), progressMonitor);                                  
169                                }
170                        }
171                        
172                        private URI resolveBase(URI base) {
173                                if (base == null) {
174                                        return sourceURI;
175                                }
176                                if (base.isRelative() && sourceURI != null && !sourceURI.isRelative()) {
177                                        return base.resolve(sourceURI);                                         
178                                }
179                                return base;                            
180                        }
181                        
182                        @SuppressWarnings("unchecked")
183                        @Override
184                        public String selectString(Object selector, URI base, ProgressMonitor progressMonitor) {
185                                if (selector instanceof Selector) {
186                                        return select((Selector<String>) selector, base, progressMonitor);
187                                }
188                                return targetEndpoint.selectString(selector, resolveBase(base), progressMonitor);
189                        }
190                        
191                        @Override
192                        public Object select(Object selector, URI base, ProgressMonitor progressMonitor) {
193                                if (selector instanceof Selector) {
194                                        return select((Selector<?>) selector, base, progressMonitor);
195                                }
196                                return targetEndpoint.select(selector, resolveBase(base), progressMonitor); 
197                        }
198                        
199                        @Override
200                        public <T> T select(Selector<T> selector, URI base, ProgressMonitor progressMonitor) {
201                                if (selector instanceof ConnectionSelector) {
202                                        return selector.select(this, resolveBase(base), progressMonitor);
203                                }
204                                return targetEndpoint.select(selector, resolveBase(base), progressMonitor);
205                        }       
206                        
207                        @Override
208                        public String createLinkString(URI base, ProgressMonitor progressMonitor) {
209                                return targetEndpoint.createLinkString(resolveBase(base), progressMonitor);
210                        }
211                        
212                        @Override
213                        public Object createLink(URI base, ProgressMonitor progressMonitor) {
214                                return targetEndpoint.createLink(resolveBase(base), progressMonitor);
215                        }
216                        
217                        @Override
218                        public Label createHelpDecorator(URI base, ProgressMonitor progressMonitor) {
219                                return targetEndpoint.createHelpDecorator(resolveBase(base), progressMonitor);
220                        }
221                        
222                        @Override
223                        public Supplier<Collection<Label>> createLabelsSupplier() {
224                                return targetEndpoint.createLabelsSupplier().then(labels -> {
225                                        for (Label label : labels) {
226                                                if (label instanceof Link) {
227                                                        ((Link) label).rebase(targetURI, sourceURI);
228                                                }
229                                        }
230                                        return labels;
231                                });
232                        }
233                        
234                        @Override
235                        public String createLabelString(ProgressMonitor progressMonitor) {
236                                return targetEndpoint.createLabelString(progressMonitor);
237                        }
238                        
239                        @Override
240                        public Object createLabel(ProgressMonitor progressMonitor) {
241                                return targetEndpoint.createLabel(progressMonitor);
242                        }
243                        
244                };
245        }
246
247}