package charset

import (
	"fmt"
	"unicode/utf8"
)

func init() {
	registerClass("big5", fromBig5, nil)
}

// Big5 consists of 89 fonts of 157 chars each
const (
	big5Max  = 13973
	big5Font = 157
	big5Data = "big5.dat"
)

type translateFromBig5 struct {
	font    int
	scratch []byte
	big5map []rune
}

func (p *translateFromBig5) Translate(data []byte, eof bool) (int, []byte, error) {
	p.scratch = p.scratch[:0]
	n := 0
	for len(data) > 0 {
		c := int(data[0])
		data = data[1:]
		n++
		if p.font == -1 {
			// idle state
			if c >= 0xa1 {
				p.font = c
				continue
			}
			if c == 26 {
				c = '\n'
			}
			continue
		}
		f := p.font
		p.font = -1
		r := utf8.RuneError
		switch {
		case c >= 64 && c <= 126:
			c -= 64
		case c >= 161 && c <= 254:
			c = c - 161 + 63
		default:
			// bad big5 char
			f = 255
		}
		if f <= 254 {
			f -= 161
			ix := f*big5Font + c
			if ix < len(p.big5map) {
				r = p.big5map[ix]
			}
			if r == -1 {
				r = utf8.RuneError
			}
		}
		p.scratch = appendRune(p.scratch, r)
	}
	return n, p.scratch, nil
}

type big5Key bool

func fromBig5(arg string) (Translator, error) {
	big5map, err := cache(big5Key(false), func() (interface{}, error) {
		data, err := readFile(big5Data)
		if err != nil {
			return nil, fmt.Errorf("charset: cannot open big5 data file: %v", err)
		}
		big5map := []rune(string(data))
		if len(big5map) != big5Max {
			return nil, fmt.Errorf("charset: corrupt big5 data")
		}
		return big5map, nil
	})
	if err != nil {
		return nil, err
	}
	return &translateFromBig5{big5map: big5map.([]rune), font: -1}, nil
}