package lib

import (
	"archive/tar"
	"bufio"
	"compress/gzip"
	"fmt"
	"io"
	"os"
	"path"
	"strings"
	"unicode"

	"github.com/bigkevmcd/go-configparser"
)

type Pool struct {
	Maintainer string `json:"-"`
	Pubkey     string `json:"-"`
	Size       string `json:"-"`

	Display string `json:"display"`
	Branch  string `json:"branch"`
	Source  string `json:"source"`
	Name    string `json:"name"`
	URL     string `json:"url"`
	Dir     string `json:"dir"`
}

func (p *Pool) ID() string {
	var res string = ""

	for _, c := range p.Display {
		if unicode.IsDigit(c) || unicode.IsLetter(c) {
			res += string(c)
			continue
		}

		res += "-"
	}

	return strings.TrimSuffix(res, "-")
}

func (p *Pool) Load(list *[]Package) error {
	var err error

	if p.Dir == "" {
		return fmt.Errorf("pool directory is not specified")
	}

	if err = p.LoadInfo(); err != nil {
		return err
	}

	if err = p.LoadList(list); err != nil {
		return err
	}

	return nil
}

func (p *Pool) LoadList(list *[]Package) error {
	var (
		list_path   string
		list_file   *os.File
		gzip_reader io.Reader
		header      *tar.Header
		err         error
	)

	list_path = path.Join(p.Dir, "LIST")

	if list_file, err = os.Open(list_path); err != nil {
		return err
	}
	defer list_file.Close()

	if gzip_reader, err = gzip.NewReader(bufio.NewReader(list_file)); err != nil {
		return err
	}

	reader := tar.NewReader(gzip_reader)

	for header, err = reader.Next(); err == nil; header, err = reader.Next() {
		if header.Typeflag != tar.TypeReg {
			continue
		}

		if path.Base(header.Name) != "DATA" {
			return fmt.Errorf("LIST archive contains an unknown file")
		}

		var pkg Package

		if err = pkg.Load(reader); err != nil {
			return err
		}

		pkg.Archive = path.Join(p.Dir, fmt.Sprintf("%s_%s.mpf", pkg.Name, pkg.Version))
		pkg.Pool = p

		*list = append(*list, pkg)
	}

	return nil
}

func (p *Pool) LoadInfo() error {
	var (
		info_path string
		info_file *os.File
		section   string
		size      int64
		err       error
	)

	info_path = path.Join(p.Dir, "INFO")

	if info_file, err = os.Open(info_path); err != nil {
		return err
	}

	parser := configparser.New()

	if err = parser.ParseReader(bufio.NewReader(info_file)); err != nil {
		return err
	}

	section = "DEFAULT"

	for _, s := range parser.Sections() {
		if s == "DEFAULT" {
			continue
		}
		section = s
		break
	}

	if section == "DEFAULT" {
		return fmt.Errorf("DATA does not contain any sections")
	}

	if p.Name != section {
		return fmt.Errorf("pool name (\"%s\") doesn't match with \"%s\"", p.Name, section)
	}

	if p.Maintainer, err = parser.Get(p.Name, "maintainer"); err != nil {
		return err
	}

	if size, err = parser.GetInt64(section, "size"); err != nil {
		return err
	}
	p.Size = SizeFromBytes(size)

	if p.Pubkey, err = parser.Get(section, "pubkey"); err != nil {
		return err
	}

	return nil
}