# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#

from . import kex_utils

TYPE_INDEXED = 1
TYPE_DATASET = 2

# -----------------------------------------------------------------------------
# 
class Archive:
    def __init__(self, type, offset=0, count=0, size=0):
        self.type = type            #0=Raw Data, 1=Indexed, 2=Dataset
        self.startOffset = 0        #first byte position of this archive. The start of the header.
        self.count = 0              #number of indexes
        self.offsets = []           #offset to each block (ints)
        self.arcIndexSizes = []     #byte size of each block (ints)
        self.arcIndexArchives = []  #Archive of each block. None if not a archive (Raw Data).
        self.arcDatasetSize = 0     #size of each entry
        
        if type == TYPE_INDEXED:
            self.startOffset = offset
            self.count = count
            self.arcIndexSizes = [0] * count
            self.arcIndexArchives = [None] * count
            self.offsets = [0] * (count + 1)
            headerSize = (len(self.offsets) * 4) + 4
            headerSize = kex_utils.ceil_divide(headerSize, 8) * 8
            self.offsets[0] = self.startOffset + headerSize
            for i in range(1, len(self.offsets)):
                self.offsets[i] = self.offsets[0]
            #end for
        elif type == TYPE_DATASET:
            self.startOffset = offset
            self.count = count
            if self.count == 0:
                self.arcDatasetSize = 0
            else:
                self.arcDatasetSize = size
            self.offsets = [0] * self.count
            if self.count > 0:
                self.offsets[0] = self.startOffset + 8 #8 bytes ahead of start for header
            #end if
            for i in range(1, self.count):
                self.offsets[i] = self.offsets[0] + (i * self.arcDatasetSize)
            #end for
        #end if
    #end func
    # -----------------------------------------------------------------------------
    # 
    def get_index_offset(self, index):
        return self.offsets[index]
    #end func
    # -----------------------------------------------------------------------------
    # Returns total size in bytes
    def write_header(self, data):
        data.seek(self.startOffset)
        if self.type == TYPE_INDEXED:
            kex_utils.write32(data, self.count, False)
            for i in range(0, len(self.offsets)):
                kex_utils.write32(data, self.offsets[i] - self.startOffset, False)
            #end for
        elif self.type == TYPE_DATASET:
            kex_utils.write32(data, self.arcDatasetSize, False)
            kex_utils.write32(data, self.count, False)
        #end if
    #end func
    # -----------------------------------------------------------------------------
    # Returns total size in bytes
    def get_total_size(self):
        if self.type == TYPE_INDEXED:
            return self.offsets[len(self.offsets) - 1] - self.startOffset
        elif self.type == TYPE_DATASET:
            tSize = (self.arcDatasetSize * self.count) + 8
            return kex_utils.ceil_divide(tSize, 8) * 8
        #end if
        
        return 0
    #end func
    # -----------------------------------------------------------------------------
    # Returns True if is empty
    def is_empty(self):
        if self.type == TYPE_INDEXED:
            return self.count == 0
        elif self.type == TYPE_DATASET:
            return self.arcDatasetSize == 0 or self.count == 0
        #end if
        
        return True
    #end func
    # -----------------------------------------------------------------------------
    # For Indexed Archives.
    def set_block(self, blockIndex, archive):
        self.set_block_size(blockIndex, archive, archive.get_total_size())
    #end func
    # -----------------------------------------------------------------------------
    # For Indexed Archives. Sets a block to another archive with the byte size of the block
    # blockIndex:   The block to set
    # archive:      Archive associated with this block. Can be None.
    # size:         byte size of block
    def set_block_size(self, blockIndex, archive, size):
        self.arcIndexArchives[blockIndex] = archive
        self.arcIndexSizes[blockIndex] = size
        self.offsets[blockIndex + 1] = self.offsets[blockIndex] + size
    #end func
    # -----------------------------------------------------------------------------
    # Creates an Archive by reading from the data at offset
    @staticmethod
    def from_read_buffer(type, data, offset):
        data.seek(offset)
        if type == TYPE_INDEXED:
            count = kex_utils.read32(data, False)
            archive = Archive(TYPE_INDEXED, offset, count)
            if count == 0:
                return archive
            for i in range(count + 1):
                archive.offsets[i] = offset + kex_utils.read32(data, False)
                #print("offset %i: %i" % (i, archive.offsets[i]))
            #end for
            for i in range(count):
                archive.arcIndexSizes[i] = archive.offsets[i + 1] - archive.offsets[i]
            #end for

            return archive
        elif type == TYPE_DATASET:
            size = kex_utils.read32(data, False)
            #print("[from_read_buffer] size: %i" % (size))
            if size == 0:
                return Archive(TYPE_DATASET, offset, 0, 0)
            count = kex_utils.read32(data, False)
            #print("[from_read_buffer] offset: %i count: %i" % (offset, count))
            
            return Archive(TYPE_DATASET, offset, count, size)
        #end if
        
        return None
    #end func
    # -----------------------------------------------------------------------------
    # Convenience function to create a string DataSet Archive
    @staticmethod
    def from_string(offset, s):
        return Archive(TYPE_DATASET, offset, 1, len(s) + 1)
    #end func
    # -----------------------------------------------------------------------------
    # Assumes this DataSet Archive offsets to a string and returns it from the data
    def as_string(self, data):
        if self.is_empty():
            return ""
        data.seek(self.offsets[0])
        return kex_utils.readStringCount(data, self.arcDatasetSize - 1) #-1 to not read the zero terminated char
    #end func
    # -----------------------------------------------------------------------------
    # 
    def __str__(self):
        return "type: %s" % (self.type)
    #end func
    # -----------------------------------------------------------------------------
    # 
    def __repr__(self):
        return str(self)
    #end func
#end class
