001/*
002 *  jDTAUS Banking RI DTAUS
003 *  Copyright (C) 2005 Christian Schulte
004 *  <cs@schulte.it>
005 *
006 *  This library is free software; you can redistribute it and/or
007 *  modify it under the terms of the GNU Lesser General Public
008 *  License as published by the Free Software Foundation; either
009 *  version 2.1 of the License, or any later version.
010 *
011 *  This library is distributed in the hope that it will be useful,
012 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
013 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014 *  Lesser General Public License for more details.
015 *
016 *  You should have received a copy of the GNU Lesser General Public
017 *  License along with this library; if not, write to the Free Software
018 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
019 *
020 */
021package org.jdtaus.banking.dtaus.ri.zka;
022
023import java.io.IOException;
024import java.math.BigInteger;
025import java.util.ArrayList;
026import java.util.Currency;
027import java.util.Date;
028import java.util.List;
029import org.jdtaus.banking.AlphaNumericText27;
030import org.jdtaus.banking.Bankleitzahl;
031import org.jdtaus.banking.Kontonummer;
032import org.jdtaus.banking.Referenznummer10;
033import org.jdtaus.banking.Referenznummer11;
034import org.jdtaus.banking.Textschluessel;
035import org.jdtaus.banking.dtaus.Checksum;
036import org.jdtaus.banking.dtaus.CorruptedException;
037import org.jdtaus.banking.dtaus.Header;
038import org.jdtaus.banking.dtaus.LogicalFileType;
039import org.jdtaus.banking.dtaus.PhysicalFileFactory;
040import org.jdtaus.banking.dtaus.Transaction;
041import org.jdtaus.banking.dtaus.spi.Fields;
042import org.jdtaus.banking.messages.IllegalDataMessage;
043import org.jdtaus.core.container.ContainerFactory;
044import org.jdtaus.core.container.Implementation;
045import org.jdtaus.core.container.ModelFactory;
046import org.jdtaus.core.logging.spi.Logger;
047import org.jdtaus.core.text.Message;
048
049/**
050 * Anlage 3 - 1.1 DTAUS0: Zahlungsverkehrssammelauftrag Diskettenformat.
051 *
052 * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
053 * @version $JDTAUS: DTAUSDisk.java 8817 2013-06-07 19:37:52Z schulte $
054 */
055public final class DTAUSDisk extends AbstractLogicalFile
056{
057
058    /** Länge des konstanten Teiles eines C Datensatzes in Byte. */
059    protected static final int CRECORD_CONST_LENGTH = 187;
060
061    /** Länge eines Erweiterungsteiles in Byte. */
062    protected static final int CRECORD_EXT_LENGTH = 29;
063
064    /**
065     * Index = A Datensatz-Feld - 1,
066     * Wert = Offset relativ zum Anfang des Satzabschnittes.
067     */
068    protected static final int[] ARECORD_OFFSETS =
069    {
070        0, 4, 5, 7, 15, 23, 50, 56, 60, 70, 80, 95, 103, 127
071    };
072
073    /**
074     * Index = A Datensatz-Feld - 1,
075     * Wert = Länge des Feldes in Byte.
076     */
077    protected static final int[] ARECORD_LENGTH =
078    {
079        4, 1, 2, 8, 8, 27, 6, 4, 10, 10, 15, 8, 24, 1
080    };
081
082    /**
083     * Index = E Datensatz-Feld - 1,
084     * Wert = Offset relativ zum Anfang des Satzabschnittes.
085     */
086    protected static final int[] ERECORD_OFFSETS =
087    {
088        0, 4, 5, 10, 17, 30, 47, 64, 77
089    };
090
091    /**
092     * Index = E Datensatz-Feld -1,
093     * Wert = Länge des Feldes in Byte.
094     */
095    protected static final int[] ERECORD_LENGTH =
096    {
097        4, 1, 5, 7, 13, 17, 17, 13, 51
098    };
099
100    /**
101     * Index = C Datensatz-Feld - 1,
102     * Wert = Offset relativ zum ersten Satzabschnitt.
103     */
104    protected static final int[] CRECORD_OFFSETS1 =
105    {
106        0, 4, 5, 13, 21, 32, 44, 49, 50, 61, 69, 79, 90, 93, 120
107    };
108
109    /**
110     * Index = C Datensatz-Feld - 1 (erster Satzabschnitt),
111     * Wert = Länge des Feldes in Byte.
112     */
113    protected static final int[] CRECORD_LENGTH1 =
114    {
115        4, 1, 8, 8, 10, 11, 5, 1, 11, 8, 10, 11, 3, 27, 8
116    };
117
118    /**
119     * Index = C Datensatz-Feld des zweiten Satzabschnittes - 1,
120     * Wert = Offset relativ zum zweiten Satzabschnitt.
121     */
122    protected static final int[] CRECORD_OFFSETS2 =
123    {
124        0, 27, 54, 55, 57, 59, 61, 88, 90, 117
125    };
126
127    /**
128     * Index = C Datensatz-Feld des zweiten Satzabschnittes - 1,
129     * Wert = Länge des Feldes in Byte.
130     */
131    protected static final int[] CRECORD_LENGTH2 =
132    {
133        27, 27, 1, 2, 2, 2, 27, 2, 27, 11
134    };
135
136    /**
137     * Index = C Datensatz-Feld des 3., 4., 5. und 6. Satzabschnittes - 1,
138     * Wert = Offset relativ zum Anfang des 3., 4., 5. und 6. Satzabschnittes.
139     */
140    protected static final int[] CRECORD_OFFSETS_EXT =
141    {
142        0, 2, 29, 31, 58, 60, 87, 89, 116
143    };
144
145    /**
146     * Index = C Datensatz-Feld des 3., 4., 5. und 6. Satzabschnittes - 1,
147     * Wert = Länge des Feldes in Byte.
148     */
149    protected static final int[] CRECORD_LENGTH_EXT =
150    {
151        2, 27, 2, 27, 2, 27, 2, 27, 12
152    };
153
154    /**
155     * Index = Anzahl Erweiterungsteile,
156     * Wert = Anzahl benötigter Satzabschnitte.
157     */
158    protected static final int[] CRECORD_EXTENSIONCOUNT_TO_BLOCKCOUNT =
159    {
160        2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6
161    };
162
163    /**
164     * Index = Index Erweiterungsteil,
165     * Wert = Satzabschnitt-Offset zu Transaktionsbeginn.
166     */
167    protected static final int[] CRECORD_EXTINDEX_TO_BLOCKOFFSET =
168    {
169        1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5
170    };
171
172    /**
173     * Index = Index Erweiterungsteil,
174     * Wert = Anfangsposition des Erweiterungsteils relativ zum Anfang des Satzabschnittes.
175     */
176    protected static final int[] CRECORD_EXTINDEX_TO_TYPEOFFSET =
177    {
178        CRECORD_OFFSETS2[5], CRECORD_OFFSETS2[7], CRECORD_OFFSETS_EXT[0], CRECORD_OFFSETS_EXT[2],
179        CRECORD_OFFSETS_EXT[4], CRECORD_OFFSETS_EXT[6], CRECORD_OFFSETS_EXT[0], CRECORD_OFFSETS_EXT[2],
180        CRECORD_OFFSETS_EXT[4], CRECORD_OFFSETS_EXT[6], CRECORD_OFFSETS_EXT[0], CRECORD_OFFSETS_EXT[2],
181        CRECORD_OFFSETS_EXT[4], CRECORD_OFFSETS_EXT[6], CRECORD_OFFSETS_EXT[0], CRECORD_OFFSETS_EXT[2],
182        CRECORD_OFFSETS_EXT[4], CRECORD_OFFSETS_EXT[6]
183    };
184
185    /**
186     * Index = Index Erweiterungsteil,
187     * Wert = Anfangsposition des Erweiterungsteils relativ zum Anfang des Satzabschnittes.
188     */
189    protected static final int[] CRECORD_EXTINDEX_TO_TYPELENGTH =
190    {
191        CRECORD_LENGTH2[5], CRECORD_LENGTH2[7], CRECORD_LENGTH_EXT[0], CRECORD_LENGTH_EXT[2],
192        CRECORD_LENGTH_EXT[4], CRECORD_LENGTH_EXT[6], CRECORD_LENGTH_EXT[0], CRECORD_LENGTH_EXT[2],
193        CRECORD_LENGTH_EXT[4], CRECORD_LENGTH_EXT[6], CRECORD_LENGTH_EXT[0], CRECORD_LENGTH_EXT[2],
194        CRECORD_LENGTH_EXT[4], CRECORD_LENGTH_EXT[6], CRECORD_LENGTH_EXT[0], CRECORD_LENGTH_EXT[2],
195        CRECORD_LENGTH_EXT[4], CRECORD_LENGTH_EXT[6]
196    };
197
198    /**
199     * Index = Index Erweiterungsteil,
200     * Wert = Anfangsposition des Erweiterungsteils relativ zum Anfang des Satzabschnittes.
201     */
202    protected static final int[] CRECORD_EXTINDEX_TO_VALUEOFFSET =
203    {
204        CRECORD_OFFSETS2[6], CRECORD_OFFSETS2[8], CRECORD_OFFSETS_EXT[1], CRECORD_OFFSETS_EXT[3],
205        CRECORD_OFFSETS_EXT[5], CRECORD_OFFSETS_EXT[7], CRECORD_OFFSETS_EXT[1], CRECORD_OFFSETS_EXT[3],
206        CRECORD_OFFSETS_EXT[5], CRECORD_OFFSETS_EXT[7], CRECORD_OFFSETS_EXT[1], CRECORD_OFFSETS_EXT[3],
207        CRECORD_OFFSETS_EXT[5], CRECORD_OFFSETS_EXT[7], CRECORD_OFFSETS_EXT[1], CRECORD_OFFSETS_EXT[3],
208        CRECORD_OFFSETS_EXT[5], CRECORD_OFFSETS_EXT[7]
209    };
210
211    /**
212     * Index = Index Erweiterungsteil,
213     * Wert = Anfangsposition des Erweiterungsteils relativ zum Anfang des Satzabschnittes.
214     */
215    protected static final int[] CRECORD_EXTINDEX_TO_VALUELENGTH =
216    {
217        CRECORD_LENGTH2[6], CRECORD_LENGTH2[8], CRECORD_LENGTH_EXT[1], CRECORD_LENGTH_EXT[3],
218        CRECORD_LENGTH_EXT[5], CRECORD_LENGTH_EXT[7], CRECORD_LENGTH_EXT[1], CRECORD_LENGTH_EXT[3],
219        CRECORD_LENGTH_EXT[5], CRECORD_LENGTH_EXT[7], CRECORD_LENGTH_EXT[1], CRECORD_LENGTH_EXT[3],
220        CRECORD_LENGTH_EXT[5], CRECORD_LENGTH_EXT[7], CRECORD_LENGTH_EXT[1], CRECORD_LENGTH_EXT[3],
221        CRECORD_LENGTH_EXT[5], CRECORD_LENGTH_EXT[7]
222    };
223
224    /**
225     * Index = Index Erweiterungsteil,
226     * Wert = Anzahl der folgenden Erweiterungsteile im selben Satzabschnitt.
227     */
228    protected static final int[] CRECORD_EXTINDEX_TO_FOLLOWINGEXTENSIONS =
229    {
230        1, 0, 3, 2, 1, 0, 3, 2, 1, 0, 3, 2, 1, 0, 3, 2, 1, 0
231    };
232
233    /**
234     * Index = Index Erweiterungsteil,
235     * Wert = Feld-Konstante für das Typen-Feld des Erweiterungsteils.
236     */
237    protected static final int[] CRECORD_EXTINDEX_TO_TYPEFIELD =
238    {
239        Fields.FIELD_C19, Fields.FIELD_C21, Fields.FIELD_C24, Fields.FIELD_C26, Fields.FIELD_C28, Fields.FIELD_C30,
240        Fields.FIELD_C33, Fields.FIELD_C35, Fields.FIELD_C37, Fields.FIELD_C39, Fields.FIELD_C42, Fields.FIELD_C44,
241        Fields.FIELD_C46, Fields.FIELD_C48, Fields.FIELD_C51, Fields.FIELD_C53, Fields.FIELD_C55, Fields.FIELD_C57,
242        Fields.FIELD_C59
243    };
244
245    /**
246     * Index = Index Erweiterungsteil,
247     * Wert = Feld-Konstante für das Werte-Feld des Erweiterungsteils.
248     */
249    protected static final int[] CRECORD_EXTINDEX_TO_VALUEFIELD =
250    {
251        Fields.FIELD_C20, Fields.FIELD_C22, Fields.FIELD_C25, Fields.FIELD_C27, Fields.FIELD_C29, Fields.FIELD_C31,
252        Fields.FIELD_C34, Fields.FIELD_C36, Fields.FIELD_C38, Fields.FIELD_C40, Fields.FIELD_C43, Fields.FIELD_C45,
253        Fields.FIELD_C47, Fields.FIELD_C49, Fields.FIELD_C52, Fields.FIELD_C54, Fields.FIELD_C56, Fields.FIELD_C58
254    };
255
256    /** Erzeugt eine neue {@code DTAUSDisk} Instanz. */
257    public DTAUSDisk()
258    {
259        super();
260    }
261
262    protected char getBlockType( final long position ) throws IOException
263    {
264        // Feld 2
265        final AlphaNumericText27 txt = this.readAlphaNumeric(
266            Fields.FIELD_A2, position + ARECORD_OFFSETS[1], ARECORD_LENGTH[1], ENCODING_ASCII );
267
268        char ret = '?';
269
270        if ( txt != null )
271        {
272            if ( txt.length() != 1 )
273            {
274                if ( ThreadLocalMessages.isErrorsEnabled() )
275                {
276                    throw new CorruptedException( this.getImplementation(), position + ARECORD_OFFSETS[1] );
277                }
278                else
279                {
280                    final Message msg = new IllegalDataMessage(
281                        Fields.FIELD_A2, IllegalDataMessage.TYPE_CONSTANT, position + ARECORD_OFFSETS[1],
282                        txt.format() );
283
284                    ThreadLocalMessages.getMessages().addMessage( msg );
285                }
286            }
287            else
288            {
289                ret = txt.charAt( 0 );
290            }
291        }
292
293        return ret;
294    }
295
296    protected Header readHeader() throws IOException
297    {
298        Long num;
299        AlphaNumericText27 txt;
300        final Header ret = new Header();
301
302        // Feld 1
303        num = this.readNumber(
304            Fields.FIELD_A1, this.getHeaderPosition() + ARECORD_OFFSETS[0], ARECORD_LENGTH[0], ENCODING_ASCII );
305
306        if ( num.longValue() != NO_NUMBER && num.intValue() != this.getBlockSize() )
307        {
308            if ( ThreadLocalMessages.isErrorsEnabled() )
309            {
310                throw new CorruptedException( this.getImplementation(), this.getHeaderPosition() + ARECORD_OFFSETS[0] );
311            }
312            else
313            {
314                final Message msg = new IllegalDataMessage(
315                    Fields.FIELD_A1, IllegalDataMessage.TYPE_CONSTANT, this.getHeaderPosition() + ARECORD_OFFSETS[0],
316                    num.toString() );
317
318                ThreadLocalMessages.getMessages().addMessage( msg );
319            }
320        }
321
322        // Feld 2
323        txt = this.readAlphaNumeric(
324            Fields.FIELD_A2, this.getHeaderPosition() + ARECORD_OFFSETS[1], ARECORD_LENGTH[1], ENCODING_ASCII );
325
326        if ( txt != null && ( txt.length() != 1 || txt.charAt( 0 ) != 'A' ) )
327        {
328            if ( ThreadLocalMessages.isErrorsEnabled() )
329            {
330                throw new CorruptedException( this.getImplementation(), this.getHeaderPosition() + ARECORD_OFFSETS[1] );
331            }
332            else
333            {
334                final Message msg = new IllegalDataMessage(
335                    Fields.FIELD_A2, IllegalDataMessage.TYPE_CONSTANT, this.getHeaderPosition() + ARECORD_OFFSETS[1],
336                    txt.format() );
337
338                ThreadLocalMessages.getMessages().addMessage( msg );
339            }
340        }
341
342        // Feld 3
343        txt = this.readAlphaNumeric(
344            Fields.FIELD_A3, this.getHeaderPosition() + ARECORD_OFFSETS[2], ARECORD_LENGTH[2], ENCODING_ASCII );
345
346        ret.setType( null );
347        if ( txt != null )
348        {
349            final LogicalFileType label = LogicalFileType.valueOf( txt.format() );
350
351            if ( label == null )
352            {
353                if ( ThreadLocalMessages.isErrorsEnabled() )
354                {
355                    throw new CorruptedException(
356                        this.getImplementation(), this.getHeaderPosition() + ARECORD_OFFSETS[2] );
357
358                }
359                else
360                {
361                    final Message msg = new IllegalDataMessage(
362                        Fields.FIELD_A3, IllegalDataMessage.TYPE_FILETYPE, this.getHeaderPosition() + ARECORD_OFFSETS[2],
363                        txt.format() );
364
365                    ThreadLocalMessages.getMessages().addMessage( msg );
366                }
367            }
368            else
369            {
370                ret.setType( label );
371            }
372        }
373
374        // Feld 4
375        num = this.readNumber(
376            Fields.FIELD_A4, this.getHeaderPosition() + ARECORD_OFFSETS[3], ARECORD_LENGTH[3], ENCODING_ASCII );
377
378        ret.setBank( null );
379        if ( num.longValue() != NO_NUMBER )
380        {
381            if ( !Bankleitzahl.checkBankleitzahl( num ) )
382            {
383                if ( ThreadLocalMessages.isErrorsEnabled() )
384                {
385                    throw new CorruptedException(
386                        this.getImplementation(), this.getHeaderPosition() + ARECORD_OFFSETS[3] );
387
388                }
389                else
390                {
391                    final Message msg = new IllegalDataMessage(
392                        Fields.FIELD_A4, IllegalDataMessage.TYPE_BANKLEITZAHL,
393                        this.getHeaderPosition() + ARECORD_OFFSETS[3], num.toString() );
394
395                    ThreadLocalMessages.getMessages().addMessage( msg );
396                }
397            }
398            else
399            {
400                ret.setBank( Bankleitzahl.valueOf( num ) );
401            }
402        }
403
404        // Feld 5
405        // Nur belegt wenn Absender Kreditinistitut ist, sonst 0.
406        num = this.readNumber(
407            Fields.FIELD_A5, this.getHeaderPosition() + ARECORD_OFFSETS[4], ARECORD_LENGTH[4], ENCODING_ASCII );
408
409        ret.setBankData( null );
410        if ( num.longValue() != NO_NUMBER && ret.getType() != null && ret.getType().isSendByBank() )
411        {
412            if ( !Bankleitzahl.checkBankleitzahl( num ) )
413            {
414                if ( ThreadLocalMessages.isErrorsEnabled() )
415                {
416                    throw new CorruptedException(
417                        this.getImplementation(), this.getHeaderPosition() + ARECORD_OFFSETS[4] );
418
419                }
420                else
421                {
422                    final Message msg = new IllegalDataMessage(
423                        Fields.FIELD_A5, IllegalDataMessage.TYPE_BANKLEITZAHL,
424                        this.getHeaderPosition() + ARECORD_OFFSETS[4], num.toString() );
425
426                    ThreadLocalMessages.getMessages().addMessage( msg );
427                }
428            }
429            else
430            {
431                ret.setBankData( Bankleitzahl.valueOf( num ) );
432            }
433        }
434
435        // Feld 6
436        txt = this.readAlphaNumeric(
437            Fields.FIELD_A6, this.getHeaderPosition() + ARECORD_OFFSETS[5], ARECORD_LENGTH[5], ENCODING_ASCII );
438
439        ret.setCustomer( txt );
440
441        // Feld 7
442        final Date createDate = this.readShortDate(
443            Fields.FIELD_A7, this.getHeaderPosition() + ARECORD_OFFSETS[6], ENCODING_ASCII );
444
445        if ( createDate == null )
446        {
447            if ( ThreadLocalMessages.isErrorsEnabled() )
448            {
449                throw new CorruptedException( this.getImplementation(), this.getHeaderPosition() + ARECORD_OFFSETS[6] );
450            }
451            else
452            {
453                ThreadLocalMessages.getMessages().addMessage( new IllegalDataMessage(
454                    Fields.FIELD_A7, IllegalDataMessage.TYPE_SHORTDATE, this.getHeaderPosition() + ARECORD_OFFSETS[6],
455                    "      " ) );
456
457            }
458        }
459
460        // Feld 8
461        // Nur belegt wenn Absender Kreditinistitut ist, sonst "".
462        txt = this.readAlphaNumeric(
463            Fields.FIELD_A8, this.getHeaderPosition() + ARECORD_OFFSETS[7], ARECORD_LENGTH[7], ENCODING_ASCII );
464
465        // Feld 9
466        num = this.readNumber(
467            Fields.FIELD_A9, this.getHeaderPosition() + ARECORD_OFFSETS[8], ARECORD_LENGTH[8], ENCODING_ASCII );
468
469        ret.setAccount( null );
470        if ( num.longValue() != NO_NUMBER )
471        {
472            if ( !Kontonummer.checkKontonummer( num ) )
473            {
474                if ( ThreadLocalMessages.isErrorsEnabled() )
475                {
476                    throw new CorruptedException(
477                        this.getImplementation(), this.getHeaderPosition() + ARECORD_OFFSETS[8] );
478
479                }
480                else
481                {
482                    final Message msg = new IllegalDataMessage(
483                        Fields.FIELD_A9, IllegalDataMessage.TYPE_KONTONUMMER,
484                        this.getHeaderPosition() + ARECORD_OFFSETS[8], num.toString() );
485
486                    ThreadLocalMessages.getMessages().addMessage( msg );
487                }
488            }
489            else
490            {
491                ret.setAccount( Kontonummer.valueOf( num ) );
492            }
493        }
494
495        // Feld 10
496        num = this.readNumber(
497            Fields.FIELD_A10, this.getHeaderPosition() + ARECORD_OFFSETS[9], ARECORD_LENGTH[9], ENCODING_ASCII );
498
499        ret.setReference( null );
500        if ( num.longValue() != NO_NUMBER )
501        {
502            if ( !Referenznummer10.checkReferenznummer10( num ) )
503            {
504                if ( ThreadLocalMessages.isErrorsEnabled() )
505                {
506                    throw new CorruptedException(
507                        this.getImplementation(), this.getHeaderPosition() + ARECORD_OFFSETS[9] );
508
509                }
510                else
511                {
512                    final Message msg = new IllegalDataMessage(
513                        Fields.FIELD_A10, IllegalDataMessage.TYPE_REFERENZNUMMER,
514                        this.getHeaderPosition() + ARECORD_OFFSETS[9], num.toString() );
515
516                    ThreadLocalMessages.getMessages().addMessage( msg );
517                }
518            }
519            else
520            {
521                ret.setReference( Referenznummer10.valueOf( num ) );
522            }
523        }
524
525        // Feld 11b
526        final Date executionDate = this.readLongDate(
527            Fields.FIELD_A11B, this.getHeaderPosition() + ARECORD_OFFSETS[11], ENCODING_ASCII );
528
529        ret.setCreateDate( createDate );
530        ret.setExecutionDate( executionDate );
531
532        ret.setCurrency( null );
533        if ( createDate != null )
534        {
535            // Feld 12
536            txt = this.readAlphaNumeric(
537                Fields.FIELD_A12, this.getHeaderPosition() + ARECORD_OFFSETS[13], ARECORD_LENGTH[13], ENCODING_ASCII );
538
539            if ( txt != null )
540            {
541                if ( txt.length() != 1 )
542                {
543                    if ( ThreadLocalMessages.isErrorsEnabled() )
544                    {
545                        throw new CorruptedException(
546                            this.getImplementation(), this.getHeaderPosition() + ARECORD_OFFSETS[13] );
547
548                    }
549                    else
550                    {
551                        final Message msg = new IllegalDataMessage(
552                            Fields.FIELD_A12, IllegalDataMessage.TYPE_CURRENCY,
553                            this.getHeaderPosition() + ARECORD_OFFSETS[13], txt.format() );
554
555                        ThreadLocalMessages.getMessages().addMessage( msg );
556                    }
557                }
558                else
559                {
560                    final char c = txt.charAt( 0 );
561                    final Currency cur = this.getCurrencyMapper().getDtausCurrency( c, createDate );
562
563                    if ( cur == null )
564                    {
565                        if ( ThreadLocalMessages.isErrorsEnabled() )
566                        {
567                            throw new CorruptedException(
568                                this.getImplementation(), this.getHeaderPosition() + ARECORD_OFFSETS[13] );
569
570                        }
571                        else
572                        {
573                            final Message msg = new IllegalDataMessage(
574                                Fields.FIELD_A12, IllegalDataMessage.TYPE_CURRENCY,
575                                this.getHeaderPosition() + ARECORD_OFFSETS[13], txt.format() );
576
577                            ThreadLocalMessages.getMessages().addMessage( msg );
578                        }
579                    }
580
581                    ret.setCurrency( cur );
582                }
583            }
584        }
585
586        return ret;
587    }
588
589    protected void writeHeader( final Header header ) throws IOException
590    {
591        final LogicalFileType label = header.getType();
592
593        // Feld 1
594        this.writeNumber(
595            Fields.FIELD_A1, this.getHeaderPosition() + ARECORD_OFFSETS[0], ARECORD_LENGTH[0], this.getBlockSize(),
596            ENCODING_ASCII );
597
598        // Feld 2
599        this.writeAlphaNumeric(
600            Fields.FIELD_A2, this.getHeaderPosition() + ARECORD_OFFSETS[1], ARECORD_LENGTH[1], "A", ENCODING_ASCII );
601
602        // Feld 3
603        this.writeAlphaNumeric(
604            Fields.FIELD_A3, this.getHeaderPosition() + ARECORD_OFFSETS[2], ARECORD_LENGTH[2], label.getCode(),
605            ENCODING_ASCII );
606
607        // Feld 4
608        this.writeNumber(
609            Fields.FIELD_A4, this.getHeaderPosition() + ARECORD_OFFSETS[3], ARECORD_LENGTH[3],
610            header.getBank().intValue(), ENCODING_ASCII );
611
612        // Feld 5
613        this.writeNumber(
614            Fields.FIELD_A5, this.getHeaderPosition() + ARECORD_OFFSETS[4],
615            ARECORD_LENGTH[4], ( label.isSendByBank() && header.getBankData() != null
616                                 ? header.getBankData().intValue() : 0 ), ENCODING_ASCII );
617
618        // Feld 6
619        this.writeAlphaNumeric(
620            Fields.FIELD_A6, this.getHeaderPosition() + ARECORD_OFFSETS[5], ARECORD_LENGTH[5],
621            header.getCustomer().format(), ENCODING_ASCII );
622
623        // Feld 7
624        this.writeShortDate(
625            Fields.FIELD_A7, this.getHeaderPosition() + ARECORD_OFFSETS[6], header.getCreateDate(), ENCODING_ASCII );
626
627        // Feld 8
628        this.writeAlphaNumeric(
629            Fields.FIELD_A8, this.getHeaderPosition() + ARECORD_OFFSETS[7], ARECORD_LENGTH[7], "", ENCODING_ASCII );
630
631        // Feld 9
632        this.writeNumber(
633            Fields.FIELD_A9, this.getHeaderPosition() + ARECORD_OFFSETS[8], ARECORD_LENGTH[8],
634            header.getAccount().longValue(), ENCODING_ASCII );
635
636        // Feld 10
637        this.writeNumber(
638            Fields.FIELD_A10, this.getHeaderPosition() + ARECORD_OFFSETS[9], ARECORD_LENGTH[9],
639            ( header.getReference() != null ? header.getReference().longValue() : 0L ), ENCODING_ASCII );
640
641        // Feld 11a
642        this.writeAlphaNumeric(
643            Fields.FIELD_A11A, this.getHeaderPosition() + ARECORD_OFFSETS[10], ARECORD_LENGTH[10], "", ENCODING_ASCII );
644
645        // Feld 11b
646        this.writeLongDate(
647            Fields.FIELD_A11B, this.getHeaderPosition() + ARECORD_OFFSETS[11], header.getExecutionDate(),
648            ENCODING_ASCII );
649
650        // Feld 11c
651        this.writeAlphaNumeric(
652            Fields.FIELD_A11C, this.getHeaderPosition() + ARECORD_OFFSETS[12], ARECORD_LENGTH[12], "", ENCODING_ASCII );
653
654        // Feld 12
655        this.writeAlphaNumeric(
656            Fields.FIELD_A12, this.getHeaderPosition() + ARECORD_OFFSETS[13], ARECORD_LENGTH[13],
657            Character.toString( this.getCurrencyMapper().getDtausCode( header.getCurrency(), header.getCreateDate() ) ),
658            ENCODING_ASCII );
659
660    }
661
662    protected Checksum readChecksum() throws IOException
663    {
664        Long num;
665        final AlphaNumericText27 txt;
666        final Checksum checksum;
667        checksum = new Checksum();
668
669        // Feld 1
670        num = this.readNumber(
671            Fields.FIELD_E1, this.getChecksumPosition() + ERECORD_OFFSETS[0], ERECORD_LENGTH[0], ENCODING_ASCII );
672
673        if ( num.longValue() != NO_NUMBER && num.intValue() != this.getBlockSize() )
674        {
675            if ( ThreadLocalMessages.isErrorsEnabled() )
676            {
677                throw new CorruptedException(
678                    this.getImplementation(), this.getChecksumPosition() + ERECORD_OFFSETS[0] );
679
680            }
681            else
682            {
683                final Message msg = new IllegalDataMessage(
684                    Fields.FIELD_E1, IllegalDataMessage.TYPE_CONSTANT, this.getChecksumPosition() + ERECORD_OFFSETS[0],
685                    num.toString() );
686
687                ThreadLocalMessages.getMessages().addMessage( msg );
688            }
689        }
690
691        // Feld 2
692        txt = this.readAlphaNumeric(
693            Fields.FIELD_E2, this.getChecksumPosition() + ERECORD_OFFSETS[1], ERECORD_LENGTH[1], ENCODING_ASCII );
694
695        if ( txt != null && ( txt.length() != 1 || txt.charAt( 0 ) != 'E' ) )
696        {
697            if ( ThreadLocalMessages.isErrorsEnabled() )
698            {
699                throw new CorruptedException(
700                    this.getImplementation(), this.getChecksumPosition() + ERECORD_OFFSETS[1] );
701
702            }
703            else
704            {
705                final Message msg = new IllegalDataMessage(
706                    Fields.FIELD_E2, IllegalDataMessage.TYPE_CONSTANT, this.getChecksumPosition() + ERECORD_OFFSETS[1],
707                    txt.format() );
708
709                ThreadLocalMessages.getMessages().addMessage( msg );
710            }
711        }
712
713        // Feld 4
714        num = this.readNumber(
715            Fields.FIELD_E4, this.getChecksumPosition() + ERECORD_OFFSETS[3], ERECORD_LENGTH[3], ENCODING_ASCII );
716
717        if ( num.longValue() != NO_NUMBER )
718        {
719            checksum.setTransactionCount( num.intValue() );
720        }
721
722        // Feld 6
723        num = this.readNumber(
724            Fields.FIELD_E6, this.getChecksumPosition() + ERECORD_OFFSETS[5], ERECORD_LENGTH[5], ENCODING_ASCII );
725
726        if ( num.longValue() != NO_NUMBER )
727        {
728            checksum.setSumTargetAccount( num.longValue() );
729        }
730
731        // Feld 7
732        num = this.readNumber(
733            Fields.FIELD_E7, this.getChecksumPosition() + ERECORD_OFFSETS[6], ERECORD_LENGTH[6], ENCODING_ASCII );
734
735        if ( num.longValue() != NO_NUMBER )
736        {
737            checksum.setSumTargetBank( num.longValue() );
738        }
739
740        // Feld 8
741        num = this.readNumber(
742            Fields.FIELD_E8, this.getChecksumPosition() + ERECORD_OFFSETS[7], ERECORD_LENGTH[7], ENCODING_ASCII );
743
744        if ( num.longValue() != NO_NUMBER )
745        {
746            checksum.setSumAmount( num.longValue() );
747        }
748
749        return checksum;
750    }
751
752    protected void writeChecksum( final Checksum checksum ) throws IOException
753    {
754        // Feld 1
755        this.writeNumber(
756            Fields.FIELD_E1, this.getChecksumPosition() + ERECORD_OFFSETS[0], ERECORD_LENGTH[0], this.getBlockSize(),
757            ENCODING_ASCII );
758
759        // Feld 2
760        this.writeAlphaNumeric(
761            Fields.FIELD_E2, this.getChecksumPosition() + ERECORD_OFFSETS[1], ERECORD_LENGTH[1], "E", ENCODING_ASCII );
762
763        // Feld 3
764        this.writeAlphaNumeric(
765            Fields.FIELD_E3, this.getChecksumPosition() + ERECORD_OFFSETS[2], ERECORD_LENGTH[2], "", ENCODING_ASCII );
766
767        // Feld 4
768        this.writeNumber(
769            Fields.FIELD_E4, this.getChecksumPosition() + ERECORD_OFFSETS[3], ERECORD_LENGTH[3],
770            checksum.getTransactionCount(), ENCODING_ASCII );
771
772        // Feld 5
773        this.writeNumber(
774            Fields.FIELD_E5, this.getChecksumPosition() + ERECORD_OFFSETS[4], ERECORD_LENGTH[4], 0L, ENCODING_ASCII );
775
776        // Feld 6
777        this.writeNumber(
778            Fields.FIELD_E6, this.getChecksumPosition() + ERECORD_OFFSETS[5], ERECORD_LENGTH[5],
779            checksum.getSumTargetAccount(), ENCODING_ASCII );
780
781        // Feld 7
782        this.writeNumber(
783            Fields.FIELD_E7, this.getChecksumPosition() + ERECORD_OFFSETS[6], ERECORD_LENGTH[6],
784            checksum.getSumTargetBank(), ENCODING_ASCII );
785
786        // Feld 8
787        this.writeNumber(
788            Fields.FIELD_E8, this.getChecksumPosition() + ERECORD_OFFSETS[7], ERECORD_LENGTH[7],
789            checksum.getSumAmount(), ENCODING_ASCII );
790
791        // Feld 9
792        this.writeAlphaNumeric(
793            Fields.FIELD_E9, this.getChecksumPosition() + ERECORD_OFFSETS[8], ERECORD_LENGTH[8], "", ENCODING_ASCII );
794
795    }
796
797    protected Transaction readTransaction( final long position,
798                                           final Transaction transaction )
799        throws IOException
800    {
801        Long num;
802        AlphaNumericText27 txt;
803        final List desc = new ArrayList( 14 );
804
805        transaction.setExecutiveExt( null );
806        transaction.setTargetExt( null );
807
808        final long extCount = this.readNumber(
809            Fields.FIELD_C18, position + this.getBlockSize() + CRECORD_OFFSETS2[4], CRECORD_LENGTH2[4],
810            ENCODING_ASCII ).longValue();
811
812        if ( extCount != NO_NUMBER && extCount > this.getMaximumExtensionCount() )
813        {
814            if ( ThreadLocalMessages.isErrorsEnabled() )
815            {
816                throw new CorruptedException( this.getImplementation(),
817                                              position + this.getBlockSize() + CRECORD_OFFSETS2[4] );
818
819            }
820            else
821            {
822                final Message msg = new IllegalDataMessage(
823                    Fields.FIELD_C18, IllegalDataMessage.TYPE_CONSTANT,
824                    position + this.getBlockSize() + CRECORD_OFFSETS2[4], Long.toString( extCount ) );
825
826                ThreadLocalMessages.getMessages().addMessage( msg );
827            }
828        }
829
830        // Konstanter Teil - Satzaschnitt 1 - Feld 1
831        num = this.readNumber(
832            Fields.FIELD_C1, position + CRECORD_OFFSETS1[0], CRECORD_LENGTH1[0], ENCODING_ASCII );
833
834        if ( num.longValue() != NO_NUMBER && extCount != NO_NUMBER
835             && num.intValue() != CRECORD_CONST_LENGTH + extCount * CRECORD_EXT_LENGTH )
836        {
837            if ( ThreadLocalMessages.isErrorsEnabled() )
838            {
839                throw new CorruptedException( this.getImplementation(), position + CRECORD_OFFSETS1[0] );
840            }
841            else
842            {
843                final Message msg = new IllegalDataMessage(
844                    Fields.FIELD_C1, IllegalDataMessage.TYPE_NUMERIC, position + CRECORD_OFFSETS1[0], num.toString() );
845
846                ThreadLocalMessages.getMessages().addMessage( msg );
847            }
848        }
849
850        // Konstanter Teil - Satzaschnitt 1 - Feld 2
851        txt = this.readAlphaNumeric(
852            Fields.FIELD_C2, position + CRECORD_OFFSETS1[1], CRECORD_LENGTH1[1], ENCODING_ASCII );
853
854        if ( txt != null && ( txt.length() != 1 || txt.charAt( 0 ) != 'C' ) )
855        {
856            if ( ThreadLocalMessages.isErrorsEnabled() )
857            {
858                throw new CorruptedException( this.getImplementation(), position + CRECORD_OFFSETS1[1] );
859            }
860            else
861            {
862                final Message msg = new IllegalDataMessage(
863                    Fields.FIELD_C2, IllegalDataMessage.TYPE_CONSTANT, position + CRECORD_OFFSETS1[1], txt.format() );
864
865                ThreadLocalMessages.getMessages().addMessage( msg );
866            }
867        }
868
869        // Konstanter Teil - Satzaschnitt 1 - Feld 3
870        num = this.readNumber( Fields.FIELD_C3, position + CRECORD_OFFSETS1[2], CRECORD_LENGTH1[2], ENCODING_ASCII );
871
872        transaction.setPrimaryBank( null );
873        if ( num.longValue() != NO_NUMBER && num.longValue() != 0L )
874        {
875            if ( !Bankleitzahl.checkBankleitzahl( num ) )
876            {
877                if ( ThreadLocalMessages.isErrorsEnabled() )
878                {
879                    throw new CorruptedException(
880                        this.getImplementation(), position + CRECORD_OFFSETS1[2] );
881
882                }
883                else
884                {
885                    final Message msg = new IllegalDataMessage(
886                        Fields.FIELD_C3, IllegalDataMessage.TYPE_BANKLEITZAHL, position + CRECORD_OFFSETS1[2],
887                        num.toString() );
888
889                    ThreadLocalMessages.getMessages().addMessage( msg );
890                }
891            }
892            else
893            {
894                transaction.setPrimaryBank( Bankleitzahl.valueOf( num ) );
895            }
896        }
897
898        // Konstanter Teil - Satzaschnitt 1 - Feld 4
899        num = this.readNumber(
900            Fields.FIELD_C4, position + CRECORD_OFFSETS1[3], CRECORD_LENGTH1[3], ENCODING_ASCII );
901
902        transaction.setTargetBank( null );
903        if ( num.longValue() != NO_NUMBER )
904        {
905            if ( !Bankleitzahl.checkBankleitzahl( num ) )
906            {
907                if ( ThreadLocalMessages.isErrorsEnabled() )
908                {
909                    throw new CorruptedException( this.getImplementation(), position + CRECORD_OFFSETS1[3] );
910                }
911                else
912                {
913                    final Message msg = new IllegalDataMessage(
914                        Fields.FIELD_C4, IllegalDataMessage.TYPE_BANKLEITZAHL, position + CRECORD_OFFSETS1[3],
915                        num.toString() );
916
917                    ThreadLocalMessages.getMessages().addMessage( msg );
918                }
919            }
920            else
921            {
922                transaction.setTargetBank( Bankleitzahl.valueOf( num ) );
923            }
924        }
925
926        // Konstanter Teil - Satzaschnitt 1 - Feld 5
927        num = this.readNumber(
928            Fields.FIELD_C5, position + CRECORD_OFFSETS1[4], CRECORD_LENGTH1[4], ENCODING_ASCII );
929
930        transaction.setTargetAccount( null );
931        if ( num.longValue() != NO_NUMBER )
932        {
933            if ( !Kontonummer.checkKontonummer( num ) )
934            {
935                if ( ThreadLocalMessages.isErrorsEnabled() )
936                {
937                    throw new CorruptedException( this.getImplementation(), position + CRECORD_OFFSETS1[4] );
938                }
939                else
940                {
941                    final Message msg = new IllegalDataMessage(
942                        Fields.FIELD_C5, IllegalDataMessage.TYPE_KONTONUMMER, position + CRECORD_OFFSETS1[4],
943                        num.toString() );
944
945                    ThreadLocalMessages.getMessages().addMessage( msg );
946                }
947            }
948            else
949            {
950                transaction.setTargetAccount( Kontonummer.valueOf( num ) );
951            }
952        }
953
954        // Konstanter Teil - Satzaschnitt 1 - Feld 6
955        num = this.readNumber(
956            Fields.FIELD_C6, position + CRECORD_OFFSETS1[5], CRECORD_LENGTH1[5], ENCODING_ASCII );
957
958        transaction.setReference( null );
959        if ( num.longValue() != NO_NUMBER )
960        {
961            if ( !Referenznummer11.checkReferenznummer11( num ) )
962            {
963                if ( ThreadLocalMessages.isErrorsEnabled() )
964                {
965                    throw new CorruptedException( this.getImplementation(), position + CRECORD_OFFSETS1[5] );
966                }
967                else
968                {
969                    final Message msg = new IllegalDataMessage(
970                        Fields.FIELD_C6, IllegalDataMessage.TYPE_REFERENZNUMMER, position + CRECORD_OFFSETS1[5],
971                        num.toString() );
972
973                    ThreadLocalMessages.getMessages().addMessage( msg );
974                }
975            }
976            else
977            {
978                transaction.setReference( Referenznummer11.valueOf( num ) );
979            }
980        }
981
982        // Konstanter Teil - Satzaschnitt 1 - Felder 7a & 7b
983        final Long keyType = this.readNumber(
984            Fields.FIELD_C7A, position + CRECORD_OFFSETS1[6], 2, ENCODING_ASCII );
985
986        num = this.readNumber(
987            Fields.FIELD_C7B, position + CRECORD_OFFSETS1[6] + 2, CRECORD_LENGTH1[6] - 2, ENCODING_ASCII );
988
989        transaction.setType( null );
990
991        if ( keyType.longValue() != NO_NUMBER && num.longValue() != NO_NUMBER
992             && this.getHeader().getCreateDate() != null )
993        {
994            final Textschluessel type = this.getTextschluesselVerzeichnis().getTextschluessel(
995                keyType.intValue(), num.intValue(), this.getHeader().getCreateDate() );
996
997            if ( type == null )
998            {
999                if ( ThreadLocalMessages.isErrorsEnabled() )
1000                {
1001                    throw new CorruptedException( this.getImplementation(), position + CRECORD_OFFSETS1[6] );
1002                }
1003                else
1004                {
1005                    final Message msg = new IllegalDataMessage(
1006                        Fields.FIELD_C7A, IllegalDataMessage.TYPE_TEXTSCHLUESSEL, position + CRECORD_OFFSETS1[6],
1007                        keyType.toString() + num.toString() );
1008
1009                    ThreadLocalMessages.getMessages().addMessage( msg );
1010                }
1011            }
1012            else
1013            {
1014                transaction.setType( type );
1015            }
1016        }
1017
1018        // Konstanter Teil - Satzaschnitt 1 - Feld 10
1019        num = this.readNumber( Fields.FIELD_C10, position + CRECORD_OFFSETS1[9], CRECORD_LENGTH1[9], ENCODING_ASCII );
1020
1021        transaction.setExecutiveBank( null );
1022        if ( num.longValue() != NO_NUMBER )
1023        {
1024            if ( !Bankleitzahl.checkBankleitzahl( num ) )
1025            {
1026                if ( ThreadLocalMessages.isErrorsEnabled() )
1027                {
1028                    throw new CorruptedException( this.getImplementation(), position + CRECORD_OFFSETS1[9] );
1029                }
1030                else
1031                {
1032                    final Message msg = new IllegalDataMessage(
1033                        Fields.FIELD_C10, IllegalDataMessage.TYPE_BANKLEITZAHL, position + CRECORD_OFFSETS1[9],
1034                        num.toString() );
1035
1036                    ThreadLocalMessages.getMessages().addMessage( msg );
1037                }
1038            }
1039            else
1040            {
1041                transaction.setExecutiveBank( Bankleitzahl.valueOf( num ) );
1042            }
1043        }
1044
1045        // Konstanter Teil - Satzaschnitt 1 - Feld 11
1046        num = this.readNumber(
1047            Fields.FIELD_C11, position + CRECORD_OFFSETS1[10], CRECORD_LENGTH1[10], ENCODING_ASCII );
1048
1049        transaction.setExecutiveAccount( null );
1050        if ( num.longValue() != NO_NUMBER )
1051        {
1052            if ( !Kontonummer.checkKontonummer( num ) )
1053            {
1054                if ( ThreadLocalMessages.isErrorsEnabled() )
1055                {
1056                    throw new CorruptedException( this.getImplementation(), position + CRECORD_OFFSETS1[10] );
1057                }
1058                else
1059                {
1060                    final Message msg = new IllegalDataMessage(
1061                        Fields.FIELD_C11, IllegalDataMessage.TYPE_KONTONUMMER, position + CRECORD_OFFSETS1[10],
1062                        num.toString() );
1063
1064                    ThreadLocalMessages.getMessages().addMessage( msg );
1065                }
1066            }
1067            else
1068            {
1069                transaction.setExecutiveAccount( Kontonummer.valueOf( num ) );
1070            }
1071        }
1072
1073        // Konstanter Teil - Satzaschnitt 1 - Feld 12
1074        num = this.readNumber(
1075            Fields.FIELD_C12, position + CRECORD_OFFSETS1[11], CRECORD_LENGTH1[11], ENCODING_ASCII );
1076
1077        transaction.setAmount(
1078            num.longValue() == NO_NUMBER
1079            ? null : BigInteger.valueOf( num.longValue() ) );
1080
1081        // Konstanter Teil - Satzaschnitt 1 - Feld 14a
1082        txt = this.readAlphaNumeric(
1083            Fields.FIELD_C14A, position + CRECORD_OFFSETS1[13], CRECORD_LENGTH1[13], ENCODING_ASCII );
1084
1085        transaction.setTargetName( txt );
1086
1087        // Konstanter Teil - Satzaschnitt 2 - Feld 15(1)
1088        txt = this.readAlphaNumeric(
1089            Fields.FIELD_C15, position + this.getBlockSize() + CRECORD_OFFSETS2[0], CRECORD_LENGTH2[0],
1090            ENCODING_ASCII );
1091
1092        transaction.setExecutiveName( txt );
1093
1094        // Konstanter Teil - Satzaschnitt 2 - Feld 16(2)
1095        txt = this.readAlphaNumeric(
1096            Fields.FIELD_C16, position + this.getBlockSize() + CRECORD_OFFSETS2[1], CRECORD_LENGTH2[1],
1097            ENCODING_ASCII );
1098
1099        if ( txt != null )
1100        {
1101            desc.add( txt );
1102        }
1103
1104        // Konstanter Teil - Satzaschnitt 2 - Feld 17a(3)
1105        txt = this.readAlphaNumeric(
1106            Fields.FIELD_C17A, position + this.getBlockSize() + CRECORD_OFFSETS2[2], CRECORD_LENGTH2[2],
1107            ENCODING_ASCII );
1108
1109        transaction.setCurrency( null );
1110
1111        if ( txt != null )
1112        {
1113            if ( txt.length() != 1 )
1114            {
1115                if ( ThreadLocalMessages.isErrorsEnabled() )
1116                {
1117                    throw new CorruptedException(
1118                        this.getImplementation(), position + this.getBlockSize() + CRECORD_OFFSETS1[10] );
1119
1120                }
1121                else
1122                {
1123                    final Message msg = new IllegalDataMessage(
1124                        Fields.FIELD_C17A, IllegalDataMessage.TYPE_CURRENCY,
1125                        position + this.getBlockSize() + CRECORD_OFFSETS1[10], txt.format() );
1126
1127                    ThreadLocalMessages.getMessages().addMessage( msg );
1128                }
1129            }
1130            else if ( this.getHeader().getCreateDate() != null )
1131            {
1132                final char c = txt.charAt( 0 );
1133                final Currency cur = this.getCurrencyMapper().getDtausCurrency( c, this.getHeader().getCreateDate() );
1134
1135                if ( cur == null )
1136                {
1137                    if ( ThreadLocalMessages.isErrorsEnabled() )
1138                    {
1139                        throw new CorruptedException(
1140                            this.getImplementation(), position + this.getBlockSize() + CRECORD_OFFSETS1[10] );
1141
1142                    }
1143                    else
1144                    {
1145                        final Message msg = new IllegalDataMessage(
1146                            Fields.FIELD_C17A, IllegalDataMessage.TYPE_CURRENCY,
1147                            position + this.getBlockSize() + CRECORD_OFFSETS1[10], txt.format() );
1148
1149                        ThreadLocalMessages.getMessages().addMessage( msg );
1150                    }
1151                }
1152
1153                transaction.setCurrency( cur );
1154            }
1155        }
1156
1157        //if(header.getLabel().isBank()) {
1158        // Konstanter Teil - Satzaschnitt 1 - Feld 8
1159        //    num = this.readNumber(block, DTAUSDisk.CRECORD_OFFSETS1[7],
1160        //        DTAUSDisk.CRECORD_LENGTH1[7]);
1161
1162        //    transaction.set
1163        //
1164        //}
1165
1166        // Erweiterungsteile des 2., 3., 4., 5. und 6. Satzabschnittes.
1167        for ( int i = 0; i < extCount && extCount != NO_NUMBER; i++ )
1168        {
1169            final long extPos = position + CRECORD_EXTINDEX_TO_BLOCKOFFSET[i] * this.getBlockSize();
1170
1171            num = this.readNumber(
1172                CRECORD_EXTINDEX_TO_TYPEFIELD[i], extPos + CRECORD_EXTINDEX_TO_TYPEOFFSET[i],
1173                CRECORD_EXTINDEX_TO_TYPELENGTH[i], ENCODING_ASCII );
1174
1175            txt = this.readAlphaNumeric(
1176                CRECORD_EXTINDEX_TO_VALUEFIELD[i], extPos + CRECORD_EXTINDEX_TO_VALUEOFFSET[i],
1177                CRECORD_EXTINDEX_TO_VALUELENGTH[i], ENCODING_ASCII );
1178
1179            if ( num.longValue() == 1L )
1180            {
1181                if ( transaction.getTargetExt() != null )
1182                {
1183                    if ( ThreadLocalMessages.isErrorsEnabled() )
1184                    {
1185                        throw new CorruptedException(
1186                            this.getImplementation(), extPos + CRECORD_EXTINDEX_TO_TYPEOFFSET[i] );
1187
1188                    }
1189                    else
1190                    {
1191                        final Message msg = new IllegalDataMessage(
1192                            CRECORD_EXTINDEX_TO_TYPEFIELD[i], IllegalDataMessage.TYPE_CONSTANT,
1193                            extPos + CRECORD_EXTINDEX_TO_TYPEOFFSET[i], num.toString() );
1194
1195                        ThreadLocalMessages.getMessages().addMessage( msg );
1196                    }
1197                }
1198                else
1199                {
1200                    transaction.setTargetExt( txt );
1201                }
1202            }
1203            else if ( num.longValue() == 2L )
1204            {
1205                if ( txt != null )
1206                {
1207                    desc.add( txt );
1208                }
1209            }
1210            else if ( num.longValue() == 3L )
1211            {
1212                if ( transaction.getExecutiveExt() != null )
1213                {
1214                    if ( ThreadLocalMessages.isErrorsEnabled() )
1215                    {
1216                        throw new CorruptedException(
1217                            this.getImplementation(), extPos + CRECORD_EXTINDEX_TO_TYPEOFFSET[i] );
1218
1219                    }
1220                    else
1221                    {
1222                        final Message msg = new IllegalDataMessage(
1223                            CRECORD_EXTINDEX_TO_TYPEFIELD[i], IllegalDataMessage.TYPE_CONSTANT,
1224                            extPos + CRECORD_EXTINDEX_TO_TYPEOFFSET[i], num.toString() );
1225
1226                        ThreadLocalMessages.getMessages().addMessage( msg );
1227                    }
1228                }
1229                else
1230                {
1231                    transaction.setExecutiveExt( txt );
1232                }
1233            }
1234            else if ( num.longValue() != NO_NUMBER )
1235            {
1236                if ( ThreadLocalMessages.isErrorsEnabled() )
1237                {
1238                    throw new CorruptedException(
1239                        this.getImplementation(), extPos + CRECORD_EXTINDEX_TO_TYPEOFFSET[i] );
1240
1241                }
1242                else
1243                {
1244                    final Message msg = new IllegalDataMessage(
1245                        CRECORD_EXTINDEX_TO_TYPEFIELD[i], IllegalDataMessage.TYPE_CONSTANT,
1246                        extPos + CRECORD_EXTINDEX_TO_TYPEOFFSET[i], num.toString() );
1247
1248                    ThreadLocalMessages.getMessages().addMessage( msg );
1249                }
1250            }
1251        }
1252
1253        transaction.setDescriptions( (AlphaNumericText27[]) desc.toArray( new AlphaNumericText27[ desc.size() ] ) );
1254        return transaction;
1255    }
1256
1257    protected void writeTransaction( final long position, final Transaction transaction ) throws IOException
1258    {
1259        AlphaNumericText27 txt;
1260        final AlphaNumericText27[] desc = transaction.getDescriptions();
1261        final Textschluessel type = transaction.getType();
1262        int extCount = desc.length > 0 ? desc.length - 1 : 0;
1263
1264        if ( transaction.getExecutiveExt() != null )
1265        {
1266            extCount++;
1267        }
1268
1269        if ( transaction.getTargetExt() != null )
1270        {
1271            extCount++;
1272        }
1273
1274        // Konstanter Teil - 1. Satzabschnitt - Feld 1
1275        this.writeNumber( Fields.FIELD_C1, position + CRECORD_OFFSETS1[0], CRECORD_LENGTH1[0],
1276                          CRECORD_CONST_LENGTH + extCount * CRECORD_EXT_LENGTH, ENCODING_ASCII );
1277
1278        // Konstanter Teil - 1. Satzabschnitt - Feld 2
1279        this.writeAlphaNumeric( Fields.FIELD_C2, position + CRECORD_OFFSETS1[1], CRECORD_LENGTH1[1], "C",
1280                                ENCODING_ASCII );
1281
1282        // Konstanter Teil - 1. Satzabschnitt - Feld 3
1283        this.writeNumber( Fields.FIELD_C3, position + CRECORD_OFFSETS1[2], CRECORD_LENGTH1[2],
1284                          transaction.getPrimaryBank() != null ? transaction.getPrimaryBank().intValue() : 0,
1285                          ENCODING_ASCII );
1286
1287        // Konstanter Teil - 1. Satzabschnitt - Feld 4
1288        this.writeNumber( Fields.FIELD_C4, position + CRECORD_OFFSETS1[3], CRECORD_LENGTH1[3],
1289                          transaction.getTargetBank().intValue(), ENCODING_ASCII );
1290
1291        // Konstanter Teil - 1. Satzabschnitt - Feld 5
1292        this.writeNumber( Fields.FIELD_C5, position + CRECORD_OFFSETS1[4], CRECORD_LENGTH1[4],
1293                          transaction.getTargetAccount().longValue(), ENCODING_ASCII );
1294
1295        // Konstanter Teil - 1. Satzabschnitt - Feld 6
1296        this.writeNumber( Fields.FIELD_C6A, position + CRECORD_OFFSETS1[5] - 1, 1, 0L, ENCODING_ASCII );
1297
1298        this.writeNumber( Fields.FIELD_C6, position + CRECORD_OFFSETS1[5], CRECORD_LENGTH1[5],
1299                          transaction.getReference() != null ? transaction.getReference().longValue() : 0L,
1300                          ENCODING_ASCII );
1301
1302        this.writeNumber( Fields.FIELD_C6C, position + CRECORD_OFFSETS1[6] - 1, 1, 0L, ENCODING_ASCII );
1303
1304        // Konstanter Teil - 1. Satzabschnitt - Felder 7a & 7b
1305        // TODO -3, +/- 2
1306        this.writeNumber( Fields.FIELD_C7A, position + CRECORD_OFFSETS1[6], CRECORD_LENGTH1[6] - 3, type.getKey(),
1307                          ENCODING_ASCII );
1308
1309        this.writeNumber( Fields.FIELD_C7B, position + CRECORD_OFFSETS1[6] + 2, CRECORD_LENGTH1[6] - 2,
1310                          type.getExtension(), ENCODING_ASCII );
1311
1312        // Konstanter Teil - 1. Satzabschnitt - Feld 8
1313        this.writeAlphaNumeric( Fields.FIELD_C8, position + CRECORD_OFFSETS1[7], CRECORD_LENGTH1[7], "",
1314                                ENCODING_ASCII );
1315
1316        // Konstanter Teil - 1. Satzabschnitt - Feld 9
1317        this.writeNumber( Fields.FIELD_C9, position + CRECORD_OFFSETS1[8], CRECORD_LENGTH1[8], 0L, ENCODING_ASCII );
1318
1319        // Konstanter Teil - 1. Satzabschnitt - Feld 10
1320        this.writeNumber( Fields.FIELD_C10, position + CRECORD_OFFSETS1[9], CRECORD_LENGTH1[9],
1321                          transaction.getExecutiveBank().intValue(), ENCODING_ASCII );
1322
1323        // Konstanter Teil - 1. Satzabschnitt - Feld 11
1324        this.writeNumber( Fields.FIELD_C11, position + CRECORD_OFFSETS1[10], CRECORD_LENGTH1[10],
1325                          transaction.getExecutiveAccount().longValue(), ENCODING_ASCII );
1326
1327        // Konstanter Teil - 1. Satzabschnitt - Feld 12
1328        this.writeNumber( Fields.FIELD_C12, position + CRECORD_OFFSETS1[11], CRECORD_LENGTH1[11],
1329                          transaction.getAmount().longValue(), ENCODING_ASCII ); // TODO longValueExact()
1330
1331        // Konstanter Teil - 1. Satzabschnitt - Feld 13
1332        this.writeAlphaNumeric( Fields.FIELD_C13, position + CRECORD_OFFSETS1[12], CRECORD_LENGTH1[12], "",
1333                                ENCODING_ASCII );
1334
1335        // Konstanter Teil - 1. Satzabschnitt - Feld 14a
1336        this.writeAlphaNumeric( Fields.FIELD_C14A, position + CRECORD_OFFSETS1[13], CRECORD_LENGTH1[13],
1337                                transaction.getTargetName().format(), ENCODING_ASCII );
1338
1339        // Konstanter Teil - 1. Satzabschnitt - Feld 14b
1340        this.writeAlphaNumeric( Fields.FIELD_C14B, position + CRECORD_OFFSETS1[14], CRECORD_LENGTH1[14], "",
1341                                ENCODING_ASCII );
1342
1343        // Konstanter Teil - 2. Satzabschnitt - Feld 15(1)
1344        this.writeAlphaNumeric( Fields.FIELD_C15, position + this.getBlockSize() + CRECORD_OFFSETS2[0],
1345                                CRECORD_LENGTH2[0], transaction.getExecutiveName().format(), ENCODING_ASCII );
1346
1347        // Konstanter Teil - 2. Satzabschnitt - Feld 16(2)
1348        this.writeAlphaNumeric( Fields.FIELD_C16, position + this.getBlockSize() + CRECORD_OFFSETS2[1],
1349                                CRECORD_LENGTH2[1], desc.length > 0 ? desc[0].format() : "", ENCODING_ASCII );
1350
1351        // Konstanter Teil - 2. Satzabschnitt - Feld 17a(3)
1352        this.writeAlphaNumeric(
1353            Fields.FIELD_C17A, position + this.getBlockSize() + CRECORD_OFFSETS2[2],
1354            CRECORD_LENGTH2[2], Character.toString( this.getCurrencyMapper().getDtausCode(
1355            transaction.getCurrency(), this.getHeader().getCreateDate() ) ), ENCODING_ASCII );
1356
1357        // Konstanter Teil - 2. Satzabschnitt - Feld 17b(4)
1358        this.writeAlphaNumeric( Fields.FIELD_C17B, position + this.getBlockSize() + CRECORD_OFFSETS2[3],
1359                                CRECORD_LENGTH2[3], "", ENCODING_ASCII );
1360
1361        // Konstanter Teil - 2. Satzabschnitt - Feld 18(5)
1362        this.writeNumber( Fields.FIELD_C18, position + this.getBlockSize() + CRECORD_OFFSETS2[4],
1363                          CRECORD_LENGTH2[4], extCount, ENCODING_ASCII );
1364
1365        // Erweiterungs-Teile im zweiten Satzabschnitt initialisieren.
1366        this.initializeExtensionBlock( position + this.getBlockSize(), 1 );
1367
1368        // Erweiterungs-Teile.
1369        int extIndex = 0;
1370        int blockOffset = CRECORD_EXTINDEX_TO_BLOCKOFFSET[extIndex];
1371        int lastBlockOffset = blockOffset;
1372        long blockPos = position + blockOffset * this.getBlockSize();
1373
1374        // Erweiterung des beteiligten Kontos als ersten Erweiterungsteil.
1375        if ( ( txt = transaction.getTargetExt() ) != null )
1376        {
1377            this.writeNumber(
1378                CRECORD_EXTINDEX_TO_TYPEFIELD[extIndex], blockPos + CRECORD_EXTINDEX_TO_TYPEOFFSET[extIndex],
1379                CRECORD_EXTINDEX_TO_TYPELENGTH[extIndex], 1L, ENCODING_ASCII );
1380
1381            this.writeAlphaNumeric(
1382                CRECORD_EXTINDEX_TO_VALUEFIELD[extIndex], blockPos + CRECORD_EXTINDEX_TO_VALUEOFFSET[extIndex],
1383                CRECORD_EXTINDEX_TO_VALUELENGTH[extIndex], txt.format(), ENCODING_ASCII );
1384
1385            extIndex++;
1386        }
1387
1388        // Verwendungszweck-Zeilen des 2., 3., 4., 5. und 6. Satzabschnittes.
1389        for ( int i = 1; i < desc.length; i++, extIndex++ )
1390        {
1391            blockOffset = CRECORD_EXTINDEX_TO_BLOCKOFFSET[extIndex];
1392            blockPos = position + blockOffset * this.getBlockSize();
1393
1394            if ( blockOffset != lastBlockOffset )
1395            {
1396                // Nächsten Satzabschnitt initialisieren.
1397                this.initializeExtensionBlock( blockPos, blockOffset );
1398            }
1399
1400            this.writeNumber( CRECORD_EXTINDEX_TO_TYPEFIELD[extIndex],
1401                              blockPos + CRECORD_EXTINDEX_TO_TYPEOFFSET[extIndex],
1402                              CRECORD_EXTINDEX_TO_TYPELENGTH[extIndex], 2L, ENCODING_ASCII );
1403
1404            this.writeAlphaNumeric( CRECORD_EXTINDEX_TO_VALUEFIELD[extIndex],
1405                                    blockPos + CRECORD_EXTINDEX_TO_VALUEOFFSET[extIndex],
1406                                    CRECORD_EXTINDEX_TO_VALUELENGTH[extIndex], desc[i].format(), ENCODING_ASCII );
1407
1408            lastBlockOffset = blockOffset;
1409        }
1410
1411        // Erweiterung des Auftraggeber-Kontos im letzten Erweiterungsteil.
1412        if ( ( txt = transaction.getExecutiveExt() ) != null )
1413        {
1414            blockOffset = CRECORD_EXTINDEX_TO_BLOCKOFFSET[extIndex];
1415            blockPos = position + blockOffset * this.getBlockSize();
1416
1417            if ( blockOffset != lastBlockOffset )
1418            {
1419                // Nächsten Satzabschnitt initialisieren.
1420                this.initializeExtensionBlock( blockPos, blockOffset );
1421            }
1422
1423            this.writeNumber(
1424                CRECORD_EXTINDEX_TO_TYPEFIELD[extIndex], blockPos + CRECORD_EXTINDEX_TO_TYPEOFFSET[extIndex],
1425                CRECORD_EXTINDEX_TO_TYPELENGTH[extIndex], 3L, ENCODING_ASCII );
1426
1427            this.writeAlphaNumeric(
1428                CRECORD_EXTINDEX_TO_VALUEFIELD[extIndex], blockPos + CRECORD_EXTINDEX_TO_VALUEOFFSET[extIndex],
1429                CRECORD_EXTINDEX_TO_VALUELENGTH[extIndex], txt.format(), ENCODING_ASCII );
1430
1431            extIndex++;
1432            lastBlockOffset = blockOffset;
1433        }
1434    }
1435
1436    protected int byteCount( final Transaction transaction )
1437    {
1438        int extCount = transaction.getDescriptions().length > 0 ? transaction.getDescriptions().length - 1 : 0;
1439
1440        if ( transaction.getExecutiveExt() != null )
1441        {
1442            extCount++;
1443        }
1444        if ( transaction.getTargetExt() != null )
1445        {
1446            extCount++;
1447        }
1448
1449        return CRECORD_EXTENSIONCOUNT_TO_BLOCKCOUNT[extCount] * this.getBlockSize();
1450    }
1451
1452    protected int getBlockSize()
1453    {
1454        return PhysicalFileFactory.FORMAT_DISK;
1455    }
1456
1457    private void initializeExtensionBlock( final long blockPos, final int blockOffset ) throws IOException
1458    {
1459        int extIndex;
1460        int startingExt;
1461        int endingExt;
1462        int reservedField;
1463        int reservedOffset;
1464        int reservedLength;
1465
1466        if ( blockOffset == 1 )
1467        {
1468            startingExt = 0;
1469            endingExt = 1;
1470            reservedField = Fields.FIELD_C23;
1471            reservedOffset = CRECORD_OFFSETS2[9];
1472            reservedLength = CRECORD_LENGTH2[9];
1473        }
1474        else if ( blockOffset == 2 )
1475        {
1476            startingExt = 2;
1477            endingExt = 5;
1478            reservedField = Fields.FIELD_C32;
1479            reservedOffset = CRECORD_OFFSETS_EXT[8];
1480            reservedLength = CRECORD_LENGTH_EXT[8];
1481        }
1482        else if ( blockOffset == 3 )
1483        {
1484            startingExt = 6;
1485            endingExt = 9;
1486            reservedField = Fields.FIELD_C41;
1487            reservedOffset = CRECORD_OFFSETS_EXT[8];
1488            reservedLength = CRECORD_LENGTH_EXT[8];
1489        }
1490        else if ( blockOffset == 4 )
1491        {
1492            startingExt = 10;
1493            endingExt = 13;
1494            reservedField = Fields.FIELD_C50;
1495            reservedOffset = CRECORD_OFFSETS_EXT[8];
1496            reservedLength = CRECORD_LENGTH_EXT[8];
1497        }
1498        else if ( blockOffset == 5 )
1499        {
1500            startingExt = 14;
1501            endingExt = 17;
1502            reservedField = Fields.FIELD_C59;
1503            reservedOffset = CRECORD_OFFSETS_EXT[8];
1504            reservedLength = CRECORD_LENGTH_EXT[8];
1505        }
1506        else
1507        {
1508            throw new IllegalArgumentException( Integer.toString( blockOffset ) );
1509        }
1510
1511        // Erweiterungsteile leeren.
1512        for ( extIndex = startingExt; extIndex <= endingExt; extIndex++ )
1513        {
1514            this.writeNumber(
1515                CRECORD_EXTINDEX_TO_TYPEFIELD[extIndex], blockPos + CRECORD_EXTINDEX_TO_TYPEOFFSET[extIndex],
1516                CRECORD_EXTINDEX_TO_TYPELENGTH[extIndex], 0L, ENCODING_ASCII );
1517
1518            this.writeAlphaNumeric(
1519                CRECORD_EXTINDEX_TO_VALUEFIELD[extIndex], blockPos + CRECORD_EXTINDEX_TO_VALUEOFFSET[extIndex],
1520                CRECORD_EXTINDEX_TO_VALUELENGTH[extIndex], "", ENCODING_ASCII );
1521
1522        }
1523
1524        // Reserve-Feld initialisieren.
1525        this.writeAlphaNumeric( reservedField, blockPos + reservedOffset, reservedLength, "", ENCODING_ASCII );
1526    }
1527
1528    protected Implementation getImplementation()
1529    {
1530        return ModelFactory.getModel().getModules().
1531            getImplementation( DTAUSDisk.class.getName() );
1532
1533    }
1534
1535    //--Dependencies------------------------------------------------------------
1536
1537// <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:jdtausDependencies
1538    // This section is managed by jdtaus-container-mojo.
1539
1540    /**
1541     * Gets the configured <code>Logger</code> implementation.
1542     *
1543     * @return The configured <code>Logger</code> implementation.
1544     */
1545    protected Logger getLogger()
1546    {
1547        return (Logger) ContainerFactory.getContainer().
1548            getDependency( this, "Logger" );
1549
1550    }
1551
1552// </editor-fold>//GEN-END:jdtausDependencies
1553
1554    //------------------------------------------------------------Dependencies--
1555}