1    package com.instantbank.component.lettertemplate.util;
2    
3    import java.io.Serializable;
4    import java.util.ArrayList;
5    
6    import com.instantbank.common.uiutils.MessageFrame;
7    import com.instantbank.common.utilcomponents.LetterTemplateGlobals;
8    import com.instantbank.common.utilcomponents.LetterTemplateExceptionMessage;
9    import com.instantbank.lettertemplate.editor.web.TemplateTransformer;
10   import com.instantbank.lettertemplate.control.LetterTemplateEventException;
11   import com.instantbank.lettertemplate.control.util.JSPUtil;
12   
13   /**
14    *  In memory representation of a letter template.
15    *
16    * @author InstantBank (Rodrigo Lopez)
17    * @created September 2002
18    */
19   public class Template
20       implements Serializable, LetterViewable {
21   
22     /**
23      *  Integer code for the LASER print type.
24      */
25     public static final int LASER = 1;
26   
27     /**
28      *  Integer code for the TYPEWRITTER print type.
29      */
30     public static final int TYPEWRITTER = 2;
31   
32     /**
33      *  The template can be saved without worrying about its components.
34      */
35     public static final int OK = 0;
36   
37     /**
38      *  The template has changed one of its components.
39      */
40     public static final int NEW_COMPONENT = 1;
41   
42     /**
43      *  The header component.
44      */
45     private LetterComponent header;
46   
47     /**
48      *  The body component.
49      */
50     private LetterComponent body;
51   
52     /**
53      *  The closing component.
54      */
55     private LetterComponent closing;
56   
57     /**
58      *  The name of the template
59      */
60     private String name;
61   
62     /**
63      *  The Template code in the data base.
64      */
65   
66     private long code;
67     /**
68      *  The category code (for the template) in the data base.
69      */
70     private long category;
71   
72     /**
73      *  The print type: LASER/TYPEWRITTER
74      */
75     private int printType;
76   
77     /**
78      *  The time stamp of the last time the template was saved.
79      */
80     private String stamp;
81   
82     /**
83      *  Save status for the template: OK or NEW_COMPONENT.
84      */
85     public int saveStatus;
86   
87     /**
88      * Left margin (in twips = 1/1440 inches).
89      */
90     private int leftMargin = LetterTemplateGlobals.DEFAULT_LEFT_MARGIN;
91   
92     /**
93      * Right margin (in twips = 1/1440 inches).
94      */
95     private int rightMargin = LetterTemplateGlobals.DEFAULT_RIGHT_MARGIN;
96   
97     /**
98      * Top margin (in twips = 1/1440 inches).
99      */
100    private int topMargin = LetterTemplateGlobals.DEFAULT_TOP_MARGIN;
101  
102    /**
103     * Bottom margin (in twips = 1/1440 inches).
104     */
105    private int bottomMargin = LetterTemplateGlobals.DEFAULT_BOTTOM_MARGIN;
106  
107  
108    /**
109     *  Basic constructor used to initialize the Template when the editor starts.
110     *
111     * @param printType The print type: LASER, TYPEWRITER.
112     */
113    public Template(int printType) {
114      code = LetterTemplateGlobals.UNDEF;
115      category = LetterTemplateGlobals.UNDEF;
116      this.printType = printType;
117  
118      header = new LetterComponent(LetterComponent.HEADER, printType);
119      body = new LetterComponent(LetterComponent.BODY, printType);
120      closing = new LetterComponent(LetterComponent.CLOSING, printType);
121      name = LetterTemplateGlobals.STR_UNNAMED;
122      stamp = LetterTemplateGlobals.STR_UNDEF;
123    }
124  
125  
126  
127    /**
128     *  Big constructor, defines explicitly all the attributes of the Template.
129     *
130     * @param code Template's code
131     * @param name Template's description
132     * @param category Template's category
133     * @param printType Print type (lase, typewriter)
134     * @param header Header component
135     * @param body Body component
136     * @param closing Closing component
137     * @param timeStamp Time stamp when this template was saved for the last time.
138     * @param leftMargin Left margin when printed/previewed (in twips)
139     * @param rightMargin Left margin when printed/previewed (in twips)
140     * @param topMargin Left margin when printed/previewed (in twips)
141     * @param bottomMargin Left margin when printed/previewed (in twips)
142     */
143    public Template(long code, String name, long category, int printType,
144                    LetterComponent header, LetterComponent body, LetterComponent closing,
145                    String timeStamp, int leftMargin, int rightMargin, int topMargin,
146                    int bottomMargin) {
147      this.code = code;
148      this.name = name;
149      this.category = category;
150      this.printType = printType;
151      this.header = header;
152      this.body = body;
153      this.closing = closing;
154      this.stamp = timeStamp;
155      this.leftMargin = leftMargin;
156      this.rightMargin = rightMargin;
157      this.topMargin = topMargin;
158      this.bottomMargin = bottomMargin;
159    }
160  
161  
162    /**
163     *  Getter method for {@link #code}
164     *
165     * @return The code value
166     */
167    public long getCode() {
168      return code;
169    }
170  
171  
172    /**
173     *  Setter method for {@link #code}
174     *
175     * @param code The new code value
176     */
177    public void setCode(long code) {
178      this.code = code;
179    }
180  
181  
182    /**
183     *  Getter method for {@link #category}
184     *
185     * @return The category value
186     */
187    public long getCategory() {
188      return category;
189    }
190  
191  
192    /**
193     *  Setter method for {@link #category}
194     *
195     * @param c The new category value
196     */
197    public void setCategory(long c) {
198      category = c;
199    }
200  
201  
202    /**
203     *  Getter method for {@link #printType}
204     *
205     * @return The printType value
206     */
207    public int getPrintType() {
208      return printType;
209    }
210  
211  
212    /**
213     *  Setter method for {@link #printType}
214     *
215     * @param p The new printType value
216     */
217    public void setPrintType(int p) {
218      printType = p;
219    }
220  
221  
222    /**
223     *  Getter method for {@link #name}
224     *
225     * @return The name value
226     */
227    public String getName() {
228      return name;
229    }
230  
231  
232    /**
233     *  Setter method for {@link #name}
234     *
235     * @param nm The new name value
236     */
237    public void setName(String nm) {
238      name = nm;
239    }
240  
241  
242    /**
243     *  Getter method for {@link #header}
244     *
245     * @return The header value
246     */
247    public LetterComponent getHeader() {
248      return header;
249    }
250  
251  
252    /**
253     *  Setter method for {@link #header}
254     *
255     * @param cmp The new header value
256     */
257    public void setHeader(LetterComponent cmp) {
258      header = cmp;
259    }
260  
261  
262    /**
263     *  Getter method for {@link #body}
264     *
265     * @return The body value
266     */
267    public LetterComponent getBody() {
268      return body;
269    }
270  
271  
272    /**
273     *  Setter method for {@link #body}
274     *
275     * @param cmp The new body value
276     */
277    public void setBody(LetterComponent cmp) {
278      body = cmp;
279    }
280  
281  
282    /**
283     *  Getter method for {@link #closing}
284     *
285     * @return The closing value
286     */
287    public LetterComponent getClosing() {
288      return closing;
289    }
290  
291  
292    /**
293     *  Setter method for {@link #closing}
294     *
295     * @param cmp The new closing value
296     */
297    public void setClosing(LetterComponent cmp) {
298      closing = cmp;
299    }
300  
301  
302    /**
303     *  Getter method for {@link #stamp}
304     *
305     * @return The stamp value
306     */
307    public String getStamp() {
308      return stamp;
309    }
310  
311  
312    /**
313     *  Setter method for {@link #stamp}
314     *
315     * @param s The new stamp value
316     */
317    public void setStamp(String s) {
318      stamp = s;
319    }
320  
321  
322    /**
323     *  Getter methos for {@link #saveStatus}.
324     *
325     * @return The saveStatus value
326     */
327    public int getSaveStatus() {
328      return saveStatus;
329    }
330  
331  
332    /**
333     *  Setter method for {@link #saveStatus}
334     *
335     * @param status The new saveStatus value
336     */
337    public void setSaveStatus(int status) {
338      saveStatus = status;
339    }
340  
341  
342    /**
343     *  Gets a component of the template from its type.
344     *
345     * @param compType Type of the component: {@link LetterComponent#HEADER},
346     *      {@link LetterComponent#BODY}, {@link LetterComponent#CLOSING}.
347     * @return The component value
348     */
349    public LetterComponent getComponent(int compType) {
350      switch (compType) {
351        case LetterComponent.HEADER:
352          return header;
353        case LetterComponent.BODY:
354          return body;
355        case LetterComponent.CLOSING:
356          return closing;
357        default:
358          return null;
359      }
360    }
361  
362  
363    /**
364     *  Changes a template's component.
365     *
366     * @param compType The type of the component to be changed: {@link
367     *      LetterComponent#HEADER}, {@link LetterComponent#BODY}, {@link
368     *      LetterComponent#CLOSING}.
369     * @param comp The component that replaces the original one.
370     */
371    public void setComponent(int compType, LetterComponent comp) {
372  
373      switch (compType) {
374        case LetterComponent.HEADER:
375          header = comp;
376          break;
377        case LetterComponent.BODY:
378          body = comp;
379          break;
380        case LetterComponent.CLOSING:
381          closing = comp;
382          break;
383        default:
384          break;
385      }
386    }
387  
388  
389    /**
390     * Getter method for leftMargin
391     *
392     * @return The leftMargin value
393     */
394    public int getLeftMargin() {
395      return leftMargin;
396    }
397  
398  
399    /**
400     * Setter method for leftMargin
401     *
402     * @param twips left margin (in twips).
403     */
404    public void setLeftMargin(int twips) {
405      leftMargin = twips;
406    }
407  
408  
409    /**
410     * Getter method for rightMargin
411     *
412     * @return The rightMargin value
413     */
414    public int getRightMargin() {
415      return rightMargin;
416    }
417  
418  
419    /**
420     * Setter method for rightMargin
421     *
422     * @param twips right margin (in twips).
423     */
424    public void setRightMargin(int twips) {
425      rightMargin = twips;
426    }
427  
428  
429    /**
430     * Getter method for topMargin
431     *
432     * @return The topMargin value
433     */
434    public int getTopMargin() {
435      return topMargin;
436    }
437  
438  
439    /**
440     * Setter method for topMargin
441     *
442     * @param twips margin (in twips).
443     */
444    public void setTopMargin(int twips) {
445      topMargin = twips;
446    }
447  
448  
449    /**
450     * Getter method for bottomMargin
451     *
452     * @return The bottomMargin value
453     */
454    public int getBottomMargin() {
455      return bottomMargin;
456    }
457  
458  
459    /**
460     * Setter method for Margin
461     *
462     * @param twips margin (in twips).
463     */
464    public void setBottomMargin(int twips) {
465      bottomMargin = twips;
466    }
467  
468  
469    /**
470     *  Produces a human readable/printable version of the code, name and stamp
471     *  attributes of this template and its components.
472     *
473     * @return String
474     */
475    public String codesToString() {
476      String res = "Template = <" + code + " , " + name + "," + stamp + ">\n";
477      if(header != null) {
478        res += "Header = " + header.codesToString() + "\n";
479      }
480      if(body != null) {
481        res += "Body = " + body.codesToString() + "\n";
482      }
483      if(closing != null) {
484        res += "Closing = " + closing.codesToString() + "\n";
485      }
486      return res;
487    }
488  
489  
490    /**
491     *  Calculates the set --without repetitions-- of codes of variables mentioned
492     *  in any of the components of this template. Each variable will be paired with
493     *  a list of formats.
494     *
495     * @return Array of [varCode, [format1, format2, ..]]. If there is no
496     *      variables, returns an array with 0 entries.
497     */
498    public ArrayList[] setOfVariables() {
499  
500      ArrayList allVars = (ArrayList)header.getTraceVariables().clone();
501      allVars.addAll(body.getTraceVariables());
502      allVars.addAll(closing.getTraceVariables());
503  
504      return TemplateTransformer.setOfVariables(allVars);
505    }
506  
507  
508    /**
509     *  Produces an array with information of images, in ascending order through
510     *  all the text. The position information is kept but is meaningless in this
511     *  case.
512     *
513     * @return An array of <position, image>
514     */
515    public ArrayList[] getAllImages() {
516      ArrayList hd = getHeader().getTraceImages();
517      ArrayList bd = getBody().getTraceImages();
518      ArrayList cl = getClosing().getTraceImages();
519  
520      ArrayList[] res = new ArrayList[hd.size() + bd.size() + cl.size()];
521  
522      int i = 0;
523  
524      int j;
525  
526      j = hd.size() - 1;
527      while(j >= 0) {
528        res[i++] = (ArrayList)hd.get(j--);
529      }
530  
531      j = bd.size() - 1;
532      while(j >= 0) {
533        res[i++] = (ArrayList)bd.get(j--);
534      }
535  
536      j = cl.size() - 1;
537      while(j >= 0) {
538        res[i++] = (ArrayList)cl.get(j--);
539      }
540  
541      return res;
542    }
543  
544  
545    /**
546     *  Produces an array with information of variables, in ascending order
547     *  through all the text. The position information is kept but is meaningless
548     *  in this case.
549     *
550     * @return An array of <position, fieldCode, formatCode>
551     */
552    public ArrayList[] getAllVariables() {
553      ArrayList hd = getHeader().getTraceVariables();
554      ArrayList bd = getBody().getTraceVariables();
555      ArrayList cl = getClosing().getTraceVariables();
556  
557      ArrayList[] res = new ArrayList[hd.size() + bd.size() + cl.size()];
558  
559      int i = 0;
560  
561      int j;
562  
563      j = hd.size() - 1;
564      while(j >= 0) {
565        res[i++] = (ArrayList)hd.get(j--);
566      }
567  
568      j = bd.size() - 1;
569      while(j >= 0) {
570        res[i++] = (ArrayList)bd.get(j--);
571      }
572  
573      j = cl.size() - 1;
574      while(j >= 0) {
575        res[i++] = (ArrayList)cl.get(j--);
576      }
577  
578      return res;
579    }
580  
581  
582    /**
583     *  Tests if this template contains variables.
584     *
585     * @return True if it has variables, False otherwise.
586     */
587    public boolean hasVariables() {
588      int num = header.getTraceVariables().size() +
589        body.getTraceVariables().size() +
590        closing.getTraceVariables().size();
591  
592      return num > 0;
593    }
594  
595  
596    /**
597     *  Tests if this template contains images.
598     *
599     * @return True if it has images, False otherwise.
600     */
601    public boolean hasImages() {
602      int num = header.getTraceImages().size() +
603        body.getTraceImages().size() +
604        closing.getTraceImages().size();
605  
606      return num > 0;
607    }
608  
609  
610    /**
611     *  Test if this template has changed; i.e, if any of its components has
612     *  changed.
613     *
614     * @return True if it has changed, False otherwise.
615     */
616    public boolean hasChanged() {
617      return header.hasChanged || body.hasChanged || closing.hasChanged;
618    }
619  
620  
621    /**
622     *  Sets to false all of its component's "hasChanged" attribute.
623     */
624    public void upToDate() {
625      header.hasChanged = false;
626      body.hasChanged = false;
627      closing.hasChanged = false;
628    }
629  
630  
631    /**
632     *  Sets to true all of its component's "hasChanged" attribute.
633     */
634    public void outOfDate() {
635      header.hasChanged = true;
636      body.hasChanged = true;
637      closing.hasChanged = true;
638    }
639  
640  
641    /**
642     * Produces the append of the rtf text contained in the header, body and
643     * closing of this template. Due to a bug in swing's RTFEditorKit, here we also
644     * substitute the "\fnil" font family by actual font families. The current
645     * families in the system are "\fmodern, \froman and \fswiss". The
646     * substitution is guided by the equivalences established by FONT constants in
647     * class LetterOp. The central part of the algorithm replaces ocurrences of a
648     * font table like <pre>
649     * {\fonttbl\f0\fnil Monospaced;\f1\fnil Times New Roman;\f2\fnil Arial;}
650     * </pre>
651     * by something with actual font families like: <pre>
652     * {\fonttbl\f0\fmodern Courier;\f1\froman Times;\f2\fswiss helvetica;}
653     * </pre> <p>
654     *
655     * @return The appended rtf text of the three template components.
656     */
657    public String extractRtf() {
658      String header = this.getHeader().getRtfText();
659      StringBuffer res = new StringBuffer(header);
660  
661      //Replaces the header's font table
662      int startFontTable = 0;
663      int endFontTable = 0;
664      String fontTable = "";
665  
666      startFontTable = header.indexOf("\\fonttbl");
667      endFontTable = header.indexOf("}", startFontTable);
668  
669      fontTable = header.substring(startFontTable, endFontTable);
670      String actFontTable = TemplateTransformer.actualFontTable(fontTable);
671  
672      res.replace(startFontTable, endFontTable, actFontTable);
673  
674      endFontTable = startFontTable + actFontTable.length() + 1;
675      res.insert(endFontTable, buildRtfMargins());
676  
677      //deletes header's final '}'
678      int i = res.length() - 1;
679      while(res.charAt(i) != '}') {
680        i--;
681      }
682      res.delete(i, res.length());
683  
684      //separates header from body with end of line.
685      res.append('\n');
686  
687      String body = this.getBody().getRtfText();
688      StringBuffer bres = new StringBuffer(body);
689  
690      startFontTable = body.indexOf("\\fonttbl");
691      endFontTable = body.indexOf("}", startFontTable);
692  
693      fontTable = body.substring(startFontTable, endFontTable);
694      bres.replace(startFontTable, endFontTable,
695        TemplateTransformer.actualFontTable(fontTable));
696  
697      //deletes body's final '}'
698      i = bres.length() - 1;
699      while(bres.charAt(i) != '}') {
700        i--;
701      }
702      bres.delete(i, bres.length());
703  
704      //separates body from closing with end of line.
705      bres.append('\n');
706  
707      //Appends new body including opening '{' from font table.
708      res.append(bres.substring(startFontTable - 1));
709  
710      String closing = this.getClosing().getRtfText();
711      StringBuffer cres = new StringBuffer(closing);
712  
713      //Locates closing's font table
714      startFontTable = closing.indexOf("\\fonttbl");
715      endFontTable = closing.indexOf("}", startFontTable);
716  
717      fontTable = closing.substring(startFontTable, endFontTable);
718      cres.replace(startFontTable, endFontTable,
719        TemplateTransformer.actualFontTable(fontTable));
720  
721      //Appends new closing including opening '{' from font table.
722      res.append(cres.substring(startFontTable - 1));
723  
724      return res.toString();
725    }
726  
727  
728    /**
729     * Transform this LetterTemplate in a "fo-template" without external references to
730     * image files.
731     *
732     * @return The fo-template --as a String-- or null if something goes wrong.
733     */
734    public String toFoTemplate() {
735      String rtf = extractRtf();
736  
737      //Substitutes variables occurrences in the rtfText by the
738      //rtf variable convention.
739      try {
740        if(this.hasVariables()) {
741          rtf = TemplateTransformer.substituteVariableTags(rtf, getAllVariables());
742        }
743      }
744      catch(LetterTemplateEventException lex) {
745        //Cannot happen if the rtf is generated by this system
746        return null;
747      }
748  
749      //Produces the fo-template version of the text.
750      return TemplateTransformer.rtftoFoTemplate(rtf);
751    }
752  
753  
754    private String buildRtfMargins() {
755      StringBuffer res = new StringBuffer(62);
756      res.append("\n\\margl");
757      res.append(leftMargin);
758      res.append("\\margr");
759      res.append(rightMargin);
760      res.append("\\margt");
761      res.append(topMargin);
762      res.append("\\margb");
763      res.append(bottomMargin);
764      return res.toString();
765    }
766  }
767