// Path: copybook4java/src/main/java/com/nordea/oss/copybook/exceptions/CopyBookException.java
// public class CopyBookException extends RuntimeException {
//     private static final long serialVersionUID = 28118369047109260L;
//     public CopyBookException(String message) {
//         super(message);
//     }
// 
//     public CopyBookException(String message, TypeConverterException ex) {
//         super(message + ": " + ex.getClass().getSimpleName() + " :" + ex.getMessage());
//     }
// 
//     public CopyBookException(String message, Exception ex) {
//         super(message + ": " + ex.getClass().getSimpleName() + " :" + ex.getMessage());
//     }
// }


import com.nordea.oss.copybook.exceptions.CopyBookException;
import java.lang.reflect.Array;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/*
 * Copyright (c) 2015. Troels Liebe Bentsen <tlb@nversion.dk>
 * Copyright (c) 2016. Nordea Bank AB
 * Licensed under the MIT license (LICENSE.txt)
 */

package com.nordea.oss.copybook.serializers;



public class FullMapper extends CopyBookMapperBase {

    public <T> byte[] serialize(T obj) {
        ByteBuffer buffer = ByteBuffer.wrap(new byte[this.maxRecordSize]);
        writeFieldsToBuffer(this.fields, buffer, obj);
        byte[] result = new byte[buffer.position()];
        System.arraycopy(buffer.array(), 0, result, 0, buffer.position()); // Copy bytes to result array
        return result;
    }

    private <T> void writeFieldsToBuffer(List<CopyBookField> fields, ByteBuffer buffer, T rootObj) {
        for(CopyBookField field : fields) {
            if(field.isArray()) {
                Object array = field.getObject(rootObj);
                int arraySize = Math.max(array != null ? Array.getLength(array) : 0, field.getMinOccurs());
                if(field.hasSubCopyBookFields()) {
                    // Complex array types fx. Request[]
                    for (int i = 0; i < arraySize; i++) {
                        writeFieldsToBuffer(field.getSubCopyBookFields(), buffer, field.getObject(rootObj, i));
                    }

                } else {
                    // Simple array types, fx. int[]
                    for (int i = 0; i < arraySize; i++) {
                        buffer.put(field.getBytes(rootObj, array, i, true));
                    }
                }

            } else if(field.hasSubCopyBookFields()) {
                // Complex type fx, Request
                writeFieldsToBuffer(field.getSubCopyBookFields(), buffer, field.getObject(rootObj));

            } else {
                // Simple type fx. int
                byte[] bytes = field.getBytes(rootObj, true);
                if(bytes != null) {
                    buffer.put(bytes);

                } else if(rootObj == null) {
// Path: copybook4java/src/main/java/com/nordea/oss/copybook/exceptions/CopyBookException.java
// public class CopyBookException extends RuntimeException {
//     private static final long serialVersionUID = 28118369047109260L;
//     public CopyBookException(String message) {
//         super(message);
//     }
// 
//     public CopyBookException(String message, TypeConverterException ex) {
//         super(message + ": " + ex.getClass().getSimpleName() + " :" + ex.getMessage());
//     }
// 
//     public CopyBookException(String message, Exception ex) {
//         super(message + ": " + ex.getClass().getSimpleName() + " :" + ex.getMessage());
//     }
// }


// Path: copybook4java/src/main/java/com/nordea/oss/copybook/serializers/FullMapper.java
import com.nordea.oss.copybook.exceptions.CopyBookException;
import java.lang.reflect.Array;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/*
 * Copyright (c) 2015. Troels Liebe Bentsen <tlb@nversion.dk>
 * Copyright (c) 2016. Nordea Bank AB
 * Licensed under the MIT license (LICENSE.txt)
 */

package com.nordea.oss.copybook.serializers;



public class FullMapper extends CopyBookMapperBase {

    public <T> byte[] serialize(T obj) {
        ByteBuffer buffer = ByteBuffer.wrap(new byte[this.maxRecordSize]);
        writeFieldsToBuffer(this.fields, buffer, obj);
        byte[] result = new byte[buffer.position()];
        System.arraycopy(buffer.array(), 0, result, 0, buffer.position()); // Copy bytes to result array
        return result;
    }

    private <T> void writeFieldsToBuffer(List<CopyBookField> fields, ByteBuffer buffer, T rootObj) {
        for(CopyBookField field : fields) {
            if(field.isArray()) {
                Object array = field.getObject(rootObj);
                int arraySize = Math.max(array != null ? Array.getLength(array) : 0, field.getMinOccurs());
                if(field.hasSubCopyBookFields()) {
                    // Complex array types fx. Request[]
                    for (int i = 0; i < arraySize; i++) {
                        writeFieldsToBuffer(field.getSubCopyBookFields(), buffer, field.getObject(rootObj, i));
                    }

                } else {
                    // Simple array types, fx. int[]
                    for (int i = 0; i < arraySize; i++) {
                        buffer.put(field.getBytes(rootObj, array, i, true));
                    }
                }

            } else if(field.hasSubCopyBookFields()) {
                // Complex type fx, Request
                writeFieldsToBuffer(field.getSubCopyBookFields(), buffer, field.getObject(rootObj));

            } else {
                // Simple type fx. int
                byte[] bytes = field.getBytes(rootObj, true);
                if(bytes != null) {
                    buffer.put(bytes);

                } else if(rootObj == null) {
                    throw new CopyBookException("Root object for field '" + field.getFieldName() + "' is null and the TypeConverter '" + field.getConverter().getClass().getSimpleName() + "' does not support null filler");