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