001/**
002 * Copyright 2010 The Kuali Foundation Licensed under the
003 * Educational Community License, Version 2.0 (the "License"); you may
004 * not use this file except in compliance with the License. You may
005 * obtain a copy of the License at
006 *
007 * http://www.osedu.org/licenses/ECL-2.0
008 *
009 * Unless required by applicable law or agreed to in writing,
010 * software distributed under the License is distributed on an "AS IS"
011 * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
012 * or implied. See the License for the specific language governing
013 * permissions and limitations under the License.
014 */
015package org.kuali.student.r1.common.assembly.dictionary;
016
017import java.util.ArrayList;
018import java.util.Collections;
019import java.util.List;
020import java.util.Set;
021
022import org.kuali.student.r1.common.assembly.data.ConstraintMetadata;
023import org.kuali.student.r1.common.assembly.data.Data;
024import org.kuali.student.r1.common.assembly.data.LookupMetadata;
025import org.kuali.student.r1.common.assembly.data.LookupParamMetadata;
026import org.kuali.student.r1.common.assembly.data.Metadata;
027import org.kuali.student.r1.common.assembly.data.MetadataInterrogator;
028
029@Deprecated
030public class MetadataFormatter {
031
032        private StringBuilder builder = new StringBuilder(5000);
033        private Metadata structureMetadata;
034        private String type;
035        private String rowSeperator = "\n";
036        private String colSeperator = "|";
037        private String structureName;
038        private int level;
039//      private Map<String, Metadata> subStructuresToProcess = new LinkedHashMap<String, Metadata>();
040        private Set<Metadata> structuresAlreadyProcessed;
041        private MetadataFormatter parent;
042
043        public MetadataFormatter(String structureName, Metadata structureMetadata,
044                        String type, MetadataFormatter parent,
045                        Set<Metadata> structuresAlreadyProcessed, int level) {
046                this.structureName = structureName;
047                this.structureMetadata = structureMetadata;
048                this.type = type;
049                this.parent = parent;
050                this.structuresAlreadyProcessed = structuresAlreadyProcessed;
051                this.level = level;
052        }
053
054        public String getStructureName() {
055                return structureName;
056        }
057
058        public MetadataFormatter getParent() {
059                return parent;
060        }
061
062        public String getRowSeperator() {
063                return rowSeperator;
064        }
065
066        public void setRowSeperator(String rowSeperator) {
067                this.rowSeperator = rowSeperator;
068        }
069
070        public String getColSeparator() {
071                return colSeperator;
072        }
073
074        public void setColSeparator(String separator) {
075                this.colSeperator = separator;
076        }
077
078        private String pad(String str, int size) {
079                StringBuilder padStr = new StringBuilder(size);
080                padStr.append(str);
081                while (padStr.length() < size) {
082                        padStr.append(' ');
083                }
084                return padStr.toString();
085        }
086
087        public String formatForWiki() {
088                if (!this.structuresAlreadyProcessed.add(structureMetadata)) {
089                        return "";
090                }
091                if (level == 1) {
092                        builder.append(rowSeperator);
093                        // builder.append
094                        // ("======= start dump of object structure definition ========");
095                        builder.append(rowSeperator);
096                        String header = "h1. " + this.calcSimpleName(structureName);
097                        if (type != null) {
098                                header = "h2. " + type;
099                        }
100                        builder.append(header);
101                        builder.append("{anchor:" + structureName + "}");
102                        builder.append(rowSeperator);
103                        builder.append("The object key is " + structureName);
104                        builder.append(rowSeperator);
105                        builder.append("The type is " + type);
106                        builder.append(rowSeperator);
107                        builder.append(colSeperator);
108                        builder.append(colSeperator);
109                        builder.append("Field");
110                        builder.append(colSeperator);
111                        builder.append(colSeperator);
112                        builder.append("Required?");
113                        builder.append(colSeperator);
114                        builder.append(colSeperator);
115                        builder.append("DataType");
116                        builder.append(colSeperator);
117                        builder.append(colSeperator);
118                        builder.append("Length");
119                        builder.append(colSeperator);
120                        builder.append(colSeperator);
121                        builder.append("Dynamic");
122                        builder.append(colSeperator);
123                        builder.append(colSeperator);
124                        builder.append("Default");
125                        builder.append(colSeperator);
126                        builder.append(colSeperator);
127                        builder.append("Repeats?");
128                        builder.append(colSeperator);
129                        builder.append(colSeperator);
130                        builder.append("Valid Characters");
131                        builder.append(colSeperator);
132                        builder.append(colSeperator);
133                        builder.append("Lookup Widget");
134                        builder.append(colSeperator);
135                        builder.append(colSeperator);
136                        builder.append("Lookup");
137                        builder.append(colSeperator);
138                        builder.append(colSeperator);
139                        builder.append(rowSeperator);
140                }
141
142                List<String> keys = new ArrayList<String>();
143                keys.addAll(structureMetadata.getProperties().keySet());
144                Collections.sort(keys);
145                for (String key : keys) {
146   if (key.equalsIgnoreCase ("_runtimeData"))
147   {
148    continue;
149   }
150                        Metadata fieldMeta = structureMetadata.getProperties().get(key);
151                        builder.append(colSeperator);
152                        builder.append(calcFieldInfo (key, fieldMeta));
153                        builder.append(colSeperator);
154                        builder.append(pad(calcRequired(fieldMeta), 10));
155                        builder.append(colSeperator);
156                        builder.append(pad(calcDataType(fieldMeta), 25));
157                        builder.append(colSeperator);
158                        builder.append(pad(calcLength(fieldMeta), 15));
159                        builder.append(colSeperator);
160                        builder.append(pad(calcDynamic(fieldMeta), 7));
161                        builder.append(colSeperator);
162                        builder.append(pad(calcDefaultValue(fieldMeta), 15));
163                        builder.append(colSeperator);
164                        builder.append(calcRepeating(fieldMeta));
165                        builder.append(colSeperator);
166                        builder.append(calcValidChars(fieldMeta));
167                        builder.append(colSeperator);
168                        builder.append(calcWidget(fieldMeta));
169                        builder.append(colSeperator);
170                        builder.append(calcLookup(fieldMeta));
171                        builder.append(colSeperator);
172                        builder.append(rowSeperator);
173                        if (fieldMeta.getDataType().equals(Data.DataType.DATA)
174                                        || fieldMeta.getDataType().equals(Data.DataType.LIST)) {
175                                if (fieldMeta.getProperties() == null) {
176                                        throw new IllegalArgumentException(
177                                                        fieldMeta.getName()
178                                                                        + " is DATA but does not have a sub-structure defined");
179                                }
180                                MetadataFormatter formatter = new MetadataFormatter(key,
181                                                fieldMeta, null, this, structuresAlreadyProcessed,
182                                                level + 1);
183                                builder.append(formatter.formatForWiki());
184                        }
185                }
186
187                return builder.toString();
188        }
189
190        private String calcDataType(Metadata fieldMeta) {
191                if (fieldMeta.getDataType().equals(Data.DataType.LIST)) {
192                        StringBuilder type = new StringBuilder();
193                        type.append("LIST of ");
194                        String comma = "";
195                        for (String key : fieldMeta.getProperties().keySet()) {
196                                type.append(comma);
197                                type.append(fieldMeta.getProperties().get(key).getDataType()
198                                                .toString());
199                                comma = ", ";
200                        }
201                        return type.toString();
202                }
203                return fieldMeta.getDataType().toString();
204        }
205
206        private String calcDefaultValue(Metadata fieldMeta) {
207                if (fieldMeta.getDefaultValue() != null) {
208                        return fieldMeta.getDefaultValue().toString();
209                }
210                return " ";
211        }
212
213        private String calcDynamic(Metadata meta) {
214                if (meta.isDynamic()) {
215                        return "dynamic";
216                }
217                return " ";
218        }
219
220 private String calcFieldInfo (String key, Metadata fieldMeta)
221 {
222  StringBuilder bldr = new StringBuilder (40);
223  bldr.append (pad(calcFullyQualifiedFieldName(key), 30));
224  if (fieldMeta.getLabelKey () != null)
225  {
226   bldr.append ("\\\\\n");
227   bldr.append ("Label: ");
228   bldr.append (fieldMeta.getLabelKey ());
229  }
230  return bldr.toString ();
231 }
232
233        public String calcFullyQualifiedFieldName(String fieldName) {
234                if (parent == null) {
235                        return escapeWiki(fieldName);
236                }
237                return parent.calcFullyQualifiedFieldName(structureName) + "."
238                                + escapeWiki(fieldName);
239        }
240
241        private String calcSimpleName(String name) {
242                if (name.lastIndexOf(".") != -1) {
243                        name = name.substring(name.lastIndexOf(".") + 1);
244                }
245                return name;
246        }
247
248        private String calcNotSoSimpleName(String name) {
249                if (name.lastIndexOf(".") == -1) {
250                        return name;
251                }
252                String simpleName = calcSimpleName(name);
253                String fieldName = calcSimpleName(name.substring(0, name.length()
254                                - simpleName.length() - 1));
255                return fieldName + "." + simpleName;
256        }
257
258        private String calcRequired(Metadata fieldMeta) {
259                for (ConstraintMetadata cons : fieldMeta.getConstraints()) {
260                        if (cons.getMaxOccurs() != null) {
261                                if (cons.getMaxOccurs() == 0) {
262                                        return "NOT USED";
263                                }
264                        }
265
266                        if (cons.getMinOccurs() != null) {
267                                if (cons.getMinOccurs() >= 1) {
268                                        return "required";
269                                }
270                        }
271                }
272                return " ";
273                // return "optional";
274        }
275
276        private static final String LINK_TO_DEFINITIONS = "KULSTG:Formatted View of Base Dictionary#Valid Character Definitions";
277
278        private String calcValidChars(Metadata fieldMeta) {
279                for (ConstraintMetadata cons : fieldMeta.getConstraints()) {
280                        if (cons.getValidChars() == null) {
281                                continue;
282                        }
283                        String validChars = escapeWiki(cons.getValidChars());
284                        String descr = "[" + "See" + "|" + LINK_TO_DEFINITIONS + "]"
285                                        + "\\\\\n" + validChars;
286                        return descr;
287                }
288                return " ";
289        }
290
291        private String escapeWiki(String str) {
292                StringBuilder bldr = new StringBuilder(str.length());
293                boolean precededByBackSlash = false;
294                for (int i = 0; i < str.length(); i++) {
295                        char c = str.charAt(i);
296                        switch (c) {
297                        case '\\':
298                        case '[':
299                        case '*':
300                        case ']':
301                        case '|':
302                                if (!precededByBackSlash) {
303                                        bldr.append('\\');
304                                }
305                                break;
306                        default:
307                                break;
308                        }
309                        bldr.append(c);
310                        if (c == '\\') {
311                                precededByBackSlash = true;
312                        } else {
313                                precededByBackSlash = false;
314                        }
315                }
316                return bldr.toString();
317        }
318
319        private String calcWidget(Metadata fieldMeta) {
320                StringBuilder bldr = new StringBuilder();
321                String comma = "";
322                if (!fieldMeta.isCanEdit()) {
323                        bldr.append(comma);
324                        bldr.append("not editable");
325                        comma = ", ";
326                }
327                if (!fieldMeta.isCanView()) {
328                        bldr.append(comma);
329                        bldr.append("not viewable");
330                        comma = ", ";
331                }
332                if (!fieldMeta.isCanUnmask()) {
333                        bldr.append(comma);
334                        bldr.append("Not unmaskable");
335                        comma = ", ";
336                }
337                if (fieldMeta.getInitialLookup() != null) {
338                        bldr.append(comma);
339                        bldr.append(fieldMeta.getInitialLookup().getWidget());
340                        comma = ", ";
341                }
342                if (bldr.length() == 0) {
343                        bldr.append(" ");
344                }
345                return bldr.toString();
346        }
347
348        private String calcLookup(Metadata fieldMeta) {
349  StringBuilder bldr = new StringBuilder ();
350                if (fieldMeta.getInitialLookup() != null) {
351                 bldr.append (calcLookup (fieldMeta.getInitialLookup ()));
352                }
353   
354  if (fieldMeta.getAdditionalLookups () != null) {
355   if (fieldMeta.getAdditionalLookups ().size () > 0) {
356    if (fieldMeta.getInitialLookup() == null) {
357                   bldr.append ("No initial lookup but...");
358                  }
359                  bldr.append("\\\\");
360                  bldr.append("\n");   
361                  bldr.append("\\\\");
362                  bldr.append("\n");
363    bldr.append ("Additional Lookups:");
364                  bldr.append("\\\\");
365                  bldr.append("\n");
366   }
367   for (LookupMetadata lm : fieldMeta.getAdditionalLookups ())  {
368                  bldr.append("\\\\");
369                bldr.append("\n");
370    bldr.append (calcLookup (lm));
371    bldr.append("\\\\");
372                  bldr.append("\n");
373   }  
374  }
375  if (bldr.length () == 0)
376  {
377   bldr.append (" ");
378  }
379  return bldr.toString ();
380 }
381
382 private String calcLookup(LookupMetadata lm) {
383                StringBuilder bldr = new StringBuilder();
384                bldr.append(lm.getId());
385//  if (lm.getUsage () != null) {
386//   bldr.append (" usage " + lm.getUsage ());
387//  }
388                // this is the search description not the lookup description
389                bldr.append (" - ");
390                bldr.append (lm.getName());
391  bldr.append (" " + lm.getWidget ());
392  String and = " with option ";
393  if (lm.getWidgetOptions () != null) {
394   for (LookupMetadata.WidgetOption wo: lm.getWidgetOptions ().keySet ())
395   {
396    bldr.append (" and ");
397    bldr.append (wo);
398    bldr.append ("=");
399    bldr.append (lm.getWidgetOptions ().get (wo));
400   }
401  }
402                and = "";
403                bldr.append("\\\\\n");
404                bldr.append("Implemented using search: ");
405                String searchPage = calcWikiSearchPage(lm.getSearchTypeId());
406                bldr.append("[" + lm.getSearchTypeId() + "|" + searchPage + "#"
407                                + lm.getSearchTypeId() + "]");
408                List<LookupParamMetadata> configuredParameters = filterConfiguredParams(lm
409                                .getParams());
410                if (configuredParameters.size() > 0) {
411                        bldr.append("\\\\");
412                        bldr.append("\n");
413                        bldr.append(" where ");
414                        and = "";
415                        for (LookupParamMetadata param : configuredParameters) {
416                                bldr.append(and);
417                                and = " and ";
418                                bldr.append(param.getName());
419    bldr.append (" (" + param.getDataType () + ") ");
420                                bldr.append("=");
421                                if (param.getDefaultValueString() != null) {
422                                        bldr.append(param.getDefaultValueString());
423                                }
424                                if (param.getDefaultValueList() != null) {
425                                        String comma = "";
426                                        for (String defValue : param.getDefaultValueList()) {
427                                                bldr.append(comma);
428                                                comma = ", ";
429                                                bldr.append(defValue);
430                                        }
431                                }
432                        }
433  }
434  List<LookupParamMetadata> userEnterableParameters = this.filterUserEnterableParams (lm
435                                .getParams());
436                if (userEnterableParameters.size() > 0) {
437                        bldr.append("\\\\");
438                        bldr.append("\n");
439                        bldr.append(" and the user can enter: ");
440                        for (LookupParamMetadata param : userEnterableParameters) {
441                                bldr.append ("\\\\\n");
442                                bldr.append(param.getName());
443    bldr.append (" (" + param.getDataType () + ")");
444    if (param.getWidget () != null) {
445                                 bldr.append(" using widget ");
446     bldr.append (param.getWidget ());
447    }
448                                if (param.getDefaultValueString() != null) {
449                                        bldr.append("defaulted to " + param.getDefaultValueString());
450                                }
451                                if (param.getDefaultValueList() != null) {
452                                        String comma = "defaulted to ";
453                                        for (String defValue : param.getDefaultValueList()) {
454                                                bldr.append(comma);
455                                                comma = ", ";
456                                                bldr.append(defValue);
457                                        }
458                                }
459    if (param.getChildLookup () != null)
460    {
461                          bldr.append("\\\\");
462                          bldr.append("\n");
463     bldr.append ("using a child lookup: ");
464                          bldr.append("\\\\");
465                          bldr.append("\n");
466     bldr.append (calcLookup (param.getChildLookup ()));
467    }
468   }
469                }
470                return bldr.toString();
471 }
472
473        private static final String PAGE_PREFIX = "Formatted View of ";
474        private static final String PAGE_SUFFIX = " Searches";
475
476        private String calcWikiSearchPage(String searchType) {
477                return PAGE_PREFIX + calcWikigPageAbbrev(searchType) + PAGE_SUFFIX;
478        }
479
480        private String calcWikigPageAbbrev(String searchType) {
481                if (searchType == null) {
482                        return null;
483                }
484                if (searchType.equals("enumeration.management.search")) {
485                        return "EM";
486                }
487                if (searchType.startsWith("lu.")) {
488                        return "LU";
489                }
490                if (searchType.startsWith("cluset.")) {
491                        return "LU";
492                }
493                if (searchType.startsWith("lo.")) {
494                        return "LO";
495                }
496                if (searchType.startsWith("lrc.")) {
497                        return "LRC";
498                }
499                if (searchType.startsWith("comment.")) {
500                        return "Comment";
501                }
502                if (searchType.startsWith("org.")) {
503                        return "Organization";
504                }
505                if (searchType.startsWith("atp.")) {
506                        return "ATP";
507                }
508                if (searchType.startsWith("person.")) {
509                        return "Person";
510                }
511                if (searchType.startsWith("proposal.")) {
512                        return "Proposal";
513                }
514                if (searchType.startsWith("subjectCode.")) {
515                        return "SC";
516                }
517                throw new IllegalArgumentException("Unknown type of search: "
518                                + searchType);
519        }
520
521        private List<LookupParamMetadata> filterConfiguredParams(
522                        List<LookupParamMetadata> params) {
523                List<LookupParamMetadata> list = new ArrayList<LookupParamMetadata>();
524                if (params == null) {
525                        return list;
526                }
527                if (params.size() == 0) {
528                        return list;
529                }
530                for (LookupParamMetadata param : params) {
531                        if (param.getDefaultValueString() != null) {
532                                list.add(param);
533                                continue;
534                        }
535                        if (param.getDefaultValueList() != null) {
536                                list.add(param);
537    continue;
538                        }
539                }
540                return list;
541        }
542
543        private List<LookupParamMetadata> filterUserEnterableParams (
544                        List<LookupParamMetadata> params) {
545                List<LookupParamMetadata> list = new ArrayList<LookupParamMetadata>();
546                if (params == null) {
547                        return list;
548                }
549                if (params.size() == 0) {
550                        return list;
551                }
552                for (LookupParamMetadata param : params) {
553                        if (param.getWriteAccess () != null) {
554    if ( ! param.getWriteAccess ().equals (Metadata.WriteAccess.NEVER)) {
555                                list.add(param);
556                                continue;
557    }
558                        }
559                }
560                return list;
561        }
562
563        private String calcRepeating(Metadata fieldMeta) {
564                if (!fieldMeta.getDataType().equals(Data.DataType.LIST)) {
565                        return " ";
566                }
567                // return "repeating";
568                MetadataInterrogator mi = new MetadataInterrogator(fieldMeta);
569                if (mi.getSmallestMaxOccurs() == null) {
570                        if (mi.getLargestMinOccurs() != null
571                                        && mi.getLargestMinOccurs() > 1) {
572                                return "repeating: minimum " + mi.getLargestMinOccurs()
573                                                + " times";
574                        }
575                        return "repeating: unlimited";
576                }
577                if (mi.getSmallestMaxOccurs() == 0) {
578                        return "NOT USED";
579                }
580                if (mi.getSmallestMaxOccurs() == 1) {
581                        return " ";
582                        // return "single";
583                }
584
585                if (mi.getLargestMinOccurs() != null) {
586                        if (mi.getLargestMinOccurs() > 1) {
587                                return "repeating: " + mi.getLargestMinOccurs() + " to "
588                                                + mi.getSmallestMaxOccurs() + " times";
589                        }
590                }
591                return "repeating: maximum " + mi.getSmallestMaxOccurs() + " times";
592        }
593
594        private String calcLength(Metadata fieldMeta) {
595                MetadataInterrogator mi = new MetadataInterrogator(fieldMeta);
596                if (mi.getSmallestMaxLength() != null) {
597                        if (mi.getLargestMinLength() != null
598                                        && mi.getLargestMinLength() != 0) {
599                                if (mi.getSmallestMaxLength() == mi.getLargestMinLength()) {
600                                        return ("(must be " + mi.getSmallestMaxLength() + ")");
601                                }
602                                return "(" + mi.getLargestMinLength() + " to "
603                                                + mi.getSmallestMaxLength() + ")";
604                        }
605                        return "(up to " + mi.getSmallestMaxLength() + ")";
606                }
607                if (mi.getLargestMinLength() != null) {
608                        return "(over " + mi.getLargestMinLength() + ")";
609                }
610                return " ";
611        }
612}