// Path: src/main/java/com/qoomon/banking/swift/message/block/exception/BlockFieldParseException.java
// public class BlockFieldParseException extends Exception {
// 
// 
//     public BlockFieldParseException(String message) {
//         super(message);
//     }
// 
// 
//     public BlockFieldParseException(String message, Throwable cause) {
//         super(message, cause);
//     }
// 
// }
// 
// Path: src/main/java/com/qoomon/banking/swift/message/block/exception/BlockParseException.java
// public class BlockParseException extends Exception {
// 
//     private final int lineNumber;
// 
//     public BlockParseException(Throwable cause) {
//         super(cause);
//         this.lineNumber = 0;
//     }
// 
//     public BlockParseException(String message) {
//         super(message);
//         this.lineNumber = 0;
//     }
// 
//     public BlockParseException(String message, int lineNumber) {
//         super(message + " at line " + lineNumber);
//         this.lineNumber = lineNumber;
//     }
// 
//     public BlockParseException(String message, int lineNumber, Throwable cause) {
//         super(message + " at line " + lineNumber, cause);
//         this.lineNumber = lineNumber;
//     }
// 
//     public int getLineNumber() {
//         return lineNumber;
//     }
// }


import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import com.qoomon.banking.swift.message.block.exception.BlockFieldParseException;
import com.qoomon.banking.swift.message.block.exception.BlockParseException;
import java.io.StringReader;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
        this.bankingPriorityCode = Optional.ofNullable(bankingPriorityCode);
        this.messageUserReference = messageUserReference;
        this.additionalSubblocks = ImmutableMap.copyOf(additionalSubblocks);
    }

    public static UserHeaderBlock of(GeneralBlock block) throws BlockFieldParseException {
        Preconditions.checkArgument(block.getId().equals(BLOCK_ID_3), "unexpected block id '%s'", block.getId());

        SwiftBlockReader blockReader = new SwiftBlockReader(new StringReader(block.getContent()));

        String bankingPriorityCode = null;
        String messageUserReference = null;
        Map<String, GeneralBlock> additionalSubblocks = new HashMap<>();

        try {
            GeneralBlock subblock;
            while ((subblock = blockReader.readBlock()) != null) {
                switch (subblock.getId()) {
                    case "113":
                        bankingPriorityCode = subblock.getContent(); // TODO regex check
                        break;
                    case "108":
                        messageUserReference = subblock.getContent(); // TODO regex check
                        break;
                    default:
                        additionalSubblocks.put(subblock.getId(), subblock);
                        break;
                }
            }
        } catch (BlockParseException e) {
// Path: src/main/java/com/qoomon/banking/swift/message/block/exception/BlockFieldParseException.java
// public class BlockFieldParseException extends Exception {
// 
// 
//     public BlockFieldParseException(String message) {
//         super(message);
//     }
// 
// 
//     public BlockFieldParseException(String message, Throwable cause) {
//         super(message, cause);
//     }
// 
// }
// 
// Path: src/main/java/com/qoomon/banking/swift/message/block/exception/BlockParseException.java
// public class BlockParseException extends Exception {
// 
//     private final int lineNumber;
// 
//     public BlockParseException(Throwable cause) {
//         super(cause);
//         this.lineNumber = 0;
//     }
// 
//     public BlockParseException(String message) {
//         super(message);
//         this.lineNumber = 0;
//     }
// 
//     public BlockParseException(String message, int lineNumber) {
//         super(message + " at line " + lineNumber);
//         this.lineNumber = lineNumber;
//     }
// 
//     public BlockParseException(String message, int lineNumber, Throwable cause) {
//         super(message + " at line " + lineNumber, cause);
//         this.lineNumber = lineNumber;
//     }
// 
//     public int getLineNumber() {
//         return lineNumber;
//     }
// }


// Path: src/main/java/com/qoomon/banking/swift/message/block/UserHeaderBlock.java
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import com.qoomon.banking.swift.message.block.exception.BlockFieldParseException;
import com.qoomon.banking.swift.message.block.exception.BlockParseException;
import java.io.StringReader;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

        this.bankingPriorityCode = Optional.ofNullable(bankingPriorityCode);
        this.messageUserReference = messageUserReference;
        this.additionalSubblocks = ImmutableMap.copyOf(additionalSubblocks);
    }

    public static UserHeaderBlock of(GeneralBlock block) throws BlockFieldParseException {
        Preconditions.checkArgument(block.getId().equals(BLOCK_ID_3), "unexpected block id '%s'", block.getId());

        SwiftBlockReader blockReader = new SwiftBlockReader(new StringReader(block.getContent()));

        String bankingPriorityCode = null;
        String messageUserReference = null;
        Map<String, GeneralBlock> additionalSubblocks = new HashMap<>();

        try {
            GeneralBlock subblock;
            while ((subblock = blockReader.readBlock()) != null) {
                switch (subblock.getId()) {
                    case "113":
                        bankingPriorityCode = subblock.getContent(); // TODO regex check
                        break;
                    case "108":
                        messageUserReference = subblock.getContent(); // TODO regex check
                        break;
                    default:
                        additionalSubblocks.put(subblock.getId(), subblock);
                        break;
                }
            }
        } catch (BlockParseException e) {
            throw new BlockFieldParseException("Block '" + block.getId() + "' content error", e);