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.alter.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.aliteralmind.codelet.simplesig.SimpleMethodSignature SimpleMethodSignature}.{@link com.github.aliteralmind.codelet.simplesig.SimpleMethodSignature#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.alter.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}