1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
package Torello.Java;

import Torello.Java.Additional.AppendableSafe;
import Torello.Java.Additional.BiAppendable;

import static Torello.Java.C.BGREEN;
import static Torello.Java.C.RESET;

import java.util.regex.Pattern;
import java.util.regex.MatchResult;
import java.util.function.Function;
import java.util.stream.Stream;

// This Configuration-Record is generated solely from the User-Input Method-Parameters which may be
// passed to the 8 variants that are offered by the Top-Level User-API Class 'SED'.  This 
// Data-Record Class does not have any methods whatsoever - it only has constructors.  Furthermore
// the fields in this Data-Class are fields which are strictly obtained (directly copied) from the
// User-Input Parameters obtained from the eight methods offered by class 'Torello.Java.SED'
// 
// ================================================================================================
// 
// The biggest benefit of looking at this is that *EVERY SINGLE ONE* of the following fields are 
// all declared 'final', and that means that when looking at the code inside of the various classes
// which do the processing for this Top-Level Dispatch-Class (Torello.Java.SED) you should be ssafe
// in knowing that instances of this class are strictly Data-Lookup, and therefore do not contain
// any fields which may be modified during the processing of a Text-File.  For some programmers, 
// especially me, this can be a somewhat non-trivial value when trying to understand what the hell
// these complicated for-loops and string-processing methods are even doing.
// 
// Note that this class has two variants for constructors.  One of the constructors is used for 
// SED-Replacement that involves Regular-Expressions, while the latter is used for direct 
// String-to-String replacements
// 
// Constructor-Variant ONE Parameters:
//      final String matchStr
//      final String replaceStr
//
// Constructor-Variant TWO Parameters:
//      final Pattern                       regEx,
//      final Function<MatchResult, String> replaceFunction
// 
// ================================================================================================
// 
// The second biggest benefit that this class provides is that because all of these fields are used
// sporadically throught he processing classes, it is more efficient to pass the parameters around 
// the internal methods used by SED.  Passing one single Record that contains all of the 
// Data-Fields (obtained from user parameters) to the methods means that their are fewer parameters
// or "arguments" to the various methods in SED.

class CONFIG_RECORD 
{
    // ********************************************************************************************
    // ********************************************************************************************
    // The two Data-Records
    // ********************************************************************************************
    // ********************************************************************************************


    // These two fields are only used when the User is doing a **REGULAR-EXPRESSION** Replacement
    final Pattern                       regEx;
    final Function<MatchResult, String> replaceFunction;

    // These two fields are only used when the User is doing a **STRING** Replacement
    final String matchStr;
    final String replaceStr;

    // This value is used repeatedly in this loop, so it is better left as a constant
    final int MATCH_STR_LEN;

    // These five fields are used when either of the two variants of SED are invoked
    final boolean               askFirst;
    final IOExceptionHandler    ioeh;
    final boolean               useUNIXColors;
    final Verbosity             verbosity;
    final Appendable            appendable;

    // Simple Print Loop Helpers ...
    final String HILITE_START;
    final String HILITE_END;


    // This Stream-Builder contains the list of FileNode's that are modified.  This Stream-Builder 
    // generates the Returned-Value from all of the SED methods which are offered by the Top-Level 
    // User-API SED-Class.

    final Stream.Builder<FileNode> ret = Stream.builder();


    // ********************************************************************************************
    // ********************************************************************************************
    // Two Constructors: One for the two Regular-Expression SED Methods, and one for String-Repl...
    // ********************************************************************************************
    // ********************************************************************************************


    // This Constructor is invoked by the two public SED methods which accept a Regular-Expression
    // Matcher along with a MatchResult Replacement-Function

    CONFIG_RECORD(
            final Pattern                       regEx, 
            final Function<MatchResult, String> replaceFunction, 
            final boolean                       askFirst,
            final IOExceptionHandler            ioeh,
            final boolean                       useUNIXColors, 
            final Verbosity                     verbosity,
            final Appendable                    outputSaver
        )
    {
        this.regEx              = regEx;
        this.replaceFunction    = replaceFunction;

        this.matchStr           = null;
        this.replaceStr         = null;
        this.MATCH_STR_LEN      = -1;

        this.askFirst           = askFirst;
        this.ioeh               = ioeh;
        this.useUNIXColors      = useUNIXColors;
        this.verbosity          = verbosity;
        this.appendable         = generateTheAppendable(outputSaver);

        this.HILITE_START       = useUNIXColors ? BGREEN  : "";
        this.HILITE_END         = useUNIXColors ? RESET   : "";
    }


    // This Constructor is (obviously!) invoked by the two SED methods which accept a Match-Sring 
    // and a Replacement-String as Configuration-Parameters.

    CONFIG_RECORD(
            final String                matchStr,
            final String                replaceStr,
            final boolean               askFirst,
            final IOExceptionHandler    ioeh,
            final boolean               useUNIXColors, 
            final Verbosity             verbosity,
            final Appendable            outputSaver
        )
    {
        this.regEx              = null;
        this.replaceFunction    = null;

        this.matchStr           = matchStr;
        this.replaceStr         = replaceStr;
        this.MATCH_STR_LEN      = matchStr.length();

        this.askFirst           = askFirst;
        this.ioeh               = ioeh;
        this.useUNIXColors      = useUNIXColors;
        this.verbosity          = verbosity;
        this.appendable         = generateTheAppendable(outputSaver);

        this.HILITE_START       = useUNIXColors ? BGREEN  : "";
        this.HILITE_END         = useUNIXColors ? RESET   : "";
    }


    // ********************************************************************************************
    // ********************************************************************************************
    // Very Short, Static, Constructor-Helper Method
    // ********************************************************************************************
    // ********************************************************************************************


    private static Appendable generateTheAppendable(final Appendable outputSaver)
    {
        return (outputSaver == null)

            // If no 'outputSaver' was provided, then just send text to Standard-Out
            ? System.out

            // This just allows for printing to **BOTH** System.out **AND** the 'outputSaver'
            : new BiAppendable
                (System.out, new AppendableSafe(outputSaver, AppendableSafe.USE_APPENDABLE_ERROR));
    }
}