package com.punchthrough.bean.sdk.message;

import com.punchthrough.bean.sdk.internal.exception.HexParsingException;
import com.punchthrough.bean.sdk.internal.exception.NameLengthException;
import com.punchthrough.bean.sdk.internal.intelhex.Line;
import com.punchthrough.bean.sdk.internal.intelhex.LineRecordType;

import org.apache.commons.codec.DecoderException;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.ListIterator;

import static com.punchthrough.bean.sdk.internal.utility.Misc.asciiHexToBytes;
import static com.punchthrough.bean.sdk.internal.utility.Misc.bytesToInt;

public class SketchHex {

    private static final int MAX_SKETCH_NAME_LENGTH = 20;

    private String sketchName;
    private List<Line> lines = new ArrayList<>();

    /**
     * Initialize a SketchHex object with a string of Intel Hex data.
     * @param hexString The Intel Hex data as a string
     */
    public SketchHex(String hexString) throws HexParsingException {
        parseHexString(hexString);
    }

    /**
     * Retrieve the name of the sketch.
     * @return The name of the sketch
     */
    public String getSketchName() {
        return sketchName;
    }

    /**
     * Set the name of this sketch for programming to a Bean.
     * @param sketchName The new name of the sketch
     */
    public void setSketchName(String sketchName) throws NameLengthException {
        if (sketchName.length() > MAX_SKETCH_NAME_LENGTH) {
            throw new NameLengthException(String.format(
                    "Sketch name must be %d characters or less", MAX_SKETCH_NAME_LENGTH));
        }
        this.sketchName = sketchName;
    }

    public byte[] getBytes() {
        List<Line> dataLines = new ArrayList<>();
        int byteCount = 0;
        for (Line line : lines) {
            if (line.getRecordType() == LineRecordType.DATA) {
                dataLines.add(line);
                byteCount += line.getByteCount();
            }
        }

        byte[] bytes = new byte[byteCount];
        int i = 0;
        for (Line line : dataLines) {
            for (byte b : line.getData()) {
                bytes[i] = b;
                i++;
            }
        }

        return bytes;
    }

    private void parseHexString(String hexString) throws HexParsingException {
        List<String> rawLines = Arrays.asList(hexString.split("\n"));
        ListIterator<String> iterator = rawLines.listIterator();
        while (iterator.hasNext()) {

            int rawLineNum = iterator.nextIndex();
            String rawLine = iterator.next();

            if (rawLine.length() < 11) continue;

            if ( ! rawLine.startsWith(":") ) {
                throw new HexParsingException(String.format(
                        "Couldn't parse hex: line %d did not start with ':'", rawLineNum));
            }

            rawLine = rawLine.replaceAll("\r", "");

            // rawBytes: bytes of the string without the leading colon, parsed into hex
            byte[] rawBytes;
            try {
                rawBytes = asciiHexToBytes(rawLine.substring(1));
            } catch (DecoderException e) {
                throw new HexParsingException(String.format(
                        "Couldn't parse hex: line %d ASCII could not be parsed to byte array: %s",
                        rawLineNum, e.getLocalizedMessage()));
            }

            Line line = new Line();
            line.setByteCount(rawBytes[0]);
            line.setAddress(bytesToInt(rawBytes[1], rawBytes[2]));

            byte rawRecordType = rawBytes[3];
            LineRecordType recordType;
            if (rawRecordType == 0) {
                recordType = LineRecordType.DATA;
            } else if (rawRecordType == 1) {
                recordType = LineRecordType.END_OF_FILE;
            } else if (rawRecordType == 2) {
                recordType = LineRecordType.EXTENDED_SEGMENT_ADDRESS;
            } else if (rawRecordType == 3) {
                recordType = LineRecordType.START_SEGMENT_ADDRESS;
            } else if (rawRecordType == 4) {
                recordType = LineRecordType.EXTENDED_LINEAR_ADDRESS;
            } else if (rawRecordType == 5) {
                recordType = LineRecordType.START_LINEAR_ADDRESS;
            } else {
                throw new HexParsingException(String.format(
                        "Couldn't parse hex: line %d had invalid record type %d",
                        rawLineNum, rawRecordType));
            }
            line.setRecordType(recordType);

            if (line.getByteCount() > 0) {
                line.setData(Arrays.copyOfRange(rawBytes, 4, 4 + line.getByteCount()));
            }

            line.setChecksum(rawBytes[4 + line.getByteCount()]);

            lines.add(line);

        }
    }
}

@@ -33,24 +33,81 @@
 k.message;%0A%0A
+import android.os.Parcel;%0Aimport android.os.Parcelable;%0A%0A
 import com.p
@@ -701,16 +701,38 @@
 etchHex 
+implements Parcelable 
 %7B%0A%0A    p
@@ -4878,11 +4878,1034 @@
  %7D%0A    %7D
+%0A%0A    protected SketchHex(Parcel in) %7B%0A        sketchName = in.readString();%0A        if (in.readByte() == 0x01) %7B%0A            lines = new ArrayList%3CLine%3E();%0A            in.readList(lines, Line.class.getClassLoader());%0A        %7D else %7B%0A            lines = null;%0A        %7D%0A    %7D%0A%0A    @Override%0A    public int describeContents() %7B%0A        return 0;%0A    %7D%0A%0A    @Override%0A    public void writeToParcel(Parcel dest, int flags) %7B%0A        dest.writeString(sketchName);%0A        if (lines == null) %7B%0A            dest.writeByte((byte) (0x00));%0A        %7D else %7B%0A            dest.writeByte((byte) (0x01));%0A            dest.writeList(lines);%0A        %7D%0A    %7D%0A%0A    @SuppressWarnings(%22unused%22)%0A    public static final Parcelable.Creator%3CSketchHex%3E CREATOR = new Parcelable.Creator%3CSketchHex%3E() %7B%0A        @Override%0A        public SketchHex createFromParcel(Parcel in) %7B%0A            return new SketchHex(in);%0A        %7D%0A%0A        @Override%0A        public SketchHex%5B%5D newArray(int size) %7B%0A            return new SketchHex%5Bsize%5D;%0A        %7D%0A    %7D;
 %0A%7D%0A

Make Sketchhex Parcelable