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     */
016    package org.opengion.fukurou.util;
017    
018    import java.io.UnsupportedEncodingException;
019    import java.util.List;
020    import java.util.ArrayList;
021    import java.util.Arrays;
022    
023    /**
024     * FixLengthData.java は、固定長??タを作?するための簡易クラスです?
025     *
026     * ??タの?(String[])を?それぞれの中で?桁数にあわせて、スペ?ス埋めします?
027     * ??目間に、追?るスペ?ス数は、setAddLength( int[] ) メソ?で?
028     * ??目のタイ?半角文字?全角混在、数?の??、setType( int[] ) メソ?行います?
029     *
030     * こ?クラスは同期処??保障されて?せん?
031     *
032     * @og.rev 5.6.6.0 (2013/07/05) keys の整合?チェ?を追?
033     *
034     * @version  4.0
035     * @author       Kazuhiko Hasegawa
036     * @since    JDK5.0,
037     */
038    public final class FixLengthData {
039    
040            /** ?タイプ?定義変数?X:半角文?{@value} */
041            public static final int X = 0 ;
042            /** ?タイプ?定義変数?S:数?前空白)     {@value}        */
043            public static final int S = 1 ;                                                                         // 5.6.6.0 (2013/07/05) 前空白詰めに変更
044            /** ?タイプ?定義変数?K:半角?角混在     {@value}        */
045            public static final int K = 2 ;
046            /** ?タイプ?定義変数?X9:数?前ゼロ)     {@value}        */
047            public static final int S0 = 3 ;                                                                        // 5.6.6.0 (2013/07/05) 前ゼロ詰めを変更
048    
049            /** ?間空白配?の定義変数?T:タブ区?    {@value}        */
050            public static final int T  = -1 ;                                                                       // 5.6.6.0 (2013/07/05) タブ区?
051            public static final int T2 = -2 ;                                                                       // 5.6.6.0 (2013/07/05) タブ区?
052            public static final int T3 = -3 ;                                                                       // 5.6.6.0 (2013/07/05) タブ区?
053            public static final int T4 = -4 ;                                                                       // 5.6.6.0 (2013/07/05) タブ区?
054    
055            private static final String[] TAB = new String[] { "","\t","\t\t","\t\t\t","\t\t\t\t" };
056    
057            private static final String CR = System.getProperty("line.separator");
058    
059            /** 初期 ENCODE ?{@value}       */
060            public static final String ENCODE = "Windows-31J" ;
061    
062            private final int[]     addLen  ;               // ?ータ間に追?るスペ?スを設定する?
063            private final int[]     type    ;               // ?ータの固定長形式? 0:半角文?1:数?前空白) 2:半角?角混在 3:数?前ゼロ) 
064            private final int       size    ;               // ??タの個数
065    //      private String  encode  = ENCODE;       // 5.6.6.0 (2013/07/05) ?
066    
067            private int[]           maxLen  = null;         // ?変数。各??タの?長を記?する?
068            private String[]        fill_X  = null;         // スペ?スの??
069            private String[]        fill_S  = null;         // ゼロの??
070            private String[]        addSpc  = null;         // ?変数。addLen で?された?数??空白を管?ます?
071            private final List<String[]> list = new ArrayList<String[]>();
072    
073            /**
074             * ??タの?数を指定して、オブジェクトを構築します?
075             *
076             * @og.rev 5.6.6.0 (2013/07/05) addLen の代わりに、addSpc で管?ます?
077             *
078             * @param       len     ??タの?数
079             */
080            public FixLengthData( final int len ) {
081                    size    = len ;
082                    addLen  = new int[size];
083                    type    = new int[size];
084                    maxLen  = new int[size];
085            }
086    
087            /**
088             * ?間空白配?と??目のタイプ?列を?して、オブジェクトを構築します?
089             * どちらも、int型?列なので??番に注意してください?
090             *
091             * @og.rev 5.6.6.0 (2013/07/05) 新規追?
092             *
093             * @param   inAddLen    ??タの?間空白配?
094             * @param   inType              ??タの??目のタイプ??
095             * @see         #setAddLength( int[] )
096             * @see         #setType( int[] )
097             * @throws  IllegalArgumentException 引数?null の場?
098             */
099            public FixLengthData( final int[] inAddLen,final int[] inType ) {
100                    if( inAddLen == null || inType == null ) {
101                            String errMsg = "?間空白配? また???目のタイプ?列に、null は、指定できません?;
102                            throw new IllegalArgumentException( errMsg );
103                    }
104    
105                    size    = inAddLen.length ;
106    
107                    addLen  = new int[size];
108                    type    = new int[size];
109                    maxLen  = new int[size];
110    
111                    setAddLength( inAddLen );
112                    setType( inType );
113            }
114    
115            /**
116             * ??タの全角混在時に??長を算?するのに使用する エンコード方式を?します?
117             * 固定長では、基本?は、?角2Byte 半角1Byte で換算すべきです?
118             * 設定?が?null また?、ゼロ??の場合?、NullPointerException ?throw されます?
119             * 初期値は?Windows-31J" です?
120             *
121             * @og.rev 5.6.6.0 (2013/07/05) ?。基本?外部からエンコード指定する??な??
122             *
123             * @param       encode  全角混在時?固定長?数算?エンコー?
124             * @throws  IllegalArgumentException 引数?null また?、ゼロ??の場?
125             */
126    //      public void setEncode( final String encode ) {
127    //              if( encode == null || encode.length() == 0 ) {
128    //                      String errMsg = "エンコードに、null また?、ゼロ??は、指定できません?;
129    //                      throw new IllegalArgumentException( errMsg );
130    //              }
131    //
132    //              this.encode = encode;
133    //      }
134    
135            /**
136             * ??タの?に対応した?固定時の間に挿入する空白?数を指定します?
137             * 初期値は? です?
138             *
139             * @og.rev 5.6.6.0 (2013/07/05) addLen の代わりに、addSpc で管?ます?
140             *
141             * @param   inAddLen    ??タの?間空白配?
142             * @throws  IllegalArgumentException 引数の??タ件数が?コンストラクタで?した数と異なる??
143             */
144            public void setAddLength( final int[] inAddLen ) {
145                    int len = (inAddLen == null) ? 0 : inAddLen.length ;
146                    if( len != size ) {
147                            String errMsg = "引数の??タ件数が?コンストラクタで?した数と異なります?"
148                                                                    + "SIZE=[" + size + "] , 引数長=[" + len + "]" ;
149                            throw new IllegalArgumentException( errMsg );
150                    }
151    
152                    System.arraycopy( inAddLen,0,addLen,0,size );
153            }
154    
155            /**
156             * ??タの??目のタイ?半角文字?数?を指定します?
157             * X:半角文字?場合?、データを前方に、余った?を後方にスペ?スを埋めます?
158             * S:数?前空白)の場合?、データを後方に、余った?を空白を前方に埋めます?
159             * S0:数?前ゼロ)の場合?、データを後方に、余った?をゼロを前方に埋めます?
160             * K:半角?角混在の場合?、ENCODE(Windows-31J) で?数を求めるとともに、X:半角文字と同様?処?行います?
161             * 初期値は、X:半角文?です?
162             *
163             * @param   inType      ??タの??目のタイプ??
164             * @see #X
165             * @see #S
166             * @see #S0
167             * @see #K
168             * @throws  IllegalArgumentException 引数の??タ件数が?コンストラクタで?した数と異なる??
169             */
170            public void setType( final int[] inType ) {
171                    int len = (inType == null) ? 0 : inType.length ;
172                    if( len != size ) {
173                            String errMsg = "引数の??タ件数が?コンストラクタで?した数と異なります?"
174                                                                    + "SIZE=[" + size + "] , 引数長=[" + len + "]" ;
175                            throw new IllegalArgumentException( errMsg );
176                    }
177    
178                    System.arraycopy( inType,0,type,0,size );
179            }
180    
181            /**
182             * ??タの??目に対応した?列データを設定します?
183             * 配???タを登録しながら、各?の???タ長をピ?ア??して?ます?
184             *
185             * @param       inData  ??タの??目の配???タ
186             * @throws  IllegalArgumentException 引数の??タ件数が?コンストラクタで?した数と異なる??
187             */
188            public void addListData( final String[] inData ) {
189                    int len = (inData == null) ? 0 : inData.length ;
190                    if( len != size ) {
191                            String errMsg = "引数の??タ件数が?コンストラクタで?した数と異なります?"
192                                                                    + "SIZE=[" + size + "] , 引数長=[" + len + "]" ;
193                            throw new IllegalArgumentException( errMsg );
194                    }
195    
196                    // ???タ長の取得?み行っておきます?
197                    try {
198                            for( int i=0; i<size; i++ ) {
199                                    if( inData[i] != null ) {
200                                            if( type[i] == K ) {
201                                                    len = inData[i].getBytes( ENCODE ).length ;
202                                            }
203                                            else {
204                                                    len = inData[i].length();
205                                            }
206                                            if( maxLen[i] < len ) { maxLen[i] = len; }
207                                    }
208                            }
209                    }
210                    catch( UnsupportedEncodingException ex ) {
211                            String errMsg = "??タの変換に失敗しました?" + ENCODE + "]" ;
212                            throw new RuntimeException( errMsg,ex );
213                    }
214                    list.add( inData );
215            }
216    
217            /**
218             * ??行に対する固定文字数に設定された??を返します?
219             * 引数の行番号は、addListData(String[])メソ?で登録された?番です?
220             *
221             * @og.rev 5.6.6.0 (2013/07/05) addLen の代わりに、addSpc で管?ます?
222             *
223             * @param       line    行番号(addListData で登録した?
224             *
225             * @return      固定文字数に設定された??
226             */
227            public String getFixData( final int line ) {
228                    if( fill_X == null ) { makeSpace(); }   // 初期処?
229    
230                    String[] data = list.get( line );
231                    StringBuilder rtn = new StringBuilder();
232                    for( int i=0; i<size; i++ ) {
233                            String dt = ( data[i] == null ) ? "" : data[i] ;
234                            switch( type[i] ) {
235                                    case X: // ?を出力してから、スペ?スで埋める?
236                                                    rtn.append( dt );
237                                                    rtn.append( fill_X[i].substring( dt.length() ) );
238                                                    break;
239                                    case S: // 空白で埋めてから、文字を出力する?
240                                                    rtn.append( fill_X[i].substring( dt.length() ) );
241                                                    rtn.append( dt );
242                                                    break;
243                                    case S0: // ゼロで埋めてから、文字を出力する?
244                                                    rtn.append( fill_S[i].substring( dt.length() ) );
245                                                    rtn.append( dt );
246                                                    break;
247                                    case K: // 全角を含?字を出力してから、スペ?スで埋める?
248                                                    try {
249                                                            int len = dt.getBytes( ENCODE ).length ;
250                                                            rtn.append( dt );
251                                                            rtn.append( fill_X[i].substring( len ) );
252                                                    }
253                                                    catch( UnsupportedEncodingException ex ) {
254                                                            String errMsg = "??タの変換に失敗しました?" + ENCODE + "]" ;
255                                                            throw new RuntimeException( errMsg,ex );
256                                                    }
257                                                    break;
258                                    default: // 基本?ありえな?
259                                                    String errMsg = "不正な種別が指定されました[" + type[i] + "]" ;
260                                                    throw new RuntimeException( errMsg );
261                                    //              break;
262                            }
263                            rtn.append( addSpc[i] );                // 5.6.6.0 (2013/07/05) ?間?スペ?スを??
264                    }
265                    return rtn.toString();
266            }
267    
268            /**
269             * ??タの??目に対応した?列データを?すべて設定します?
270             * ここでは??列?配?型データを受け取り???、addListData( String[] )?
271             * 実行して?す?
272             * 簡易的なメソ?です?
273             *
274             * @og.rev 5.6.6.0 (2013/07/05) 新規追?
275             *
276             * @param       inData  ??タの??目の配???タの配?
277             * @see         #addListData( String[] )
278             * @throws  IllegalArgumentException 引数の??タ件数が?コンストラクタで?した数と異なる??
279             */
280            public void addAllListData( final String[][] inData ) {
281                    for( int i=0; i<inData.length; i++ ) {
282                            addListData( inData[i] );
283                    }
284            }
285    
286            /**
287             * ?登録済みのすべての??タを?結して出力します?
288             * 連結時には、改行コードを設定して?す?
289             *
290             * @og.rev 5.6.6.0 (2013/07/05) getAllFixData( StringBuilder ) を使用するように?処?変更
291             *
292             * @return      固定文字数に設定された??
293             * @see         #getFixData( int )
294             * @see         #getAllFixData( StringBuilder )
295             */
296            public String getAllFixData() {
297                    return getAllFixData( new StringBuilder( 1000 ) ).toString();
298    
299    //              StringBuilder buf = new StringBuilder( 1000 );
300    //
301    //              int len = list.size();
302    //              for( int i=0; i<len; i++ ) {
303    //                      buf.append( getFixData( i ) ).append( CR );
304    //              }
305    //
306    //              return buf.toString();
307            }
308    
309            /**
310             * ?登録済みのすべての??タを引数のStringBuilderに連結して返します?
311             * 連結時には、改行コードを設定して?す?
312             * return オブジェクト?、この引数と同??オブジェクトです?
313             *
314             * @og.rev 5.6.6.0 (2013/07/05) 新規追?
315             *
316             * @param       buf 連結に使用する StringBuilder
317             * @return      固定文字数に設定された StringBuilder(入力と同じ)
318             * @see         #getFixData( int )
319             * @see         #getAllFixData()
320             */
321            public StringBuilder getAllFixData( final StringBuilder buf ) {
322                    int len = list.size();
323                    for( int i=0; i<len; i++ ) {
324                            buf.append( getFixData( i ) ).append( CR );
325                    }
326    
327                    return buf;
328            }
329    
330            /**
331             * 固定文字?を作?するための種となるスペ?ス??とゼロ??を作?します?
332             *
333             * @og.rev 5.6.6.0 (2013/07/05) addLen の代わりに、addSpc で管?ます?
334             */
335            private void makeSpace() {
336                    fill_X  = new String[size];
337                    fill_S  = new String[size];
338                    addSpc  = new String[size];
339                    char[] ch ;
340    
341                    int startCnt = 0;                               // 先?からの?数
342                    for( int i=0; i<size; i++ ) {
343    //                      char[] ch = new char[maxLen[i]+addLen[i]];
344                            // addLen に、T(タ?が指定された場合?addSpc は?の倍数になるよ?調整する?
345                            startCnt += maxLen[i];
346                            int addCnt = addLen[i] ;
347                            if( addCnt < 0 ) {                                   // T,T2,T3,T4 のケース
348            //                      addSpc[i] = TAB[-addCnt];
349                                    addCnt = (-4*addCnt) - (startCnt % 4);          // TAB数に合わせたスペ?スに換算した数
350                            }
351            //              else {
352                                    ch = new char[addCnt];
353                                    Arrays.fill( ch, ' ' );
354                                    addSpc[i] = String.valueOf( ch );
355            //              }
356                            startCnt += addCnt ;
357    
358                            ch = new char[maxLen[i]];
359                            switch( type[i] ) {
360                                    case S0:
361                                                    Arrays.fill( ch, '0' );
362                                                    fill_S[i] = String.valueOf( ch );
363                                                    break;
364                                    case X:
365                                    case S:
366                                    case K:
367                                                    Arrays.fill( ch, ' ' );
368                                                    fill_X[i] = String.valueOf( ch );
369                                                    break;
370                                    default: // 基本?ありえな?
371                                                    String errMsg = "不正な種別が指定されました[" + type[i] + "]" ;
372                                                    throw new RuntimeException( errMsg );
373                                    //              break;
374                            }
375                    }
376            }
377    
378            /**
379             * ?変数の??タと、最大値のキャ?ュをクリアします?
380             *
381             * それ以外?変数(size、addLength、type)は、設定時のまま残って?す?
382             *
383             */
384            public void clear() {
385                    list.clear() ;
386                    maxLen  = new int[size];
387                    fill_X  = null;         // スペ?スの??
388                    fill_S  = null;         // ゼロの??
389                    addSpc  = null;         // ?間空白
390            }
391    }