#####################################
##     Created by briandeheus      ##
## https://github.com/briandeheus  ##
##    Implementation and changes   ##
##           LoafyLemon            ##
#####################################
init python:
    import binascii
    import struct

    class ImagePayload(object):

        _END_CHUNK_TYPE = 'IEND'
        _PUNK_CHUNK_TYPE = 'wtSi'
        _MAX_BYTES = 2147483647
        _chunks = dict()

        def __init__(self):
            self._mode = None
            self._file = None
            self._output = None
            self._bytes_to_hide = None

            self._bytes_read = 0

        def decode(self, input_file):
            self.__init__()
            self._mode = 'decode'
            self._file = open("{}/outfits/{}".format(config.gamedir, input_file), 'rb+')
            #self._output = open(config.basedir+'/game/'+output_file+'.txt', 'wb+')

            # First move cursor past the signature
            self._read_bytes(8)

            # Start reading chunks
            self._read_next_chunk()
            return self._output

        def encode(self, input_file, bytes_to_hide):
            self.__init__()
            self._mode = 'encode'
            self._file = open("{}/outfits/{}.png".format(config.gamedir, input_file), 'rb+')
            self._bytes_to_hide = bytes_to_hide.encode('utf-8')

            # First move cursor past the signature
            self._read_bytes(8)

            # Start reading chunks
            self._read_next_chunk()

        def _read_bytes_as_hex(self, position):
            return self._read_bytes(position).encode('hex')

        def _read_bytes_as_ascii(self, position):
            return self._read_bytes(position).encode('ascii')

        def _read_bytes_as_int(self, position):
            return int(self._read_bytes_as_hex(position), 16)

        def _read_bytes(self, byte_count):
            self._bytes_read += byte_count
            return self._file.read(byte_count)

        def _rewind_bytes(self, byte_count):
            self._bytes_read -= byte_count
            self._file.seek(self._bytes_read)

        def _inject_punk_chunk(self):
            # Move back 8 bytes.
            self._rewind_bytes(8)

            chunk_size = len(self._bytes_to_hide)
            print 'Hiding', (chunk_size / 1024), 'kB (', chunk_size, 'bytes)'

            # Create a temporary byte array for the CRC check.
            tmp_bytes = bytearray()

            # First write the chunk type
            tmp_bytes.extend(bytearray(self._PUNK_CHUNK_TYPE))

            # Now write the bytes of whatever we're trying to hide
            tmp_bytes.extend(self._bytes_to_hide)

            #print 'Injecting punk chunk'

            # Write the chunk size
            self._file.write(bytearray(struct.pack('!i', chunk_size)))

            # And the type
            self._file.write(bytearray(self._PUNK_CHUNK_TYPE))

            self._file.write(self._bytes_to_hide)

            crc = binascii.crc32(tmp_bytes)
            self._file.write(bytearray(struct.pack('!i', crc)))

            # Write the end chunk. Start with the size.
            self._file.write(bytearray(struct.pack('!i', 0)))
            # Then the chunk type.
            self._file.write(bytearray(self._END_CHUNK_TYPE))

            crc = binascii.crc32(bytearray(self._END_CHUNK_TYPE))
            self._file.write(bytearray(struct.pack('!i', crc)))

            #print 'Punk chunk injected'

        def _read_next_chunk(self):
            chunk_size = self._read_bytes_as_int(4)
            print 'Chunk size:', chunk_size

            chunk_type = self._read_bytes_as_ascii(4)
            print 'Chunk type:', chunk_type

            if self._mode == 'encode' and chunk_type == self._END_CHUNK_TYPE:
                self._inject_punk_chunk()

                #print 'Reached EOF'
                self._file.close()
                return

            content = self._read_bytes(chunk_size)

            crc = self._read_bytes_as_hex(4)
            print 'CRC:', crc

            if self._mode == 'decode' and chunk_type == self._PUNK_CHUNK_TYPE:
                print "Found a chunk data", len(content), "bytes. Importing.."
                #self._output.write(bytearray(content))
                #self._output.close()
                self._output = content.decode('utf-8')
                self._file.close()
                print "Done."
                return True

            self._read_next_chunk()

    image_payload = ImagePayload()
