001package Torello.Java.Additional;
002
003import Torello.JavaDoc.JDHeaderBackgroundImg;
004import Torello.Java.UnreachableError;
005
006// Used for the JavaDoc '@see' tag, a few lines directly-below
007import Torello.Java.OSCommands;
008
009import java.io.IOException;
010
011/**
012 * Builds a composite {@code java.lang.Appendable} using up to <B STYLE='color: red;'>three</B>
013 * independent input-parameter {@code Appendable's}.  Character data appended to an instance of
014 * {@code TriAppendable} will, in turn, be appended to any of the input-{@code Appendable's} which
015 * have been provided to this class' constructor and are non-null.
016 * 
017 * <BR /><BR />Passing null input-{@code Appendable's} <B STYLE='color: red;'><I>will not</I></B>
018 * cause this class to fail, and <B STYLE='color: red;'><I>will not</I></B> generate
019 * {@code NullPointerException's}.  One of the primary values of this class is that the chunk of
020 * code that tests for a "Null Log" is done inside this class.
021 * 
022 * <BR /><BR />The meaning of a "Null Log" is just that a user has decided against logging a tool 
023 * or utility's output to any logger, and has passed 'null' to one of the log references in his
024 * code.
025 * 
026 * @see OSCommands
027 */
028@JDHeaderBackgroundImg
029    (EmbedTagFileID={"APPENDABLE_EXTENSION", "TRI_APPENDABLE_JDHBI", "BI_TRI_BOTH_JDHBI"})
030public class TriAppendable implements Appendable
031{
032    private final Appendable appendable;
033
034    /**
035     * Creates an instance of this class, using up to three input {@code Appendable's}.
036     * 
037     * @param a Any {@code java.lang.Appendable}.  This parameter may be null, and if it is it will
038     * be ignored.  Passing null here, will not generated a {@code NullPointerException}
039     * 
040     * @param b Any {@code java.lang.Appendable}.  This parameter may be null, and if it is it will
041     * be ignored.  Passing null here, will not generated a {@code NullPointerException}
042     * 
043     * @param c Any {@code java.lang.Appendable}.  This parameter may be null, and if it is it will
044     * be ignored.  Passing null here, will not generated a {@code NullPointerException}
045     */
046    public TriAppendable(Appendable a, Appendable b, Appendable c)
047    {
048        // Minor coding trick.  Pretend this is a base-2 number, with three bits.  I think this
049        // improves efficiency a tiny bit, since it isn't comparing the nulls over and over again.
050        // Here it checks the references for nulls only once.
051
052        int theSum =
053            ((a == null) ? 0 : 4) +
054            ((b == null) ? 0 : 2) +
055            ((c == null) ? 0 : 1);
056        
057        // if ((a == null) && (b == null) && (c == null)) this.appendable = new Appendable()
058        if (theSum == 0) this.appendable = new Appendable()
059        {
060            public Appendable append(char ch) throws IOException
061            { return this; }
062    
063            public Appendable append(CharSequence cs) throws IOException
064            { return this; }
065
066            public Appendable append(CharSequence cs, int start, int end) throws IOException
067            { return this; }
068        };
069
070        // else if ((a == null) && (b == null) && (c != null)) this.appendable = new Appendable()
071        else if (theSum == 1) this.appendable = new Appendable()
072        {
073            public Appendable append(char ch) throws IOException
074            { c.append(ch); return this; }
075    
076            public Appendable append(CharSequence cs) throws IOException
077            { c.append(cs); return this; }
078
079            public Appendable append(CharSequence cs, int start, int end) throws IOException
080            { c.append(cs, start, end); return this; }
081        };
082
083        // else if ((a == null) && (b != null) && (c == null)) this.appendable = new Appendable()
084        else if (theSum == 2) this.appendable = new Appendable()
085        {
086            public Appendable append(char ch) throws IOException
087            { b.append(ch); return this; }
088    
089            public Appendable append(CharSequence cs) throws IOException
090            { b.append(cs); return this; }
091
092            public Appendable append(CharSequence cs, int start, int end) throws IOException
093            { b.append(cs, start, end); return this; }
094        };
095
096        // else if ((a == null) && (b != null) && (c != null)) this.appendable = new Appendable()
097        else if (theSum == 3) this.appendable = new Appendable()
098        {
099            public Appendable append(char ch) throws IOException
100            { b.append(ch); c.append(ch); return this; }
101    
102            public Appendable append(CharSequence cs) throws IOException
103            { b.append(cs); c.append(cs); return this; }
104
105            public Appendable append(CharSequence cs, int start, int end) throws IOException
106            { b.append(cs, start, end); c.append(cs, start, end); return this; }
107        };
108
109        // else if ((a != null) && (b == null) && (c == null)) this.appendable = new Appendable()
110        else if (theSum == 4) this.appendable = new Appendable()
111        {
112            public Appendable append(char ch) throws IOException
113            { a.append(ch); return this; }
114    
115            public Appendable append(CharSequence cs) throws IOException
116            { a.append(cs); return this; }
117
118            public Appendable append(CharSequence cs, int start, int end) throws IOException
119            { a.append(cs, start, end); return this; }
120        };
121
122        // else if ((a != null) && (b == null) && (c != null)) this.appendable = new Appendable()
123        else if (theSum == 5) this.appendable = new Appendable()
124        {
125            public Appendable append(char ch) throws IOException
126            { a.append(ch); c.append(ch); return this; }
127    
128            public Appendable append(CharSequence cs) throws IOException
129            { a.append(cs); c.append(cs); return this; }
130
131            public Appendable append(CharSequence cs, int start, int end) throws IOException
132            { a.append(cs, start, end); c.append(cs, start, end); return this; }
133        };
134
135        // else if ((a != null) && (b != null) && (c == null)) this.appendable = new Appendable()
136        else if (theSum == 6) this.appendable = new Appendable()
137        {
138            public Appendable append(char ch) throws IOException
139            { a.append(ch); b.append(ch); return this; }
140    
141            public Appendable append(CharSequence cs) throws IOException
142            { a.append(cs); b.append(cs); return this; }
143
144            public Appendable append(CharSequence cs, int start, int end) throws IOException
145            { a.append(cs, start, end); b.append(cs, start, end); return this; }
146        };
147
148        // else if ((a != null) && (b != null) && (c != null)) this.appendable = new Appendable()
149        else if (theSum == 7) this.appendable = new Appendable()
150        {
151            public Appendable append(char ch) throws IOException
152            { a.append(ch); b.append(ch); c.append(ch); return this; }
153    
154            public Appendable append(CharSequence cs) throws IOException
155            { a.append(cs); b.append(cs); c.append(cs); return this; }
156
157            public Appendable append(CharSequence cs, int start, int end) throws IOException
158            { a.append(cs, start, end); b.append(cs, start, end); c.append(cs, start, end); return this; }
159        };
160
161        // This appears (on cursory inspection) very "unreachable".  However the java compiler
162        // doesn't seem to like it!  (javac complains without this last line)
163
164        else throw new UnreachableError();
165    }
166
167    /**
168     * Logs a {@code char} (input-parameter {@code 'ch'}) to any / all non-null
169     * {@code Appendable's} that were passed to this class' constructor.
170     * 
171     * @param ch Any Java Character
172     * 
173     * @throws IOException Throws if any of the underlying {@code Appendable's} throw
174     * {@code IOException} upon having their corresponding {@code append()}-method invoked.
175     */
176    public Appendable append(char ch) throws IOException
177    { return this.appendable.append(ch); }
178
179    /**
180     * Logs a {@code CharSequence} (input-parameter {@code 'cs'}) to any / all non-null
181     * {@code Appendable's} that were passed to this class' constructor.
182     * 
183     * @param cs Any Java {@code CharSequence}
184     * 
185     * @throws IOException Throws if any of the underlying {@code Appendable's} throw
186     * {@code IOException} upon having their corresponding {@code append()}-method invoked.
187     */
188    public Appendable append(CharSequence cs) throws IOException
189    { return this.appendable.append(cs); }
190
191    /**
192     * Logs a partial / substring {@code CharSequence} (input-parameter {@code 'cs'}) to any / all
193     * non-null {@code Appendable's} that were passed to this class' constructor.
194     * 
195     * @param cs Any Java {@code CharSequence}
196     * 
197     * @param start Position within {@code 'cs'} of the {@code substring's} first character to be
198     * appended
199     * 
200     * @param end Position within {@code 'cs'} of the {@code substring's} last character to be
201     * appended
202     * 
203     * @throws IOException Throws if any of the underlying {@code Appendable's} throw
204     * {@code IOException} upon having their corresponding {@code append()}-method invoked.
205     */
206    public Appendable append(CharSequence cs, int start, int end) throws IOException
207    { return this.appendable.append(cs, start, end); }
208}
209