/bs/io.go
package bs

// I! O! Let's go!
// I! O! Let's go!
// I! O! Let's go!
// I! O! Let's go!
//   - with apologies to The Ramones

import (
    "io"
    "log"
    "fmt"
    "errors"
    "image/png"

    "bytex64.net/code/bitsmash/packet"
    "bytex64.net/code/bitsmash/ac"
)

func (self *BitSmash) packetType(n int) int {
    switch self.packetList[n].(type) {
    case *packet.RLEPacket:
        return 0
    case *packet.BinaryPatternPacket:
        return 1
    case *packet.DirectPacket:
        return 2
    case *packet.RepeatPacket:
        return 3
    }
    return -1
}

func (self *BitSmash) ReadFrom(file io.Reader) error {
    var header [5]byte
    n, err := file.Read(header[:])
    if n < 5 {
        log.Fatal("Short read on header")
    } else if err != nil {
        return err
    }
    self.size = sizes[int(header[0]) & 0x7]
    self.palette = (int(header[0]) >> 3) & 0xF

    n_packets := int(header[1]) + (int(header[2] & 0x3) << 8) + 1
    self.packetList = make([]packet.Packet, n_packets)

    // The transparent bit is the 17th bit of the palette map
    self.paletteMap = uint32(header[3]) + (uint32(header[4]) << 8) + (uint32(header[0] & 0x80) << 9);

    decoder, err := ac.NewDecoder(file)
    if err != nil {
        return err
    }
    self.codecManagerInit(decoder)

    for i := 0; i < n_packets; i++ {
        var pkt packet.Packet // Packet! PACKET! PACKET!!!
        packet_type := decoder.Decode(packet.CONTEXT_PACKET_TYPE)
        switch packet_type {
        case 0:
            pkt = packet.DecodeRLE(decoder)
        case 1:
            pkt = packet.DecodeBinaryPattern(decoder)
        case 2:
            pkt = packet.DecodeDirect(decoder)
        case 3:
            pkt = packet.DecodeRepeat(decoder)
        }
        self.packetList[i] = pkt
    }
    return nil
}

func (self *BitSmash) WriteTo(file io.Writer) error {
    n_packets := len(self.packetList)
    if n_packets > 1024 {
        fmt.Println("Too many packets:", n_packets)
        return errors.New("Too many packets")
    }

    var header [5]byte
    transparent := 0
    if (self.paletteMap & 0x10000 > 0) {
        transparent = 1
    }
    header[0] = byte(sizeIndex(self.size) + (self.palette << 3) + (transparent << 7))
    header[1] = byte((n_packets - 1) & 0xFF)
    header[2] = byte(((n_packets - 1) >> 8) & 0x3)
    header[3] = byte(self.paletteMap & 0xFF)
    header[4] = byte(self.paletteMap >> 8)

    file.Write(header[:])

    encoder, err := ac.NewEncoder(file)
    if err != nil {
        return err
    }
    self.codecManagerInit(encoder)

    for i, p := range(self.packetList) {
        encoder.Encode(packet.CONTEXT_PACKET_TYPE, uint32(self.packetType(i)))
        p.Encode(encoder)
    }
    encoder.Finish()
    
    return nil
}

func (self *BitSmash) WriteImage(file io.Writer) error {
    image := self.toImage()
    return png.Encode(file, image)
}