001/*
002 * Copyright (c) 2009 The openGion Project.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
013 * either express or implied. See the License for the specific language
014 * governing permissions and limitations under the License.
015 */
016package org.opengion.fukurou.system;
017
018import java.util.function.Function;
019import java.util.function.IntFunction;                                          // 6.4.4.2 (2016/04/01)
020import java.util.function.Supplier;                                                     // 6.4.4.2 (2016/04/01)
021
022/**
023 * 内部にStringBuilderを持った、文字列連結クラスです。
024 *
025 * 文字列連結時に、取り込む/取り込まないの判断を行う、boolean 付きの
026 * appendIf メソッドや、null値を無視する append など、用意しています。
027 *
028 * @og.rev 6.4.4.1 (2016/03/18) 新規追加
029 * @og.rev 6.4.5.0 (2016/04/08) CharSequenceインタフェースの追加
030 *
031 * @og.group その他
032 *
033 * @version  6.0
034 * @author       Kazuhiko Hasegawa
035 * @since    JDK8.0,
036 */
037public final class OgBuilder implements CharSequence {
038        private final StringBuilder buf = new StringBuilder( HybsConst.BUFFER_MIDDLE );
039
040        /**
041         * デフォルトコンストラクター
042         *
043         * @og.rev 6.4.4.1 (2016/03/18) 新規追加
044         */
045        public OgBuilder() { super(); }         // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。
046
047        /**
048         * 引数の可変長文字列を追加する appendです。
049         *
050         * 引数の可変長文字列の個々の文字列が null の場合は、追加しません。
051         *
052         * @og.rev 6.4.4.1 (2016/03/18) 新規追加
053         * @og.rev 6.4.5.0 (2016/04/08) 引数を可変長CharSequenceに変更
054         *
055         * @param arys  追加する可変長CharSequence
056         * @return      自分自身
057         * @og.rtnNotNull
058         */
059        public OgBuilder append( final CharSequence... arys ) {
060                if( arys != null ) {
061                        for( final CharSequence str : arys ) {
062                                if( str != null ) { buf.append( str ); }
063                        }
064                }
065
066                return this;
067        }
068
069        /**
070         * 連結文字列を、使用して、可変長引数のCharSequenceを連結して返します。
071         * 連結文字列が、null の場合は、CharSequenceをそのまま連結していきます。
072         * 連結するCharSequenceが null の場合は、連結しません。
073         * 連結文字列は、一番最後は出力されません。
074         *
075         * @og.rev 6.4.5.0 (2016/04/08) 新規追加
076         *
077         * @param       delimiter       連結文字列
078         * @param       arys    連結する可変長CharSequence
079         *
080         * @return      自分自身
081         * @og.rtnNotNull
082         */
083        public OgBuilder join( final String delimiter , final CharSequence... arys ) {
084                if( delimiter == null ) { return append( arys ); }
085
086                if( arys != null ) {
087                        boolean isAdd = false;
088                        for( final CharSequence str : arys ) {
089                                if( str != null && str.length() > 0 ) {
090                                        buf.append( str ).append( delimiter );
091                                        isAdd = true;
092                                }
093                        }
094                        if( isAdd ) { buf.setLength( buf.length()-delimiter.length() ); }       // 最後に追加した delimiter を削除。
095                }
096
097                return this;
098        }
099
100        /**
101         * 引数の可変長文字列を内部バッファーから削除します。
102         *
103         * 引数の可変長文字列の個々の文字列が null の場合は、なにもしません。
104         * また、内部バッファーに存在しない場合も、何もしません。
105         *
106         * ※ 削除の指定は、CharSequenceではなく文字列です。
107         *
108         * @og.rev 6.4.5.0 (2016/04/08) 新規追加
109         *
110         * @param arys  削除する可変長文字列
111         * @return      自分自身
112         * @og.rtnNotNull
113         */
114        public OgBuilder delete( final String... arys ) {
115                if( arys != null ) {
116                        for( final String str : arys ) {
117                                if( str != null ) {
118                                        final int len = str.length();           // 終了の位置を求めるのに使う。
119                                        int st;
120                                        while( ( st = buf.indexOf( str ) ) >= 0 ) {
121                                                buf.delete( st , st+len );
122                                        }
123                                }
124                        }
125                }
126
127                return this;
128        }
129
130        /**
131         * 引数の可変長CharSequenceを追加し、最後に改行コードを追加する appendです。
132         *
133         * 引数の可変長CharSequenceの個々のCharSequenceが null の場合は、追加しません。
134         * 引数がnull値の場合は、改行コードのみ追加されます。
135         *
136         * @og.rev 6.4.4.1 (2016/03/18) 新規追加
137         * @og.rev 6.4.5.0 (2016/04/08) 引数を可変長CharSequenceに変更
138         *
139         * @param arys  追加する文字列可変長(nullは追加しません)
140         * @return      自分自身
141         * @see         #append( CharSequence... )
142         * @og.rtnNotNull
143         */
144        public OgBuilder appendCR( final CharSequence... arys ) {
145                return append( arys ).append( HybsConst.CR );
146        }
147
148        /**
149         * 引数の可変長CharSequenceを追加する appendです。
150         *
151         * 引数の可変長CharSequenceの個々のCharSequenceの中に、一つでも null の場合は、
152         * すべて追加しません。
153         * 例えば、key="AAAA" のような文字列を構築したい場合、AAAA 部分が、nullの
154         * 場合は、key= の箇所も出しません。
155         *
156         * @og.rev 6.4.4.1 (2016/03/18) 新規追加
157         * @og.rev 6.4.5.0 (2016/04/08) 引数を可変長CharSequenceに変更
158         * @og.rev 6.9.0.2 (2018/02/13) not null の対象に、ゼロ文字列も含むようにします。
159         *
160         * @param arys  追加する可変長CharSequence
161         * @return      自分自身
162         * @og.rtnNotNull
163         */
164        public OgBuilder appendNN( final CharSequence... arys ) {
165                if( arys != null && arys.length > 0 ) {
166                        final StringBuilder tmp = new StringBuilder( HybsConst.BUFFER_MIDDLE );
167                        for( final CharSequence str : arys ) {
168//                              if( str == null ) { return this; }              // 一つでも null があれば、すぐに抜ける。
169                                // 6.9.0.2 (2018/02/13) 一つでも nullか、ゼロ文字列 があれば、すぐに抜ける。
170                                if( str == null || str.length() == 0 ) { return this; }
171                                else { tmp.append( str ); }
172                        }
173                        buf.append( tmp );
174                }
175                return this;
176        }
177
178        /**
179         * 文字列を追加するかどうか判定するフラグ付きのappendメソッドです。
180         *
181         * 引数の可変長CharSequenceの個々のCharSequenceが null の場合は、追加しません。
182         *
183         * @og.rev 6.4.4.1 (2016/03/18) 新規追加
184         * @og.rev 6.4.5.0 (2016/04/08) 引数を可変長CharSequenceに変更
185         *
186         * @param flag  文字列を追加するかどうか判定するフラグ(trueの時のみ追加)
187         * @param arys  追加する可変長CharSequence
188         * @return      自分自身
189         * @og.rtnNotNull
190         */
191        public OgBuilder appendIf( final boolean flag , final CharSequence... arys ) {
192                if( flag && arys != null ) {
193                        for( final CharSequence str : arys ) {
194                                if( str != null ) { buf.append( str ); }
195                        }
196                }
197
198                return this;
199        }
200
201        /**
202         * 引数の可変長CharSequenceを追加し、最後に改行コードを追加する appendです。
203         *
204         * 引数の可変長CharSequenceの個々のCharSequenceが null の場合は、追加しません。
205         * 引数がnull値の場合は、改行コードのみ追加されます。
206         *
207         * @og.rev 6.4.4.1 (2016/03/18) 新規追加
208         * @og.rev 6.4.5.0 (2016/04/08) 引数を可変長CharSequenceに変更
209         *
210         * @param flag  文字列を追加するかどうか判定するフラグ(trueの時のみ追加)
211         * @param arys  追加する可変長CharSequence
212         * @return      自分自身
213         * @see         #appendIf( boolean,CharSequence... )
214         * @og.rtnNotNull
215         */
216        public OgBuilder appendIfCR( final boolean flag , final CharSequence... arys ) {
217                return appendIf( flag,arys ).append( HybsConst.CR );
218        }
219
220        /**
221         * 関数を実行した結果を追加するかどうか判定するフラグ付きのappendメソッドです。
222         * 実行した結果が、null値の場合は、無視します。
223         * 引数が関数型インタフェースなので、遅延実行することが可能です。
224         *
225         * @og.rev 6.4.4.1 (2016/03/18) 新規追加
226         *
227         * @param <T>   関数型インタフェース(Function)の引数(総称型)
228         * @param <R>   関数型インタフェース(Function)の戻り値(総称型)
229         * @param flag  追加するかどうか判定するフラグ(trueの時のみ追加)
230         * @param key   関数の引数(総称型)
231         * @param func  関数を実行した結果を追加する関数型(結果がnullの場合は追加しません)
232         * @return      自分自身
233         * @og.rtnNotNull
234         */
235        public <T,R> OgBuilder appendIf( final boolean flag , final T key , final Function<? super T, ? extends R> func ) {
236                if( flag && func != null ) {
237                        final R obj = func.apply( key );
238                        if( obj != null ) { buf.append( obj ); }
239                }
240                return this;
241        }
242
243        /**
244         * 開始から終了までの引数を有する関数を実行した結果を追加するときのappendメソッドです。
245         * 実行した結果が、null値の場合は、無視します。
246         * 引数が関数型インタフェースなので、遅延実行することが可能です。
247         * 関数の結果は、オブジェクトを返します。それを、内部でappendループします。
248         *
249         * @og.rev 6.4.4.1 (2016/03/18) 新規追加
250         * @og.rev 6.4.4.2 (2016/04/01) IntFunction に変更。配列ではなく、オブジェクトに変更。
251         *
252         * @param <R>   IntFunctionの戻り値の仮想型
253         * @param st    ループカウンタの初期値(この値を含む)
254         * @param ed    ループカウンタの終了値(この値を含まない)
255         * @param func  関数を実行した結果を追加する関数型(結果がnullの場合は追加しません)
256         * @return      自分自身
257         * @og.rtnNotNull
258         */
259        public <R> OgBuilder appendRoop( final int st , final int ed , final IntFunction<R> func ) {
260                for( int i=st; i<ed; i++ ) {
261                        final R obj = func.apply( i );
262                        if( obj != null ) {
263                                buf.append( obj );
264                        }
265                }
266                return this;
267        }
268
269        /**
270         * 開始から終了までの引数を有する関数を実行した結果を追加するときのappendメソッドです。
271         * 連結文字列に null は指定できません。
272         * 連結文字列は、一番最後には使用しません。
273         *
274         * @og.rev 6.4.4.2 (2016/04/01) 連結文字列を指定。
275         *
276         * @param <R>   IntFunctionの戻り値の仮想型
277         * @param st    ループカウンタの初期値(この値を含む)
278         * @param ed    ループカウンタの終了値(この値を含まない)
279         * @param delimiter     文字列連結する場合の文字列。nullは指定できません。
280         * @param func  関数を実行した結果を追加する関数型(結果がnullの場合は追加しません)
281         * @return      自分自身
282         * @og.rtnNotNull
283         */
284        public <R> OgBuilder appendRoop( final int st , final int ed , final String delimiter , final IntFunction<R> func ) {
285                boolean fstFlg = true;
286                for( int i=st; i<ed; i++ ) {
287                        final R obj = func.apply( i );
288                        if( obj != null ) {
289                                if( fstFlg ) {
290                                        buf.append( obj );
291                                        fstFlg = false;
292                                }
293                                else {
294                                        buf.append( delimiter ).append( obj );
295                                }
296                        }
297                }
298                return this;
299        }
300
301        /**
302         * CharSequenceを追加するかどうか判定するフラグ付きのappendメソッドです。
303         * trueの場合は、第一引数を、falseの場合は、第二引数を追加します。
304         * 第二引数は、可変長CharSequenceです。
305         * ともに、CharSequenceがnullの場合は、無視します。
306         *
307         * @og.rev 6.4.4.1 (2016/03/18) 新規追加
308         * @og.rev 6.4.5.0 (2016/04/08) 引数を可変長CharSequenceに変更
309         *
310         * @param flag  CharSequenceを追加するかどうか判定するフラグ
311         * @param trueStr       flagがtrueの場合に追加するCharSequence(一つだけ)
312         * @param falseStr      flagがfalseの場合に追加する可変長CharSequence
313         * @return      自分自身
314         * @og.rtnNotNull
315         */
316        public OgBuilder appendCase( final boolean flag , final CharSequence trueStr , final CharSequence... falseStr ) {
317                if( flag ) {
318                        if( trueStr != null ) { buf.append( trueStr ); }
319                }
320                else {
321                        if( falseStr != null ) {
322                                for( final CharSequence str : falseStr ) {
323                                        if( str != null ) { buf.append( str ); }
324                                }
325                        }
326                }
327
328                return this;
329        }
330
331        /**
332         * CharSequenceを追加するかどうか判定するフラグ付きのappendメソッドです。
333         * trueの場合は、第一引数を、falseの場合は、第二引数を追加します。
334         * 第一引数、第二引数ともに、配列を返すSupplierクラスです。
335         * ともに、個々のCharSequenceがnullの場合は、無視します。
336         *
337         * @og.rev 6.4.4.1 (2016/03/18) 新規追加
338         * @og.rev 6.4.4.2 (2016/04/01) 引数を、Supplierクラスに変更して、結果を複数指定できるようにします。
339         * @og.rev 6.4.5.0 (2016/04/08) 引数を可変長CharSequenceに変更
340         *
341         * @param flag  CharSequenceを追加するかどうか判定するフラグ
342         * @param trueFunc      flagがtrueの場合に実行するFunctionオブジェクト
343         * @param falseFunc     flagがfalseの場合に追加するFunctionオブジェクト
344         * @return      自分自身
345         * @og.rtnNotNull
346         */
347        public OgBuilder appendCase( final boolean flag
348                                                                                , final Supplier<CharSequence[]> trueFunc
349                                                                                , final Supplier<CharSequence[]> falseFunc ) {
350                if( flag ) {
351                        final CharSequence[] tStrs = trueFunc.get();
352                        if( tStrs != null ) {
353                                for( final CharSequence tStr : tStrs ) {
354                                        if( tStr != null ) { buf.append( tStr ); }
355                                }
356                        }
357                }
358                else {
359                        final CharSequence[] fStrs = falseFunc.get();
360                        if( fStrs != null ) {
361                                for( final CharSequence fStr : fStrs ) {
362                                        if( fStr != null ) { buf.append( fStr ); }
363                                }
364                        }
365                }
366
367                return this;
368        }
369
370        /**
371         * 内部のStringBuilderそのものを返します。
372         *
373         * StringBuilderを関数等に渡して追加処理する場合に、
374         * 内部のStringBuilderを渡して、処理させることが出来ます。
375         *
376         * @og.rev 6.4.4.1 (2016/03/18) 新規追加
377         *
378         * @return      内部のStringBuilder
379         * @og.rtnNotNull
380         */
381        public StringBuilder getBuilder() {
382                return buf;
383        }
384
385        /**
386         * 内部のStringBuilderをクリアします。
387         *
388         * 具体的には、StringBuilder#setLength(0) を実行します。
389         *
390         * @og.rev 6.4.4.1 (2016/03/18) 新規追加
391         *
392         * @return      内部のStringBuilder
393         */
394        public OgBuilder clear() {
395                buf.setLength(0);
396                return this;
397        }
398
399        // ********************************** 以下は、CharSequence インタフェース の実装 **********************************
400
401        /**
402         * 指定されたインデックスのchar値を返します。
403         *
404         * インデックスは、0からlength() - 1の範囲になります。配列のインデックス付けの場合と同じように、
405         * シーケンスの最初のcharのインデックスは0、次の文字のインデックスは1と続きます。
406         *
407         * インデックスで指定されたchar値がサロゲートの場合、サロゲート値が返されます。
408         *
409         * @og.rev 6.4.5.0 (2016/04/08) 新規追加
410         *
411         * @param index 返されるchar値のインデックス
412         * @return 指定されたchar値
413         * @see         java.lang.CharSequence#charAt(int)
414         */
415        @Override       // CharSequence
416        public char charAt( final int index ) {
417                return buf.charAt( index );
418        }
419
420        /**
421         * この文字シーケンスの長さを返します。
422         *
423         * 長さはシーケンス内の16ビットcharの数に等しくなります。
424         *
425         * @og.rev 6.4.5.0 (2016/04/08) 新規追加
426         *
427         * @return このシーケンスのcharの数
428         * @see         java.lang.CharSequence#length()
429         */
430        @Override       // CharSequence
431        public int length() {
432                return buf.length();
433        }
434
435        /**
436         * この文字シーケンスの長さを返します。
437         *
438         * 長さはシーケンス内の16ビットcharの数に等しくなります。
439         *
440         * @og.rev 6.4.5.0 (2016/04/08) 新規追加
441         *
442         * @param start 開始インデックス(この値を含む)
443         * @param end   終了インデックス(この値を含まない)
444         * @return 指定されたサブシーケンス
445         * @see         java.lang.CharSequence#subSequence(int,int)
446         */
447        @Override       // CharSequence
448        public CharSequence subSequence( final int start , final int end ) {
449                return buf.subSequence( start , end );
450        }
451
452        /**
453         * このシーケンス内のデータを表す文字列を返します。
454         *
455         * 新しいStringオブジェクトが割り当てられ、現在このオブジェクトで表されている
456         * 文字シーケンスを含むように初期化されます。
457         * その後、このStringが返されます。その後このシーケンスが変更されても、Stringの内容には影響ありません。
458         *
459         * @og.rev 6.4.4.1 (2016/03/18) 新規追加
460         *
461         * @return この文字シーケンスの文字列表現。
462         * @see         java.lang.CharSequence#toString()
463         * @og.rtnNotNull
464         */
465        @Override       // CharSequence
466        public String toString() {
467                return buf.toString();
468        }
469}