001/**
002 * Copyright 2004-2014 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.kuali.student.contract.model.util;
017
018import java.util.HashSet;
019import java.util.LinkedHashSet;
020import java.util.Set;
021import org.kuali.student.contract.model.Lookup;
022
023import org.kuali.student.contract.model.MessageStructure;
024import org.kuali.student.contract.model.ServiceContractModel;
025import org.kuali.student.contract.model.ServiceMethod;
026import org.kuali.student.contract.model.ServiceMethodParameter;
027import org.kuali.student.contract.model.XmlType;
028import org.kuali.student.contract.writer.HtmlWriter;
029import org.slf4j.Logger;
030import org.slf4j.LoggerFactory;
031
032/**
033 *
034 * @author nwright
035 */
036public class HtmlContractMessageStructureWriter {
037
038        private static final Logger log = LoggerFactory.getLogger(HtmlContractMessageStructureWriter.class);
039        
040    private XmlType xmlType;
041    private HtmlWriter writer;
042    private ServiceContractModel model;
043    private ModelFinder finder;
044
045    public HtmlContractMessageStructureWriter(XmlType xmlType, String directory,
046            ServiceContractModel model) {
047        this.xmlType = xmlType;
048        this.writer = new HtmlWriter(directory, xmlType.getName() + ".html",
049                xmlType.getName());
050        this.model = model;
051        this.finder = new ModelFinder(this.model);
052    }
053
054    private String initUpper(String str) {
055        if (str == null) {
056            return null;
057        }
058        if (str.length() == 0) {
059            return str;
060        }
061        if (str.length() == 1) {
062            return str.toUpperCase();
063        }
064        return str.substring(0, 1).toUpperCase() + str.substring(1);
065    }
066
067    private boolean isMainMessageStructure(XmlType xmlType) {
068        if (!HtmlContractMessageStructureWriter.calcOtherXmlTypeUsages(model,
069                xmlType).isEmpty()) {
070            return false;
071        }
072        return true;
073    }
074
075    private boolean shouldAddDictionaryLink (XmlType xmlType) {
076        return this.isMainMessageStructure(xmlType);
077    }
078    
079    public void write(String projectVersion, String formattedDate) {
080       
081        this.writeStyleSheet();
082       
083        
084        if (this.shouldAddDictionaryLink(xmlType)) {
085                VersionLinesUtility.writeVersionTag(writer, "<a href=\"index.html\">home</a>", "<a href=\"../dictionarydocs/" + initUpper(xmlType.getName()) + ".html\">dictionary doc</a>", projectVersion, formattedDate);
086        }
087        else 
088                VersionLinesUtility.writeVersionTag(writer, "<a href=\"index.html\">home</a>", "" ,projectVersion, formattedDate);
089        
090
091        writer.writeTag("h1", xmlType.getName());
092        
093        writer.indentPrintln("<table id=\"structureMetaTable\">");
094        writer.indentPrintln("<tr>");
095        writer.writeTag("th", "class=h", "Name");
096        writer.writeTag("td", "id=structureName colspan=2", xmlType.getName());
097        writer.indentPrintln("</tr>");
098//  writer.indentPrintln ("<tr>");
099//  writer.writeTag ("th", "class=h", "Version");
100//  writer.writeTag ("td", "id=structureVersion colspan=2", xmlType.getVersion ());
101//  writer.indentPrintln ("</tr>");
102        writer.indentPrintln("<tr>");
103        writer.writeTag("th", "rowspan=3 class=h", "Usage");
104        writer.indentPrint("<td id=\"structureVersion\" colspan=2>");
105        for (String servKey : xmlType.getService().split(",")) {
106            writer.indentPrintln("<a href=\"" + servKey + "Service" + ".html" + "\">"
107                    + servKey + "Service" + "</a>");
108        }
109        writer.indentPrint("</td>");
110
111        writer.indentPrintln("</tr>");
112        writer.indentPrintln("<tr>");
113        writer.writeTag("th", "class=h", "");
114        writer.indentPrint("<td id=\"structureVersion\" colspan=2>");
115        for (ServiceMethod method : this.calcUsageByMethods(xmlType)) {
116            writer.indentPrintln("<a href=\"" + method.getService() + "Service"
117                    + ".html" + "#" + method.getService() + "-"
118                    + method.getName() + "\">"
119                    + method.getName() + "</a>");
120        }
121        writer.indentPrint("</td>");
122        writer.indentPrintln("</tr>");
123        writer.indentPrintln("<tr>");
124        writer.writeTag("th", "class=h", "");
125        writer.indentPrint("<td id=\"structureVersion\" colspan=2>");
126        for (String xmlTypeName : this.calcOtherXmlTypeUsages(xmlType)) {
127            XmlType usageType = finder.findXmlType(xmlTypeName);
128            if (usageType == null) {
129                throw new NullPointerException("Coud not find XmlType with name="
130                        + xmlTypeName);
131            }
132            writer.indentPrintln("<a href=\"" + usageType.getName() + ".html" + "\">"
133                    + usageType.getName() + "</a>");
134        }
135        writer.indentPrint("</td>");
136        writer.indentPrintln("</tr>");
137
138        writer.writeTag("th", "class=h", "Type");
139        writer.writeTag("td", "id=structureVersion colspan=2",
140                xmlType.getPrimitive());
141        writer.indentPrintln("</tr>");
142        writer.indentPrintln("</table>");
143
144        writer.writeTag("h2", "Description");
145        writer.indentPrintln(this.addHTMLBreaks(calcDescription (xmlType)));
146
147        if (!xmlType.getPrimitive().equals(XmlType.COMPLEX)) {
148            return;
149        }
150        writer.indentPrintln(
151                "<h2><a name=\"StructureDefinition\"></a>Structure Definition</h2>");
152
153
154        writer.indentPrintln("<table class=\"structTable\">");
155        writer.indentPrintln("<tr>");
156        writer.indentPrintln("<th class=\"h\">ShortName</th>");
157        writer.indentPrintln("<th class=\"h\">Name</th>");
158        writer.indentPrintln("<th class=\"h\">Type</th>");
159        writer.indentPrintln("<th class=\"h\">Description</th>");
160        writer.indentPrintln("<th class=\"h\">Required?</th>");
161        writer.indentPrintln("<th class=\"h\">Read only?</th>");
162        writer.indentPrintln("<th class=\"h\">Lookup (WIP)</th>");
163        writer.indentPrintln("<th class=\"h\">Implementation Notes</th>");
164        writer.indentPrintln("</tr>");
165
166        for (MessageStructure ms : finder.findMessageStructures(xmlType.getName())) {
167            this.writeMessageStructure(ms);
168        }
169        writer.indentPrintln("</table>");
170        writer.writeHeaderBodyAndFooterOutToFile();
171    }
172
173    
174     private String calcDescription(XmlType xmlType) {
175        StringBuilder sb = new StringBuilder();
176        String newLine = "";
177        if (xmlType.getDesc() != null && !xmlType.getDesc().trim().isEmpty()) {
178            sb.append(newLine);
179            newLine = "\n";
180            sb.append(xmlType.getDesc ());
181        }
182        if (xmlType.isDeprecated()) {
183            sb.append(newLine);
184            newLine = "\n";
185            sb.append("============== Deprecated ===============");
186        }
187        return sb.toString();
188    }
189
190    private String checkForNbsp(String str) {
191        if (str == null) {
192            return "&nbsp;";
193        }
194        if (str.trim().isEmpty()) {
195            return "&nbsp;";
196        }
197        return str;
198    }
199
200    private String addHTMLBreaks(String str) {
201        if (str == null) {
202            return "&nbsp;";
203        }
204        return str.replaceAll("(\r\n|\r|\n|\n\r)", "<br>");
205    }
206
207    public static Set<String> calcUsageByService(ServiceContractModel mdl, XmlType xmlType) {
208        Set<String> services = new HashSet();
209        for (ServiceMethod method : calcUsageByMethods(mdl, xmlType)) {
210            services.add(method.getService());
211        }
212        return services;
213    }
214
215    private Set<ServiceMethod> calcUsageByMethods(XmlType xmlType) {
216        return calcUsageByMethods(model, xmlType);
217    }
218
219    public static Set<ServiceMethod> calcUsageByMethods(ServiceContractModel mdl, XmlType xmlType) {
220        Set<ServiceMethod> methods = new LinkedHashSet();
221        for (ServiceMethod method : mdl.getServiceMethods()) {
222            if (stripListFromType(method.getReturnValue().getType()).equalsIgnoreCase(xmlType.getName())) {
223                methods.add(method);
224                continue;
225            }
226            for (ServiceMethodParameter param : method.getParameters()) {
227                if (stripListFromType(param.getType()).equalsIgnoreCase(xmlType.getName())) {
228                    methods.add(method);
229                    break;
230                }
231            }
232        }
233        return methods;
234    }
235
236    private Set<String> calcOtherXmlTypeUsages(XmlType xmlType) {
237        return calcOtherXmlTypeUsages(model, xmlType);
238    }
239
240    public static Set<String> calcOtherXmlTypeUsages(ServiceContractModel mdl,
241            XmlType xmlType) {
242        Set<String> xmlTypeNames = new LinkedHashSet();
243        for (MessageStructure ms : mdl.getMessageStructures()) {
244            if (ms.getType() == null) {
245                throw new NullPointerException(ms.getId() + " has no type set");
246            }
247            if (stripListFromType(ms.getType()).equalsIgnoreCase(xmlType.getName())) {
248                xmlTypeNames.add(ms.getXmlObject());
249            }
250        }
251        return xmlTypeNames;
252    }
253
254    private void writeMessageStructure(MessageStructure ms) {
255        writer.indentPrintln("<tr>");
256        writer.writeTag("td", "class=\"structSName\"", ms.getShortName());
257        writer.writeTag("td", "class=\"structLName\"", ms.getName());
258        XmlType subType = finder.findXmlType(this.stripListFromType(ms.getType()));
259        if (subType == null) {
260//            for (XmlType xmlt : model.getXmlTypes()) {
261//                System.out.println(this.getClass().getSimpleName() + ": "
262//                        + xmlt.getName());
263//            }
264//            throw new NullPointerException(ms.getXmlObject() + "." + ms.getShortName()
265//                    + " has type " + ms.getType()
266//                    + " was not found in list of known types");
267                
268                log.error (ms.getXmlObject() + "." + ms.getShortName()
269                  + " has type " + ms.getType()
270                  + " was not found in list of known types");
271                return;
272        }
273        if (subType.getPrimitive().equals(XmlType.COMPLEX)) {
274            writer.indentPrint("<td class=\"structType\">");
275            writer.indentPrintln("<a href=\"" + subType.getName() + ".html" + "\">"
276                    + ms.getType() + "</a>");
277            writer.indentPrint("</td>");
278        } else {
279            writer.writeTag("td", "class=\"structType\"", ms.getType());
280        }
281        writer.writeTag("td", "class=\"structDesc\"", addHTMLBreaks(missingData(
282                calcDescription(ms))));
283        writer.writeTag("td", "class=\"structOpt\"", checkForNbsp(ms.getRequired()));
284        writer.writeTag("td", "class=\"structOpt\"", checkForNbsp(ms.getReadOnly()));
285
286        writer.writeTag("td", "class=\"structCard\"", addHTMLBreaks (checkForNbsp (calcLookup (ms.getLookup ()))));
287//      writer.writeTag ("td", "class=\"structStatus\"", ms.getStatus ());
288        writer.writeTag("td", "class=\"commentsDesc\"", addHTMLBreaks(this.checkForNbsp(ms.getImplNotes())));
289        writer.indentPrintln("</tr>");
290
291//  writer.indentPrintln ("</table>");
292//  writer.indentPrintln ("<p>");
293
294//  writer.indentPrintln ("<p>");
295    }
296
297    private String calcLookup(Lookup lookup) {
298        if (lookup == null) {
299            return null;
300        }
301        StringBuilder sb = new StringBuilder();
302        String newLine = "\n";
303        sb.append(lookup.getServiceKey());
304        sb.append(":");
305        sb.append(lookup.getXmlTypeName());
306        if (lookup.getGetMethod() != null) {
307            sb.append(newLine);
308            sb.append(lookup.getGetMethod());
309        }
310        if (lookup.getSearchMethod() != null) {
311            sb.append(newLine);
312            sb.append(lookup.getSearchMethod());
313            if (lookup.getAdditionalCriteria() != null) {
314                sb.append(newLine);
315                sb.append(lookup.getAdditionalCriteria().toString());
316            }
317        }
318        return sb.toString();
319    }
320    
321    private String calcDescription(MessageStructure ms) {
322        StringBuilder sb = new StringBuilder();
323        String newLine = "";
324        if (ms.getDescription() != null && !ms.getDescription().trim().isEmpty()) {
325            sb.append(newLine);
326            newLine = "\n";
327            sb.append(ms.getDescription());
328        }
329        if (ms.isDeprecated()) {
330            sb.append(newLine);
331            newLine = "\n";
332            sb.append("============== Deprecated ===============");
333        }
334        return sb.toString();
335    }
336
337    private String missingData(String str) {
338        if (str == null) {
339            return "???";
340        }
341        if (str.trim().isEmpty()) {
342            return "???";
343        }
344        return str;
345    }
346
347    private static String stripListFromType(String type) {
348        if (type.endsWith("List")) {
349            return type.substring(0, type.length() - "List".length());
350        }
351        return type;
352    }
353
354    public void writeStyleSheet() {
355        writer.indentPrintln("<style type=\"text/css\">");
356        writer.indentPrintln("");
357        writer.indentPrintln("table#structureMetaTable {");
358        writer.indentPrintln("border-collapse:collapse;");
359        writer.indentPrintln("border:1px solid #000000;");
360        writer.indentPrintln("width:95%;");
361        writer.indentPrintln("}");
362        writer.indentPrintln("table#structureMetaTable th.h {");
363        writer.indentPrintln("border:1px solid #000000;");
364        writer.indentPrintln("background-color:#eeeeee;");
365        writer.indentPrintln("width:15%;");
366        writer.indentPrintln("}");
367        writer.indentPrintln("table#structureMetaTable td#structureName {");
368        writer.indentPrintln("border:1px solid #000000;");
369        writer.indentPrintln("width:85%;");
370        writer.indentPrintln("}");
371        writer.indentPrintln("table#structureMetaTable td#structureVersion {");
372        writer.indentPrintln("border:1px solid #000000;");
373        writer.indentPrintln("width:70%;");
374        writer.indentPrintln("}");
375        writer.indentPrintln("table#structureMetaTable td#structureVersionHistory {");
376        writer.indentPrintln("border:1px solid #000000;");
377        writer.indentPrintln("width:15%;");
378        writer.indentPrintln("}");
379        writer.indentPrintln("");
380        writer.indentPrintln("</style>");
381
382        writer.indentPrintln("<style type=\"text/css\">");
383        writer.indentPrintln("");
384        writer.indentPrintln("table.structTable {");
385        writer.indentPrintln("border-collapse:collapse;");
386        writer.indentPrintln("border:1px solid #000000;");
387        writer.indentPrintln("width:95%;");
388        writer.indentPrintln("}");
389        writer.indentPrintln("");
390        writer.indentPrintln("table.structTable td.d {");
391        writer.indentPrintln("border:1px solid #000000;");
392        writer.indentPrintln("}");
393        writer.indentPrintln("");
394        writer.indentPrintln("table.structTable th.h {");
395        writer.indentPrintln("border:1px solid #000000;");
396        writer.indentPrintln("background-color:#eeeeee;");
397        writer.indentPrintln("}");
398        writer.indentPrintln("");
399        writer.indentPrintln("table.structTable td.structSName {");
400        writer.indentPrintln("border:1px solid #000000;");
401        writer.indentPrintln("background-color:#f2f2f2;");
402        writer.indentPrintln("color:#222222;");
403        writer.indentPrintln("text-align:left;");
404        writer.indentPrintln("vertical-align:top;");
405        writer.indentPrintln("font-weight:bold;");
406        writer.indentPrintln("font-style:italic;");
407        writer.indentPrintln("");
408        writer.indentPrintln("}");
409        writer.indentPrintln("");
410        writer.indentPrintln("table.structTable td.structLName {");
411        writer.indentPrintln("border:1px solid #000000;");
412        writer.indentPrintln("background:#ffffff;");
413        writer.indentPrintln("vertical-align:top;");
414        writer.indentPrintln("");
415        writer.indentPrintln("}");
416        writer.indentPrintln("");
417        writer.indentPrintln("table.structTable td.structType {");
418        writer.indentPrintln("border:1px solid #000000;");
419        writer.indentPrintln("background:#ffffff;");
420        writer.indentPrintln("vertical-align:top;");
421        writer.indentPrintln("font-style:italic;");
422        writer.indentPrintln("");
423        writer.indentPrintln("}");
424        writer.indentPrintln("");
425        writer.indentPrintln("table.structTable td.structDesc {");
426        writer.indentPrintln("border:1px solid #000000;");
427        writer.indentPrintln("background:#ffffff;");
428        writer.indentPrintln("vertical-align:top;");
429        writer.indentPrintln("");
430        writer.indentPrintln("}");
431        writer.indentPrintln("");
432        writer.indentPrintln("table.structTable td.structOpt {");
433        writer.indentPrintln("border:1px solid #000000;");
434        writer.indentPrintln("background:#ffffff;");
435        writer.indentPrintln("vertical-align:top;");
436        writer.indentPrintln("text-align: center;");
437        writer.indentPrintln("}");
438        writer.indentPrintln("");
439        writer.indentPrintln("table.structTable td.structReq {");
440        writer.indentPrintln("border:1px solid #000000;");
441        writer.indentPrintln("background:#ccccff;");
442        writer.indentPrintln("vertical-align:top;");
443        writer.indentPrintln("text-align: center;");
444        writer.indentPrintln("}");
445        writer.indentPrintln("");
446        writer.indentPrintln("");
447        writer.indentPrintln("table.structTable td.structCard {");
448        writer.indentPrintln("border:1px solid #000000;");
449        writer.indentPrintln("background:#ffffff;");
450        writer.indentPrintln("vertical-align:top;");
451        writer.indentPrintln("text-align: center;");
452        writer.indentPrintln("}");
453        writer.indentPrintln("");
454        writer.indentPrintln("table.structTable td.structAttr {");
455        writer.indentPrintln("border:1px solid #000000;");
456        writer.indentPrintln("background:#ffffff;");
457        writer.indentPrintln("vertical-align:top;");
458        writer.indentPrintln("text-align: center;");
459        writer.indentPrintln("}");
460        writer.indentPrintln("");
461        writer.indentPrintln("table.structTable td.structElem {");
462        writer.indentPrintln("border:1px solid #000000;");
463        writer.indentPrintln("background:#ccccff;");
464        writer.indentPrintln("vertical-align:top;");
465        writer.indentPrintln("text-align: center;");
466        writer.indentPrintln("}");
467        writer.indentPrintln("");
468        writer.indentPrintln("table.structTable td.structStatus {");
469        writer.indentPrintln("border:1px solid #000000;");
470        writer.indentPrintln("background:#ffffff;");
471        writer.indentPrintln("vertical-align:top;");
472        writer.indentPrintln("text-align: center;");
473        writer.indentPrintln("");
474        writer.indentPrintln("}");
475        writer.indentPrintln("");
476        writer.indentPrintln("table.structTable td.commentsDesc {");
477        writer.indentPrintln("border:1px solid #000000;");
478        writer.indentPrintln("background:#ffffff;");
479        writer.indentPrintln("vertical-align:top;");
480        writer.indentPrintln("");
481        writer.indentPrintln("}");
482        writer.indentPrintln("");
483        writer.indentPrintln("");
484        writer.indentPrintln("</style>");
485
486
487    }
488}