package storage

import "github.com/boltdb/bolt"

type Bolt struct {
	db *bolt.DB
}

func NewBolt(path string) (*Bolt, error) {
	db, err := bolt.Open(path, 0600, nil)
	return &Bolt{
		db: db,
	}, err
}

func (b *Bolt) List(ns []string, limits ...string) ([]string, error) {
	namespace := resolveNamespace(ns)
	limits = resolveLimits(limits)
	found := []string{}
	err := b.db.View(func(tx *bolt.Tx) error {
		bucket := tx.Bucket([]byte(namespace))
		if bucket == nil {
			return nil
		}

		c := bucket.Cursor()
		for k, _ := c.Seek([]byte(limits[0])); k != nil; k, _ = c.Next() {
			found = append(found, string(k))
		}
		return nil
	})
	return found, err
}

func (b *Bolt) Get(key string, ns ...string) ([]byte, error) {
	namespace := resolveNamespace(ns)
	var result []byte
	err := b.db.View(func(tx *bolt.Tx) error {
		bkt := tx.Bucket([]byte(namespace))
		if bkt == nil {
			return ErrNotFound
		}
		result = bkt.Get([]byte(key))
		if result == nil {
			return ErrNotFound
		}
		return nil
	})
	return result, err
}

func (b *Bolt) Set(key string, value []byte, ns ...string) error {
	namespace := resolveNamespace(ns)
	return b.db.Update(func(tx *bolt.Tx) error {
		bkt, err := tx.CreateBucketIfNotExists([]byte(namespace))
		if err != nil {
			return err
		}
		return bkt.Put([]byte(key), value)
	})
}

func (b *Bolt) Close() error {
	return b.db.Close()
}
