001package Torello.JavaDoc.SyntaxHiLite;
002
003import Torello.CSS.ClassNameCSSException;
004
005import Torello.HTML.HTMLTags;
006import Torello.HTML.TagNode;
007import Torello.HTML.SD;
008import Torello.HTML.TC;
009
010import Torello.Java.Additional.Ret2;
011
012import java.util.Objects;
013import java.util.Arrays;
014
015public class AbstractConfig<T extends AbstractConfig<T>>
016    implements java.io.Serializable
017{    
018    protected static final long serialVersionUID = 1;
019
020
021    // ********************************************************************************************
022    // ********************************************************************************************
023    // Class-Config - Fields (These a)
024    // ********************************************************************************************
025    // ********************************************************************************************
026
027
028    protected final String[] classNames;
029
030    protected final boolean[] spansOrBolds, utilize;
031
032    protected boolean   upperOrLower_TagName        = true;
033    protected boolean   upperOrLower_ClassAttrName  = true;
034    protected SD        quotes                      = null;
035
036    private final int CONFIG_ARR_LEN;
037
038    private final Class<T> captureTheClassDummy;
039
040    protected AbstractConfig(
041            final int       CONFIG_ARR_LEN,
042            final boolean[] spansOrBolds,
043            final Class<T>  captureTheClassDummy
044        )
045    {
046        Objects.requireNonNull
047            (spansOrBolds, "The array passed to parameter 'spansOrBolds' is null");
048
049        Objects.requireNonNull
050            (captureTheClassDummy, "The class passed to parameter 'captureTheClassDummy' is null");
051
052        if (CONFIG_ARR_LEN < 1) throw new IllegalArgumentException(
053            '[' + CONFIG_ARR_LEN + "] was passed to CONFIG_ARR_LEN, but this value must be a " +
054            "positive integer that is greater than 0."
055        );
056
057        if (spansOrBolds.length != CONFIG_ARR_LEN) throw new IllegalArgumentException(
058            "The length of the Array-Parameter 'spansOrBolds' is [" + spansOrBolds.length + "], " +
059            "but the value passed to parameter CONFIG_ARR_LENGTH was [" + CONFIG_ARR_LEN + "].  " +
060            "These values must be equals."
061        );
062
063        this.CONFIG_ARR_LEN         = CONFIG_ARR_LEN;
064        this.captureTheClassDummy   = captureTheClassDummy;
065
066        this.classNames     = new String[CONFIG_ARR_LEN];
067        this.spansOrBolds   = new boolean[CONFIG_ARR_LEN];
068        this.utilize        = new boolean[CONFIG_ARR_LEN];
069
070        for (int i=1; i < CONFIG_ARR_LEN; i++) this.classNames[i]   = "HL-" + i;
071        for (int i=0; i < CONFIG_ARR_LEN; i++) this.spansOrBolds[i] = spansOrBolds[i];
072        for (int i=0; i < CONFIG_ARR_LEN; i++) this.utilize[i]      = true;
073    }
074
075    protected AbstractConfig(AbstractConfig<T> c)
076    {
077        final int L = this.CONFIG_ARR_LEN = c.CONFIG_ARR_LEN;
078
079        this.captureTheClassDummy = c.captureTheClassDummy;
080
081        this.classNames      = new String[c.CONFIG_ARR_LEN];
082        this.spansOrBolds    = new boolean[c.CONFIG_ARR_LEN];
083        this.utilize         = new boolean[c.CONFIG_ARR_LEN];
084
085        System.arraycopy(c.classNames,   0, this.classNames,    0, L);
086        System.arraycopy(c.spansOrBolds, 0, this.spansOrBolds,  0, L);
087        System.arraycopy(c.utilize,      0, this.utilize,       0, L);
088
089        this.upperOrLower_TagName       = c.upperOrLower_TagName;
090        this.upperOrLower_ClassAttrName = c.upperOrLower_ClassAttrName;
091        this.quotes                     = c.quotes;
092    }
093
094
095    // ********************************************************************************************
096    // ********************************************************************************************
097    // Class-Config - "Setters" and "Getters" (This is SYNCHRONIZED, That's Why)
098    // ********************************************************************************************
099    // ********************************************************************************************
100
101
102    public synchronized AbstractConfig<T> setClassNameCSS(byte whichOne, String className)
103    {
104        checkWhichOne(whichOne);
105        ClassNameCSSException.check(className);
106        this.classNames[whichOne] = className;
107        return this;
108    }
109
110    public synchronized String getClassName(byte whichOne)
111    { checkWhichOne(whichOne);  return this.classNames[whichOne]; }
112
113    public synchronized AbstractConfig<T> setSpanOrBold(byte whichOne, boolean spanOrBold)
114    {
115        checkWhichOne(whichOne);
116        this.spansOrBolds[whichOne] = spanOrBold;
117        return this;
118    }
119
120    public synchronized boolean getSpansOrBolds(byte whichOne)
121    { checkWhichOne(whichOne);  return this.spansOrBolds[whichOne]; }
122
123    public synchronized AbstractConfig<T> setUtilizeOrForget(byte whichOne, boolean useOrForget)
124    {
125        checkWhichOne(whichOne);
126        this.utilize[whichOne] = useOrForget;
127        return this;
128    }
129
130    public synchronized boolean getUtilized(byte whichOne)
131    { checkWhichOne(whichOne);  return this.utilize[whichOne]; }
132
133    private void checkWhichOne(byte whichOne)
134    {
135        if ((whichOne < 1) || (whichOne >= this.CONFIG_ARR_LEN))
136
137            throw new IllegalArgumentException(
138                "You have passed an invalid value [" + whichOne + "], to parameter 'whichOne'.  " +
139                "This must be a valid byte, whose value is between 1 and " +
140                (this.CONFIG_ARR_LEN - 1)
141            );
142    }
143
144
145    // ********************************************************************************************
146    // ********************************************************************************************
147    // This method serves as a "Helper" to the method that creates a HiLiter in sub-classes
148    // ********************************************************************************************
149    // ********************************************************************************************
150
151
152    protected Ret2<TagNode[], TagNode[]> generateHiLiterHelper() 
153    {
154        final String    cAttr       = this.upperOrLower_ClassAttrName ? "CLASS" : "class";
155        final boolean   useQuotes   = (this.quotes != null);
156        final String    q           = useQuotes ? ("" + this.quotes.quote) : "";
157
158        final TagNode CLOSE_SPAN = this.upperOrLower_TagName
159            ? HTMLTags.hasTag("SPAN", TC.ClosingTags)
160            : HTMLTags.hasTag("span", TC.ClosingTags);
161
162        final TagNode CLOSE_BOLD = this.upperOrLower_TagName
163            ? HTMLTags.hasTag("B", TC.ClosingTags)
164            : HTMLTags.hasTag("b", TC.ClosingTags);
165
166        final TagNode[] openers = new TagNode[this.CONFIG_ARR_LEN];
167        final TagNode[] closers = new TagNode[this.CONFIG_ARR_LEN];
168
169        for (int i=1; i < this.CONFIG_ARR_LEN; i++)
170        {
171            openers[i] = this.utilize[i]
172                ? TAG(cAttr, q, this.classNames[i], this.spansOrBolds[i])
173                : null;
174
175            closers[i] = this.utilize[i]
176                ? (spansOrBolds[i] ? CLOSE_SPAN : CLOSE_BOLD)
177                : null;
178        }
179
180        return new Ret2<>(openers, closers);
181    }
182
183    private TagNode TAG(String cAttr, String q, String className, boolean spanOrBold)
184    {
185        final String tag;
186
187        if (upperOrLower_TagName)   tag = spanOrBold ? "SPAN" : "B";
188        else                        tag = spanOrBold ? "span" : "b";
189
190        return new TagNode('<' + tag + ' ' + cAttr + '=' + q + className + q + '>');
191    }
192
193
194    // ********************************************************************************************
195    // ********************************************************************************************
196    // Class-Config - java.lang.Object (JLO) & java.lang.Cloneable
197    // ********************************************************************************************
198    // ********************************************************************************************
199
200
201    public boolean equals(Object other)
202    {
203        if (! (other instanceof Torello.JavaDoc.SyntaxHiLite.AbstractConfig))
204            return false;
205
206        @SuppressWarnings("rawtypes")
207        Torello.JavaDoc.SyntaxHiLite.AbstractConfig o =
208            (Torello.JavaDoc.SyntaxHiLite.AbstractConfig) other;
209
210        return
211                (this.CONFIG_ARR_LEN == o.CONFIG_ARR_LEN)
212            &&  Objects.equals(this.captureTheClassDummy, o.captureTheClassDummy)
213
214            &&  Arrays.equals(this.classNames,      o.classNames)
215            &&  Arrays.equals(this.spansOrBolds,    o.spansOrBolds)
216            &&  Arrays.equals(this.utilize,         o.utilize)
217
218            // Tag-Case / Upper-Case or Lower-Case
219            &&  (this.upperOrLower_TagName          == o.upperOrLower_TagName)
220            &&  (this.upperOrLower_ClassAttrName    == o.upperOrLower_ClassAttrName)
221            &&  Objects.equals(this.quotes, o.quotes);
222    }
223
224    public int hashCode()
225    {
226        int ret = 0;
227
228        for (int i=0; i < this.CONFIG_ARR_LEN; i += 3)
229            ret += this.classNames[i].hashCode();
230
231        for (int i=0; i < this.CONFIG_ARR_LEN; i += 3)
232            ret += (this.spansOrBolds[i] ? 1 : 0) * 1;
233
234        return ret;
235    }
236}