001
002/*license*\
003   Codelet: Copyright (C) 2014, Jeff Epstein (aliteralmind __DASH__ github __AT__ yahoo __DOT__ com)
004
005   This software is dual-licensed under the:
006   - Lesser General Public License (LGPL) version 3.0 or, at your option, any later version;
007   - Apache Software License (ASL) version 2.0.
008
009   Either license may be applied at your discretion. More information may be found at
010   - http://en.wikipedia.org/wiki/Multi-licensing.
011
012   The text of both licenses is available in the root directory of this project, under the names "LICENSE_lgpl-3.0.txt" and "LICENSE_asl-2.0.txt". The latest copies may be downloaded at:
013   - LGPL 3.0: https://www.gnu.org/licenses/lgpl-3.0.txt
014   - ASL 2.0: http://www.apache.org/licenses/LICENSE-2.0.txt
015\*license*/
016package  com.github.aliteralmind.codelet;
017   import  com.github.xbn.number.LengthInRange;
018   import  com.github.xbn.analyze.alter.AlterationNotMadeException;
019   import  com.github.aliteralmind.codelet.alter.DefaultAlterGetterUtil;
020   import  com.github.xbn.linefilter.alter.AllTextLineAlterer;
021   import  com.github.xbn.linefilter.alter.ExpirableTextLineAlterList;
022   import  com.github.xbn.linefilter.NewFilteredLineIteratorFor;
023   import  com.github.xbn.linefilter.alter.TextLineAlterer;
024   import  com.github.xbn.linefilter.FilteredLineIterator;
025   import  com.github.xbn.analyze.alter.ExpirableElements;
026   import  com.github.xbn.analyze.alter.MultiAlterType;
027   import  com.github.xbn.array.CrashIfArray;
028   import  com.github.xbn.array.NullContainer;
029   import  com.github.xbn.array.NullElement;
030   import  com.github.xbn.lang.CrashIfObject;
031   import  com.github.xbn.lang.IllegalArgumentStateException;
032   import  com.github.xbn.text.CrashIfString;
033   import  com.github.xbn.util.lock.AbstractOneWayLockable;
034   import  com.google.common.base.Joiner;
035   import  java.util.Iterator;
036   import  java.util.Objects;
037   import  static com.github.aliteralmind.codelet.CodeletBaseConfig.*;
038   import  static com.github.xbn.lang.XbnConstants.*;
039/**
040   <P>The instructions returned by a Codelet Customizer, which is used by the taglet-processor to modify its output.</P>
041
042   <A NAME="3_parts"></A><H4><A HREF="#overview"><IMG SRC="{@docRoot}/resources/up_arrow.gif"/></A> Codelet: Customizer: <U>Three parts</U></H4>
043
044   <P>A {@code CustomizationInstructions} is the object returned by all <A HREF="#overview">Codelet Customizer</A>s. A {@code CustomizationInstructions} is composed of three items: A <A HREF="#3_parts_filter">line filter</A>, <A HREF="#3_parts_alterer">alterer</A>, and <A HREF="#3_parts_template">template</A>.</P>
045
046   <A NAME="3_parts_filter"></A><H4><A HREF="#3_parts"><IMG SRC="{@docRoot}/resources/up_arrow.gif"/></A> Codelet: Customizer: Three parts: <U>Part 1: Line filter</U></H4>
047
048   <P>A line filter is used to keeping only wanted lines, such as a <A HREF="{@docRoot}/overview-summary.html#xmpl_snippet">code snippet</A>, or eliminating lines you define as unwanted. An example is to <A HREF="{@docRoot}/overview-summary.html#xmpl_hello">eliminate</A> the package declaration line and all JavaDoc multi-line comments.</P>
049
050   <P><UL>
051      <LI>Raw object: {@code com.github.xbn.linefilter.}{@link com.github.xbn.linefilter.FilteredLineIterator} (set with {@link #filter(FilteredLineIterator) filter})</LI>
052      <LI>Convenience creators: {@link NewLineFilterFor}, {@link com.github.xbn.linefilter.NewFilteredLineIteratorFor}</LI>
053   </UL></P>
054
055   <A NAME="3_parts_alterer"></A><H4><A HREF="#3_parts"><IMG SRC="{@docRoot}/resources/up_arrow.gif"/></A> Codelet: Customizer: Three parts: <U>2: Alterer</U></H4>
056
057   <P>The all-line alterer modifies each line returned (kept) by the filter. A {@linkplain com.github.xbn.analyze.validate.ValidResultFilter filter} may be applied so it does not start until needed, and {@linkplain com.github.xbn.lang.Expirable expires} when complete.</P>
058
059   <P><UL>
060      <LI>Raw objects: {@code com.github.xbn.linefilter.}{@link com.github.xbn.linefilter.AllTextLineAlterer} (set with {@link #alterer(AllTextLineAlterer) alterer}), which is an array of {@link com.github.xbn.linefilter.alter.TextLineAlterer}s (set with {@link #orderedAlterers(Appendable, NullElement, ExpirableElements, MultiAlterType, TextLineAlterer...) orderedAlterers})</LI>
061      <LI>Convenience creators: {@link com.github.aliteralmind.codelet.alter.NewLineAltererFor}, {@link com.github.aliteralmind.codelet.alter.NewJDLinkForWordOccuranceNum}, {@link com.github.xbn.linefilter.alter.NewTextLineAltererFor}</LI>
062   </UL></P>
063
064   <A NAME="3_parts_template"></A><H4><A HREF="#3_parts"><IMG SRC="{@docRoot}/resources/up_arrow.gif"/></A> Codelet: Customizer: Three parts: <U>3: Template</U></H4>
065
066   <P>The context into which final output text is placed, and whose {@linkplain CodeletTemplateBase#getRendered(CodeletInstance) rendered} output is what actually replaces the taglet. Templates may be overridden for an individual taglet (by setting one into <!-- GENERIC PARAMETERS FAIL IN @link --><A HREF="#template(T)"><CODE>template</CODE></A>, in a <A HREF="#overview">custom customizer</A>), or for all taglets in a JavaDoc file or an entire package (with {@link TemplateOverrides}).</P>
067
068   <P><UL>
069      <LI>Raw objects: {@linkplain CodeletTemplateBase template} (set with <!-- GENERIC PARAMETERS FAIL IN @link --><A HREF="#template(T)"><CODE>template</CODE></A>) which, at its heart, is a {@code com.github.aliteralmind.templatefeather.FeatherTemplate}</LI>
070   </UL></P>
071
072   <A NAME="overview"></A><H2><A HREF="{@docRoot}/overview-summary.html#overview_description"><IMG SRC="{@docRoot}/resources/up_arrow.gif"/></A> &nbsp; Codelet: Customizer: <U>Overview</U></H2>
073
074   <P>A &quot;Codelet Customizer&quot; is a function that returns the <I><A HREF="#skip-navbar_top">instructions</A></I> for tailoring an example code's output. As stated in the <A HREF="{@docRoot}/overview-summary.html#overview_description">overview</A>, common customizations include<UL>
075      <LI>Displaying only a portion of an example's source code: A <A HREF="{@docRoot}/overview-summary.html#xmpl_snippet">code snippet</A>.</LI>
076      <LI><A HREF="{@docRoot}/overview-summary.html#xmpl_hello">Eliminating</A> unwanted lines, such as the package declaration line and all multi-line comments.</LI>
077      <LI>Making the first appearance of a class, function, or object names into a <A HREF="{@docRoot}/overview-summary.html#xmpl_links">clickable JavaDoc link</A>.</LI>
078   </UL></P>
079
080   <P><B>Contents:</B><UL>
081      <LI><B>Taglet syntax:</B> A customizer function is &quot;called&quot; by one or more codelet-taglets. <B>Examples:</B><UL>
082         <LI><A HREF="#xmpl_defaults">Default function name and class location</A></LI>
083         <LI>Defaults with a <A HREF="#proc_custom_post">custom postfix</A></LI>
084         <LI><A HREF="#xmpl_sig">Specifying the class</A> in which the processor function exists</LI>
085         <LI>Specifying <A HREF="#xmpl_params">extra parameters</A> for the customizer function</LI>
086      </UL></P></LI>
087      <LI><B>The customizer function:</B><UL>
088         <LI>Examples: A customizer function that<UL>
089            <LI><A HREF="#func_does_nothing">Does nothing</A>.</LI>
090            <LI>Changes a function, constructor, class, or field name to a <A HREF="{@docRoot}/overview-summary.html#xmpl_links">clickable JavaDoc link</A>.</LI>
091         </UL></LI>
092         <LI><A HREF="#specifications">Specifications</A> and </LI>
093         <LI>Pre-made customizers: {@link BasicCustomizers}</LI>
094         <LI>{@link CustomizationInstructions}: The object returned by the customizer function. Made up of three parts: A <A HREF="#3_parts_filter">line filter</A>, <A HREF="#3_parts_alterer">alterer</A>, and <A HREF="#3_parts_template">template</A></LI>
095      </UL></LI>
096   </UL></P>
097
098   <A NAME="func_does_nothing"></A><H2><A HREF="#overview"><IMG SRC="{@docRoot}/resources/up_arrow.gif"/></A> &nbsp; Codelet: Customizer function: <U>Example: A customizer that does nothing</U></H2>
099
100   <P>A customizer function that makes (almost) no changes:</P>
101
102{@.codelet com.github.aliteralmind.codelet.examples.DoNothingCustomizerCompact%lineRangeWithReplace(1, true, "(<SourceCodeTemplate> aCustomizerThatDoesNothing)", "$1", "FIRST", 1, true, "&#125; +//End snippet$", "&#125;", "FIRST", "^   ")}
103
104   <P>Here is the same function, with documentation on the available {@linkplain CodeletBaseConfig#GLOBAL_DEBUG_LEVEL debugging} parameters:</P>
105
106{@.codelet com.github.aliteralmind.codelet.examples.DoNothingCustomizer%lineRangeWithReplace(1, true, "(<SourceCodeTemplate> aCustomizerThatDoesNothing)", "$1", "FIRST", 1, true, "&#125; +//End snippet$", "&#125;", "FIRST", "^   ")}
107
108   <P>This do-nothing customizer uses all {@linkplain #defaults(Appendable, LengthInRange, Appendable, Appendable) defaults}. It<OL>
109      <LI>{@link #unfiltered(Appendable, LengthInRange) Filters no lines},</LI>
110      <LI>{@linkplain com.github.aliteralmind.codelet.alter.DefaultAlterGetter Default alterers} as {@linkplain CodeletBaseConfig#DEFAULT_ALTERERS_CLASS_NAME configured}.</LI>
111      <LI>Uses the {@link #defaultOrOverrideTemplate(Appendable) Default template},</LI>
112   </OL></P>
113
114   <A NAME="specifications"></A><H2><A HREF="#overview"><IMG SRC="{@docRoot}/resources/up_arrow.gif"/></A> &nbsp; Codelet: Customizer: <U>Requirements</U></H2>
115
116   <P>The customizer function has the following requirements:<UL>
117      <LI>Its location (containing class) must be <A HREF="#xmpl_sig">explicitely specified</A> in the taglet, or must exist in one of the following <B><U>default classes</U></B>, which are searched in order:<OL>
118         <LI>{@link BasicCustomizers},</LI>
119         <LI>The {@linkplain CodeletInstance#getEnclosingClass() enclosing class}, if it is a class,</LI>
120         <LI>And a class named "{@link TagletOfTypeProcessor#DEFAULT_CUSTOMIZER_CLASS_NAME zCodeletCustomizers}", if one exists in the {@linkplain CodeletInstance#getEnclosingPackage() enclosing package}.</LI>
121      </OL></LI>
122      <LI>It must be {@code static} and</LI>
123      <LI>accessible (it is obtained with <CODE>{@link java.lang.Class Class}.{@link java.lang.Class#getDeclaredMethod(String, Class...) getDeclaredMethod}</CODE> and made accessible with <CODE>theLineProcMethod.{@link java.lang.reflect.AccessibleObject#setAccessible(boolean) setAccessible}(true)</CODE>).</LI>
124      <LI>Its first parameter must be a {@link CodeletInstance CodeletInstance} and second must be a {@link CodeletType}. Both of these parameters are ommitted from all taglets.</LI>
125      <LI>It may contain zero-or-more <A HREF="#xmpl_params">extra parameters</A>, whose types are either primitives or non-{@code null} strings ({@code null} is not possible), as specified by
126      <BR> &nbsp; &nbsp; <CODE>com.github.xbn.util.{@link com.github.xbn.util.SimpleStringSignature SimpleStringSignature}.{@link com.github.xbn.util.SimpleStringSignature#getObjectFromString(String) getObjectFromString} </CODE>
127      <BR>If there are any extra types in the customizer function signature, they must be provided in the {@linkplain TagletOfTypeProcessor#getCustomizerPortion() customizer portion} of every taglet using it. <I>The types, amount, and order of extra parameters, in both the taglet and the customizer function signature, must exactly match.</I></LI>
128   </UL></P>
129
130   <P>When taglets are used in a class (as opposed to <A HREF="http://stackoverflow.com/questions/3644726/javadoc-package-html-or-package-info-java">{@code package-info.java}</A> or your project's <A HREF="http://www.oracle.com/technetwork/java/javase/documentation/index-137868.html#sourcefiles">overview summary</A>), it is encouraged that its customizer functions be in the class, and that these functions are {@code private}. (In the Codelet and <A HREF="http://codelet.aliteralmind.com">XBN-Java</A> projects, this is not possible, as doing so would create <A HREF="http://en.wikipedia.org/wiki/Circular_dependency">circular-dependency</A> nightmare--this is the primary reason for the {@code zCodeletCustomizers} default class.)</P>
131
132   <A NAME="xmpl_defaults"></A><H2><A HREF="#overview"><IMG SRC="{@docRoot}/resources/up_arrow.gif"/></A> &nbsp; Codelet: Customizer: Taglet syntax: Example: <U>Default function name and class location</U></H2>
133
134<BLOCKQUOTE>{@code {@.codelet fully.qualified.examples.ExampleClassName%()}}</BLOCKQUOTE>
135
136   <P>This {@code ":()"} shortcut indicates a customizer function with the standard name and class location should be used. In particular:<UL>
137      <LI>Its name is {@code "getSourceCode_ExampleClassName"},</LI>
138      <LI>It has no extra parameters, and it</LI>
139      <LI>Must exist in one of the <A HREF="#specifications">default classes</A></LI>
140   </UL></P>
141
142   <P>{@code {@.codelet fully.qualified.examples.ExampleClassName%()}}</P>
143
144   <P>is equivalent to both</P>
145
146<BLOCKQUOTE>{@code {@.codelet fully.qualified.examples.ExampleClassName:getSourceCode_ExampleClassName()}}</BLOCKQUOTE>
147
148   <P>and</P>
149
150<BLOCKQUOTE>{@code {@.codelet fully.qualified.examples.ExampleClassName:package.of.EnclosingClass#getSourceCode_ExampleClassName()}}</BLOCKQUOTE>
151
152   <P>with one exception: When the processor's function name is explicitely specified, <I>but its class is not</I> (which is true in the first two of the three above), the customizer must exist in one of the default classes</P>
153
154   <A NAME="proc_custom_post"></A><H2><A HREF="#overview"><IMG SRC="{@docRoot}/resources/up_arrow.gif"/></A> &nbsp; Codelet: Customizer: Taglet syntax: Example: <U>Defaults with custom postfix</U></H2>
155
156<BLOCKQUOTE>{@code {@.codelet fully.qualified.examples.ExampleClassName%_ExtraStuff()}}</BLOCKQUOTE>
157
158   <P>Same as the <A HREF="#xmpl_defaults">default example</A>, except the underscore-first-character indicates that this is not the customizer's entire function name, rather its <I>postfix</I>.</P>
159
160   <P>This is useful when there are multiple codelets of the same {@linkplain CodeletType type}, for the same example class (or text file).</P>
161
162   <A NAME="xmpl_sig"></A><H2><A HREF="#overview"><IMG SRC="{@docRoot}/resources/up_arrow.gif"/></A> &nbsp; Codelet: Customizer: Taglet syntax: Example: <U>Specifying the class in which the processor function exists</U></H2>
163
164   <P>The customizer function can be in any class, which may explicitely specified:</P>
165
166<BLOCKQUOTE>{@code {@.codelet fully.qualified.examples.ExampleClassName:fully.qualified.package.MyCodeletCustomizers#getSource_ExampleClass(true, "See line 12")}}</BLOCKQUOTE>
167
168   <P>If using the <A HREF="#xmpl_defaults">default function name</A>, it may be omitted, although the hash ({@code '#'}) is required:</P>
169
170<BLOCKQUOTE>{@code {@.codelet fully.qualified.examples.ExampleClassName:fully.qualified.package.MyCodeletCustomizers#(true, "See line 12")}}</BLOCKQUOTE>
171
172   <P>Signature formatting is as specified by
173   <BR> &nbsp; &nbsp; <CODE>{@link com.github.aliteralmind.codelet.simplesig.SimpleMethodSignature SimpleMethodSignature}.{@link com.github.aliteralmind.codelet.simplesig.SimpleMethodSignature#newFromStringAndDefaults(Class, Object, String, Class[], Appendable) newFromStringAndDefaults}</CODE>
174   <BR>(Before being provided to {@code newFromStringAndDefaults}, the omitted function name is given its default value [{@code "getSource_ExampleClass"}], as described in this and the <A HREF="#proc_custom_post">previous example</A>. In all cases, {@code SimpleMethodSignature} requires a function name.)</P>
175
176   <A NAME="xmpl_params"></A><H2><A HREF="#overview"><IMG SRC="{@docRoot}/resources/up_arrow.gif"/></A> &nbsp; Codelet: Customizer: Taglet syntax: Example: <U>Specifying extra processor parameters</U></H2>
177
178   <P>The default customizer has a single {@link CodeletInstance CodeletInstance} parameter. This is specified in the taglet with either empty parentheses, or no parens at all, as demonstrated in the <A HREF="#xmpl_defaults">default example</A>.</P>
179
180   <P>Extra parameters may be optionally specified, and must be provided <I>both</I> in the function and in any taglet that uses (calls) it. For example, this taglet</P>
181
182<BLOCKQUOTE>{@code {@.codelet fully.qualified.examples.ExampleClassName:(true, "See line 12")}}</BLOCKQUOTE>
183
184   <P>refers to this function:</P>
185
186<BLOCKQUOTE>{@code getSourceCode_ExampleClassName(CodeletInstance taglet, CodeletType needed_defaultAlterType, boolean do_displayLineNums, String annotation)}</BLOCKQUOTE>
187
188   <P>which, since there is no fully-qualified class specified after the {@linkplain CodeletInstance#CUSTOMIZER_PREFIX_CHAR percent sign}, must be in one of the <A HREF="#specifications">default class-locations</A>.</P>
189
190   <P>Parameter formatting is specified by
191   <BR> &nbsp; &nbsp; <CODE>{@link com.github.aliteralmind.codelet.simplesig.SimpleMethodSignature}.{@link com.github.aliteralmind.codelet.simplesig.SimpleMethodSignature#newFromStringAndDefaults(Class, Object, String, Class[], Appendable) newFromStringAndDefaults}</CODE></P>
192
193   <P>This is a "simple" signature. Only {@linkplain com.github.aliteralmind.codelet.simplesig.SimpleMethodSignature#getObjectFromString(String) primitives and strings} are allowed. {@code null} is not possible.</P>
194
195   <P>Extra parameters can also be specified with the <A HREF="#xmpl_defaults">{@code ":()"} shortcut</A>:
196   <BR> &nbsp; &nbsp; {@code {@.codelet fully.qualified.examples.ExampleClassName:((byte)3, false)}}</P>
197
198
199   @since  0.1.0
200   @author  Copyright (C) 2014, Jeff Epstein ({@code aliteralmind __DASH__ github __AT__ yahoo __DOT__ com}), dual-licensed under the LGPL (version 3.0 or later) or the ASL (version 2.0). See source code for details. <A HREF="http://codelet.aliteralmind.com">{@code http://codelet.aliteralmind.com}</A>, <A HREF="https://github.com/aliteralmind/codelet">{@code https://github.com/aliteralmind/codelet}</A>
201 **/
202public class CustomizationInstructions<T extends CodeletTemplateBase> extends AbstractOneWayLockable  {
203   private FilteredLineIterator     filter        ;
204   private String             classNameOrFilePathRestricter;
205   private AllTextLineAlterer alterer       ;
206   private T                  template      ;
207   private boolean            wasTmplSet    ;
208   private Appendable         dfltTmplDbg   ;
209   private final CodeletInstance instance   ;
210   private final CodeletType  defaultAltersType;
211   /*
212        <P>Create a new instance for any taglet type except {@code {@.codelet.and.out}}.</P>
213
214        <P>Equal to
215        <BR> &nbsp; &nbsp; <CODE>{@link #CustomizationInstructions(CodeletInstance, CodeletType) this}(instance, instance.getType())</CODE></P>
216
217        @param  instance  May not be {@code null}.
218   public CustomizationInstructions(CodeletInstance instance)  {
219      this(instance, CustomizationInstructions.getType(instance));
220   }
221      private static final CodeletType getType(CodeletInstance instance)  {
222         try  {
223            return  instance.getType();
224         }  catch(RuntimeException rx)  {
225            throw  CrashIfObject.nullOrReturnCause(instance, "instance", null, rx);
226         }
227      }
228    */
229   /**
230        <P>Create a new instance.</P>
231
232        <P>Equal to
233        <BR> &nbsp; &nbsp; <CODE>{@link #CustomizationInstructions(CodeletInstance, CodeletType) this}(instance, instance.getType())</CODE></P>
234
235        @param  instance  May not be {@code null}.
236        @param  needed_defaultAlterType  The type of {@linkplain com.github.aliteralmind.codelet.alter.DefaultAlterGetter default alterers} needed when using the {@linkplain #defaultOrOverrideTemplate(Appendable) default template}. May not be {@code null}. If <CODE>instance.{@link CodeletInstance#getType() getType}.{@link CodeletType#SOURCE_AND_OUT SOURCE_AND_OUT}</CODE>, then this must be either {@link CodeletType#SOURCE_CODE SOURCE_CODE} or {@link CodeletType#CONSOLE_OUT CONSOLE_OUT}. If <CODE>instance.{@link CodeletInstance#getType() getType}</CODE> is any other type, then {@code needed_defaultAlterType} must be equal to it.
237    **/
238   public CustomizationInstructions(CodeletInstance instance, CodeletType needed_defaultAlterType)  {
239      try  {
240         if(!instance.getType().isSourceAndOut())  {
241            if(instance.getType() != needed_defaultAlterType)  {
242               throw  new IllegalArgumentStateException("instance.getType()." + instance.getType() + ", needed_defaultAlterType=" + needed_defaultAlterType + ".");
243            }
244         }  else if(!needed_defaultAlterType.isSourceCode()  &&
245               !needed_defaultAlterType.isConsoleOut())  {
246            throw  new IllegalArgumentStateException("instance.getType().SOURCE_AND_OUT, needed_defaultAlterType must be SOURCE_CODE or CONSOLE_OUT, but is actually " + needed_defaultAlterType + ".");
247         }
248      }  catch(RuntimeException rx)  {
249         CrashIfObject.nnull(instance, "instance", null);
250         throw  CrashIfObject.nullOrReturnCause(needed_defaultAlterType, "needed_defaultAlterType", null, rx);
251      }
252      alterer = null;
253      filter = null;
254      template = null;
255      wasTmplSet = false;
256      classNameOrFilePathRestricter("*");
257      this.instance = instance;
258      defaultAltersType = needed_defaultAlterType;
259   }
260   /**
261      <P>Make no customizations.</P>
262
263      <P>This calls<OL>
264         <LI>{@link #unfiltered(Appendable, LengthInRange) unfiltered}{@code (dbgDest_ifNonNull)}</LI>
265         <LI><CODE>{@link #orderedAlterers(Appendable, NullElement, ExpirableElements, MultiAlterType, TextLineAlterer...) orderedAlterers}(dbgAllAltr_ifNonNull, {@link com.github.xbn.array.NullElement NullElement}.{@link com.github.xbn.array.NullElement#BAD BAD}
266         <BR> &nbsp; &nbsp; {@link com.github.xbn.analyze.alter.ExpirableElements}.{@link com.github.xbn.analyze.alter.ExpirableElements#OPTIONAL OPTIONAL}, {@link com.github.xbn.analyze.alter.MultiAlterType}.{@link com.github.xbn.analyze.alter.MultiAlterType#CUMULATIVE CUMULATIVE}
267            <BR> &nbsp; &nbsp; {@link com.github.aliteralmind.codelet.alter.DefaultAlterGetterUtil}.{@link com.github.aliteralmind.codelet.alter.DefaultAlterGetterUtil#getDefaultAlterArray(CodeletType) getDefaultAlterArray}({@link #getNeededAlterArrayType() getNeededAlterArrayType}()))</CODE></LI>
268         <LI>{@link #defaultOrOverrideTemplate(Appendable) defaultOrOverrideTemplate}{@code (dbgTemplate_ifNonNull)}</LI>
269      </OL></P>
270
271      @return  <I>{@code this}</I>
272    **/
273   public CustomizationInstructions<T> defaults(Appendable dbgEveryLine_ifNonNull, LengthInRange rangeForEveryLineDebug_ifNonNull, Appendable dbgAllAltr_ifNonNull, Appendable dbgTemplate_ifNonNull)  {
274      unfiltered(dbgEveryLine_ifNonNull, rangeForEveryLineDebug_ifNonNull);
275      orderedAlterers(dbgAllAltr_ifNonNull, NullElement.BAD,
276         ExpirableElements.OPTIONAL, MultiAlterType.CUMULATIVE,
277         DefaultAlterGetterUtil.getDefaultAlterArray(getNeededAlterArrayType()));
278      return  defaultOrOverrideTemplate(dbgTemplate_ifNonNull);
279   }
280   /*
281      <P>The type of template needed, when using the default template. This is intended for {@link CodeletType#SOURCE_AND_OUT {@.codelet.and.out}} taglets only.</P>
282
283      @return  A non-{@code null} type representing the kind of template needed.
284      @see  #CustomizationInstructions(CodeletInstance, CodeletType) constructor
285      @see  #defaults(Appendable, LengthInRange, Appendable, Appendable) defaults
286    */
287   public CodeletType getNeededAlterArrayType()  {
288      return  defaultAltersType;
289   }
290   /**
291      <P>Get the line-filter.</P>
292
293      @see  #filter(FilteredLineIterator)
294    **/
295   public FilteredLineIterator getFilter()  {
296      return  filter;
297   }
298   /**
299      <P>Get the line-alterer.</P>
300
301      @see  #alterer(AllTextLineAlterer)
302    **/
303   public AllTextLineAlterer getAlterer()  {
304      return  alterer;
305   }
306   /**
307      <P>Get the template.</P>
308
309      @return  <UL>
310         <LI>A non-{@code null} template: When <I>this taglet only</I> should use a non-default (and non-{@linkplain TemplateOverrides override}) template.</LI>
311         <LI>{@code null}: If {@link #wasTemplateSet() wasTemplateSet}{@code ()} is<UL>
312            <LI>{@code true}: No template was set.</LI>
313            <LI>{@code false}: The default (or override) template should be used.</LI>
314         </UL></LI>
315      </UL>
316      @see  <CODE><!-- GENERIC PARAMETERS FAIL IN @link --><A HREF="#template(T)">template</A>(T)</CODE>
317      @see  #defaultOrOverrideTemplate(Appendable)
318    **/
319   public T getTemplate()  {
320      return  template;
321   }
322   public CodeletInstance getInstance()  {
323      return  instance;
324   }
325   /**
326      <P>Use the default (or override) template.</P>
327
328      <P>This sets<OL>
329         <LI>{@link #getTemplate() getTemplate}{@code ()} to {@code null}</LI>
330         <LI>{@link #wasTemplateSet() wasTemplateSet}{@code ()} to {@code true}</LI>
331      </OL></P>
332
333      <P>This leaves the template object as {@code null} to avoid having to know about the {@link CodeletInstance}, which is required to determine if the default or {@linkplain TemplateOverrides override} template should be used. A {@code null} template value triggers the {@linkplain TagletOfTypeProcessor taglet processor} to get the appropriate template.</P>
334
335      @param  dbgDest_ifNonNull  When non-{@code null}, this is the debugging destination for all gap-fills. Get with {@link #getDefaultTemplateDebug() getDefaultTemplateDebug}{@code ()}
336      @return  <I>{@code this}</I>
337      @exception  LockException  If {@link #build() build}{@code ()} was already called.
338      @exception  IllegalStateException  If {@code wasTemplateSet()} is {@code true}.
339      @see  <CODE><!-- GENERIC PARAMETERS FAIL IN @link --><A HREF="#template(T)">template</A>(T)</CODE>
340    **/
341   public CustomizationInstructions<T> defaultOrOverrideTemplate(Appendable dbgDest_ifNonNull)  {
342      ciLockedOrTmplAlreadySet();
343      template = null;
344      wasTmplSet = true;
345      dfltTmplDbg = dbgDest_ifNonNull;
346      return  this;
347   }
348   /**
349      <P>Override the template for this codelet-taglet only.</P>
350
351      <P>This sets {@link #wasTemplateSet() wasTemplateSet}{@code ()} to {@code true}.</P>
352
353      @param  template  May not be {@code null}. Get with {@link #getTemplate() getTemplate}{@code ()}. Note that JavaDoc is multi-threaded, and therefore this template-object must be a new object (not shared among multiple taglets). Use the {@linkplain com.github.aliteralmind.templatefeather.FeatherTemplate#FeatherTemplate(FeatherTemplate, Appendable) copy constructor} or {@link com.github.aliteralmind.templatefeather.FeatherTemplate#getObjectCopy() getObjectCopy}{@code ()} to duplicate it.
354      @return  <I>{@code this}</I>
355      @exception  LockException  If {@link #build() build}{@code ()} was already called.
356      @exception  IllegalStateException  If {@code wasTemplateSet()} is {@code true}.
357      @see  #defaultOrOverrideTemplate(Appendable)
358    **/
359   public CustomizationInstructions<T> template(T template)  {
360      Objects.requireNonNull(template, "template");
361      ciLockedOrTmplAlreadySet();
362      this.template = template;
363      wasTmplSet = true;
364      return  this;
365   }
366      private void ciLockedOrTmplAlreadySet()  {
367         ciLocked();
368         if(wasTmplSet)  {
369            throw  new IllegalStateException("Already set");
370         }
371      }
372   /**
373      <P>Display all lines.</P>
374
375      @return  <CODE>{@link #filter(FilteredLineIterator) filter}({@link com.github.xbn.linefilter.NewFilteredLineIteratorFor NewFilteredLineIteratorFor}.{@link com.github.xbn.linefilter.NewFilteredLineIteratorFor#keepAllLinesUnchanged(Iterator, Appendable, LengthInRange) keepAllLinesUnchanged}(null, dbgEveryLine_ifNonNull, rangeForEveryLineDebug_ifNonNull))</CODE>
376    **/
377   public CustomizationInstructions<T> unfiltered(Appendable dbgEveryLine_ifNonNull, LengthInRange rangeForEveryLineDebug_ifNonNull)  {
378      return  filter(NewFilteredLineIteratorFor.keepAllLinesUnchanged(null, dbgEveryLine_ifNonNull, rangeForEveryLineDebug_ifNonNull));
379   }
380   /**
381      <P>Keep or eliminate lines that meet some conditions. Kept lines may be {@linkplain #orderedAlterers(Appendable, NullElement, ExpirableElements, MultiAlterType, TextLineAlterer...) altered}.</P>
382
383      <P>Two examples of filtering lines:<UL>
384         <LI>Displaying only a range of lines--a <A HREF="{@docRoot}/overview-summary.html#xmpl_snippet">code snippet</A>.</LI>
385         <LI><A HREF="{@docRoot}/overview-summary.html#xmpl_hello">Eliminating</A> the package declaration line and all JavaDoc multi-line comments</LI>
386      </UL></P>
387
388      @param  filter  May not be {@code null}. Get with {@link #getFilter() getFilter}{@code ()}.
389      @return  <I>{@code this}</I>
390      @see  #unfiltered(Appendable, LengthInRange)
391      @exception  LockException  If {@link #build() build}{@code ()} was already called.
392    **/
393   public CustomizationInstructions<T> filter(FilteredLineIterator filter)  {
394      ciLocked();
395      if(filter.wasAllIteratorSet())  {
396         throw  new IllegalStateException("filter.wasAllIteratorSet()=true");
397      }
398      this.filter = filter;
399      return  this;
400   }
401   /**
402      <P>Set an ordered series of line-alterers.</P>
403
404      @param  alterers  May not be {@code null} or empty and, if <CODE>null_element.{@link com.github.xbn.array.NullElement#isBad() isBad}()</CODE> is {@code true}, no elements may be {@code null}. Elements <I>should</I> not be duplicate.
405      @return  <CODE>{@link #alterer(AllTextLineAlterer) alterer}(new {@link com.github.xbn.linefilter.AllTextLineAlterer#AllTextLineAlterer(TextLineAlterer[], ExpirableElements, MultiAlterType, Appendable) AllTextLineAlterer}(alterers, xprbl_elements, multi_type, dbgDest_ifNonNull))</CODE>
406    **/
407   public CustomizationInstructions<T> orderedAlterers(Appendable dbgDest_ifNonNull, NullElement null_element, ExpirableElements xprbl_elements, MultiAlterType multi_type, TextLineAlterer... alterers)  {
408      try  {
409         if(null_element.isOk())  {
410            alterers = ExpirableTextLineAlterList.
411               getTextLineAltererArrayFromOrderedElementsIfNonNull(null_element, "alterers", alterers);
412         }
413      }  catch(RuntimeException rx)  {
414         throw  CrashIfObject.nullOrReturnCause(null_element, "null_element", null, rx);
415      }
416      CrashIfArray.lengthLessThan(alterers, "alterers", NullContainer.BAD, 1, null);
417      return  alterer(new AllTextLineAlterer(alterers, xprbl_elements, multi_type, dbgDest_ifNonNull));
418   }
419   /**
420      <P>Set the line-alterer.</P>
421
422      @param  all_lineAlterer  May not be {@code null}. Get with {@link #getAlterer() getAlterer}{@code ()}.
423      @return  <I>{@code this}</I>
424      @exception  LockException  If {@link #build() build}{@code ()} was already called.
425      @see  #orderedAlterers(Appendable, NullElement, ExpirableElements, MultiAlterType, TextLineAlterer...)
426    **/
427   public CustomizationInstructions<T> alterer(AllTextLineAlterer all_lineAlterer)  {
428      ciLocked();
429      Objects.requireNonNull(all_lineAlterer, "all_lineAlterer");
430      alterer = all_lineAlterer;
431      return  this;
432   }
433   /**
434      <P>Wildcard search-term to restrict the classes or files that may utilize this customizer.</P>
435
436      @param  whitelist_searchTerm  Wildcard search term to match the fully-qualified class name of the example code, or path of the text file that is allowed to use this customizer. Class name examples:<UL>
437         <LI>{@code "com.github.mylibrary.examples.AGoodExample"}</LI>
438         <LI>{@code "com.github.mylibrary.examples.A*Example"}</LI>
439         <LI>{@code "*.examples.A*Example"}</LI>
440      </UL>Text file examples:<UL>
441         <LI>{@code "com/github/mylibrary/examples/doc-files/AGoodExample_input.txt"}</LI>
442         <LI>{@code "com/github/mylibrary/examples/doc-files/*_input.txt"}</LI>
443         <LI>{@code "*_input.txt"}</LI>
444      </UL>May not be {@code null} or empty, and <I>should</I> be a valid wildcard term. Get with {@link #getClassNameOrFilePathRestricter() getClassNameOrFilePathRestricter}{@code ()}.
445      @return  <I>{@code this}</I>
446      @see  org.apache.commons.io.FilenameUtils#wildcardMatch(String, String) FilenameUtils#wildcardMatch
447      @see  TagletOfTypeProcessor#crashIfClassOrFileCannotUseCustomizer(CustomizationInstructions) TagletOfTypeProcessor#crashIfClassOrFileCannotUseCustomizer
448    **/
449   public CustomizationInstructions<T> classNameOrFilePathRestricter(String whitelist_searchTerm)  {
450      CrashIfString.nullEmpty(whitelist_searchTerm, "whitelist_searchTerm", null);
451      classNameOrFilePathRestricter = whitelist_searchTerm;
452      return  this;
453   }
454   /**
455      <P>Wildcard search-term to restrict the classes that may utilize this customizer.</P>
456
457      @see  #classNameOrFilePathRestricter(String)
458    **/
459   public String getClassNameOrFilePathRestricter()  {
460      return  classNameOrFilePathRestricter;
461   }
462   /**
463      <P>Was the template set?.</P>
464
465      @see  #getTemplate()
466      @see  <CODE><!-- GENERIC PARAMETERS FAIL IN @link --><A HREF="#template(T)">template</A>(T)</CODE>
467      @see  #defaultOrOverrideTemplate(Appendable)
468    **/
469   public boolean wasTemplateSet()  {
470      return  wasTmplSet;
471   }
472   /**
473      <P>When using the default template only, this is its debug destination.</P>
474
475      @see  #getTemplate()
476      @see  #defaultOrOverrideTemplate(Appendable)
477    **/
478   public Appendable getDefaultTemplateDebug()  {
479      return  dfltTmplDbg;
480   }
481   /**
482      <P>Given all configured customization instructions, transform the raw output (source-code, console-output, or file-text) into its fully-processed form, ready for insertion into the template.</P>
483
484      <P>This logs all alterers that do not make an alteration.</P>
485
486      @exception  AlterationNotMadeException  If at least one alteration is not made, and it is {@linkplain CodeletBaseConfig#ALTERATION_NOT_MADE_CRASH configured} that a crash should occur (in addition to the warning).
487    **/
488   public String getCustomizedBody(CodeletInstance instance, Iterator<String> raw_lineItr)  {
489      getFilter().setAllIterator(raw_lineItr);
490      String body = getAlterer().getAlteredFromLineObjects(1, getFilter(), LINE_SEP);
491
492      if(!getAlterer().isComplete())  {
493         String msg = getAlterer().appendIncompleteInfo((new StringBuilder())).toString();
494         if(!isDebugOn(instance, "zzTagletProcessor.codeletfound"))  {
495            msg = "(" + instance + ") " + msg;
496         }
497         debuglnAndToConsole(instance, "Codelet warning: " + msg);
498         if(doCrashIfAlterationNotMade())  {
499            throw  new AlterationNotMadeException("(CodeletBaseConfig.doCrashIfAlterationNotMade() is true): " + msg);
500         }
501      }
502
503      return  body;
504   }
505   /**
506      <P>Declare that this object is ready for use and should be locked.</P>
507
508      @return  <I>{@code this}</I>
509      @exception  IllegalStateException  If the {@linkplain #getFilter() filter} or {@linkplain #getAlterer() alterer} are {@code null}, or {@link #wasTemplateSet() wasTemplateSet}{@code ()} is {@code false}.
510    **/
511   public CustomizationInstructions<T> build()  {
512      crashIfNotReady();
513      super.lock();
514      return  this;
515   }
516      private void crashIfNotReady()  {
517         if(alterer != null  &&  filter != null  &&
518               wasTmplSet)  {
519            return;
520         }
521
522      //At least one is unset
523      String sFltr = ((getFilter() != null) ? null : "filter(FilteredLineIterator)");
524      String sAlter = ((getAlterer() != null) ? null : "alterer(AllTextLineAlterer)");
525      String sTmpl = (wasTmplSet ? null : "template(T)");
526
527/*
528String s = Joiner.on(", ").skipNulls().join(null, null);
529System.out.println("Joiner.on(', ').skipNulls().join(null, null, null) == null: " + (s == null));
530System.out.println("Joiner.on(', ').skipNulls().join(null, null, null).length(): " + s.length());
531
532   Output:
533      ... == null: false
534      ....length(): 0
535 */
536      throw  new IllegalStateException("Must set: " +
537         Joiner.on(", ").skipNulls().join(sFltr, sAlter, sTmpl));
538   }
539}