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;'>two</B>
013 * independent input-parameter {@code Appendable's}.  Character data appended to an instance of
014 * {@code BiAppendable} 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", "BI_APPENDABLE_JDHBI", "BI_TRI_BOTH_JDHBI"})
030public class BiAppendable implements Appendable
031{
032    private final Appendable appendable;
033
034    /**
035     * Creates an instance of this class, using up to two 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    public BiAppendable(Appendable a, Appendable b)
044    {
045        // Minor coding trick.  Pretend this is a base-2 number, with three bits.  I think this
046        // improves efficiency a tiny bit, since it isn't comparing the nulls over and over again.
047        // Here it checks the references for nulls only once.
048
049        int theSum =
050            ((a == null) ? 0 : 2) +
051            ((b == null) ? 0 : 1);
052
053        // if ((a == null) && (b == null)) this.appendable = new Appendable()
054        if (theSum == 0) this.appendable = new Appendable()
055        {
056            public Appendable append(char ch) throws IOException
057            { return this; }
058    
059            public Appendable append(CharSequence cs) throws IOException
060            { return this; }
061
062            public Appendable append(CharSequence cs, int start, int end) throws IOException
063            { return this; }
064        };
065
066        // else if ((a == null) && (b != null)) this.appendable = new Appendable()
067        else if (theSum == 1) this.appendable = new Appendable()
068        {
069            public Appendable append(char ch) throws IOException
070            { b.append(ch); return this; }
071    
072            public Appendable append(CharSequence cs) throws IOException
073            { b.append(cs); return this; }
074
075            public Appendable append(CharSequence cs, int start, int end) throws IOException
076            { b.append(cs, start, end); return this; }
077        };
078
079        // else if ((a != null) && (b == null)) this.appendable = new Appendable()
080        else if (theSum == 2) this.appendable = new Appendable()
081        {
082            public Appendable append(char ch) throws IOException
083            { a.append(ch); return this; }
084    
085            public Appendable append(CharSequence cs) throws IOException
086            { a.append(cs); return this; }
087
088            public Appendable append(CharSequence cs, int start, int end) throws IOException
089            { a.append(cs, start, end); return this; }
090        };
091
092        // else if ((a != null) && (b != null)) this.appendable = new Appendable()
093        else if (theSum == 3) this.appendable = new Appendable()
094        {
095            public Appendable append(char ch) throws IOException
096            { a.append(ch); b.append(ch); return this; }
097    
098            public Appendable append(CharSequence cs) throws IOException
099            { a.append(cs); b.append(cs); return this; }
100
101            public Appendable append(CharSequence cs, int start, int end) throws IOException
102            { a.append(cs, start, end); b.append(cs, start, end); return this; }
103        };
104
105        // This appears (on cursory inspection) very "unreachable".  However the java compiler
106        // doesn't seem to like it!  (javac complains without this last line)
107
108        else throw new UnreachableError();
109    }
110
111    /**
112     * Logs a {@code char} (input-parameter {@code 'ch'}) to any / all non-null
113     * {@code Appendable's} that were passed to this class' constructor.
114     * 
115     * @param ch Any Java Character
116     * 
117     * @throws IOException Throws if any of the underlying {@code Appendable's} throw
118     * {@code IOException} upon having their corresponding {@code append()}-method invoked.
119     */
120    public Appendable append(char ch) throws IOException
121    { return this.appendable.append(ch); }
122
123    /**
124     * Logs a {@code CharSequence} (input-parameter {@code 'cs'}) to any / all non-null
125     * {@code Appendable's} that were passed to this class' constructor.
126     * 
127     * @param cs Any Java {@code CharSequence}
128     * 
129     * @throws IOException Throws if any of the underlying {@code Appendable's} throw
130     * {@code IOException} upon having their corresponding {@code append()}-method invoked.
131     */
132    public Appendable append(CharSequence cs) throws IOException
133    { return this.appendable.append(cs); }
134
135    /**
136     * Logs a partial / substring {@code CharSequence} (input-parameter {@code 'cs'}) to any / all
137     * non-null {@code Appendable's} that were passed to this class' constructor.
138     * 
139     * @param cs Any Java {@code CharSequence}
140     * 
141     * @param start Position within {@code 'cs'} of the {@code substring's} first character to be
142     * appended
143     * 
144     * @param end Position within {@code 'cs'} of the {@code substring's} last character to be
145     * appended
146     * 
147     * @throws IOException Throws if any of the underlying {@code Appendable's} throw
148     * {@code IOException} upon having their corresponding {@code append()}-method invoked.
149     */
150    public Appendable append(CharSequence cs, int start, int end) throws IOException
151    { return this.appendable.append(cs, start, end); }
152}