// Copyright Fuzamei Corp. 2018 All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package db

import (
	"bytes"
	"sync"

	"sort"
	"strings"

	log "github.com/33cn/chain33/common/log/log15"
	"github.com/33cn/chain33/types"
)

var mlog = log.New("module", "db.memdb")

// memdb 应该无需区分同步与异步操作

func init() {
	dbCreator := func(name string, dir string, cache int) (DB, error) {
		return NewGoMemDB(name, dir, cache)
	}
	registerDBCreator(memDBBackendStr, dbCreator, false)
}

//GoMemDB db
type GoMemDB struct {
	TransactionDB
	db   map[string][]byte
	lock sync.RWMutex
}

//NewGoMemDB new
func NewGoMemDB(name string, dir string, cache int) (*GoMemDB, error) {
	// memdb 不需要创建文件，后续考虑增加缓存数目
	return &GoMemDB{
		db: make(map[string][]byte),
	}, nil
}

//CopyBytes 复制字节
func CopyBytes(b []byte) (copiedBytes []byte) {
	/* 兼容leveldb
	if b == nil {
		return nil
	}
	*/
	copiedBytes = make([]byte, len(b))
	copy(copiedBytes, b)

	return copiedBytes
}

//Get get
func (db *GoMemDB) Get(key []byte) ([]byte, error) {
	db.lock.RLock()
	defer db.lock.RUnlock()

	if entry, ok := db.db[string(key)]; ok {
		return CopyBytes(entry), nil
	}
	return nil, ErrNotFoundInDb
}

//Set set
func (db *GoMemDB) Set(key []byte, value []byte) error {
	db.lock.Lock()
	defer db.lock.Unlock()
	//debug.PrintStack()
	//println("--", string(key)[0:4], common.ToHex(key))
	db.db[string(key)] = CopyBytes(value)
	if db.db[string(key)] == nil {
		mlog.Error("Set", "error have no mem")
	}
	return nil
}

//SetSync 设置同步
func (db *GoMemDB) SetSync(key []byte, value []byte) error {
	db.lock.Lock()
	defer db.lock.Unlock()
	//debug.PrintStack()
	//println("--", string(key)[0:4], common.ToHex(key))
	db.db[string(key)] = CopyBytes(value)
	if db.db[string(key)] == nil {
		mlog.Error("Set", "error have no mem")
	}
	return nil
}

//Delete 删除
func (db *GoMemDB) Delete(key []byte) error {
	db.lock.Lock()
	defer db.lock.Unlock()

	delete(db.db, string(key))
	return nil
}

//DeleteSync 删除同步
func (db *GoMemDB) DeleteSync(key []byte) error {
	db.lock.Lock()
	defer db.lock.Unlock()

	delete(db.db, string(key))
	return nil
}

//DB db
func (db *GoMemDB) DB() map[string][]byte {
	return db.db
}

//Close 关闭
func (db *GoMemDB) Close() {

}

//Print 打印
func (db *GoMemDB) Print() {
	for key, value := range db.db {
		mlog.Info("Print", "key", key, "value", string(value))
	}
}

//Stats ...
func (db *GoMemDB) Stats() map[string]string {
	//TODO
	return nil
}

//Iterator 迭代器
func (db *GoMemDB) Iterator(start []byte, end []byte, reverse bool) Iterator {
	db.lock.RLock()
	defer db.lock.RUnlock()
	if end == nil {
		end = bytesPrefix(start)
	}
	if bytes.Equal(end, types.EmptyValue) {
		end = nil
	}
	base := itBase{start, end, reverse}

	var keys []string
	for k := range db.db {
		if base.checkKey([]byte(k)) {
			keys = append(keys, k)
		}
	}
	sort.Strings(keys)
	var index int
	return &goMemDBIt{base, index, keys, db}
}

//BatchGet 批量获取
func (db *GoMemDB) BatchGet(keys [][]byte) (value [][]byte, err error) {
	mlog.Error("BatchGet", "Need to implement")
	return nil, nil
}

type goMemDBIt struct {
	itBase
	index   int      // 记录当前索引
	keys    []string // 记录所有keys值
	goMemDb *GoMemDB
}

//Seek 查找
func (dbit *goMemDBIt) Seek(key []byte) bool { //指向当前的index值
	for i, k := range dbit.keys {
		if 0 == strings.Compare(k, string(key)) {
			dbit.index = i
			return true
		}
	}
	return false
}

//Close 关闭
func (dbit *goMemDBIt) Close() {
	dbit.goMemDb.Close()
}

//Next next
func (dbit *goMemDBIt) Next() bool {
	if dbit.reverse { // 反向
		dbit.index-- //将当前key值指向前一个
		return dbit.Valid()
	}
	// 正向
	dbit.index++ //将当前key值指向后一个
	return dbit.Valid()

}

//Rewind ...
func (dbit *goMemDBIt) Rewind() bool {
	if dbit.reverse { // 反向
		if (len(dbit.keys) > 0) && dbit.Valid() {
			dbit.index = len(dbit.keys) - 1 // 将当前key值指向最后一个
			return true
		}
		return false
	}
	// 正向
	if dbit.Valid() {
		dbit.index = 0 // 将当前key值指向第一个
		return true
	}
	return false
}

//Key key
func (dbit *goMemDBIt) Key() []byte {
	return []byte(dbit.keys[dbit.index])
}

//Value value
func (dbit *goMemDBIt) Value() []byte {
	value, _ := dbit.goMemDb.Get([]byte(dbit.keys[dbit.index]))
	return value
}

func (dbit *goMemDBIt) ValueCopy() []byte {
	v, _ := dbit.goMemDb.Get([]byte(dbit.keys[dbit.index]))
	value := make([]byte, len(v))
	copy(value, v)
	return value
}

func (dbit *goMemDBIt) Valid() bool {

	if (dbit.goMemDb == nil) && (len(dbit.keys) == 0) {
		return false
	}

	if len(dbit.keys) > dbit.index && dbit.index >= 0 {
		return true
	}
	return false

}

func (dbit *goMemDBIt) Error() error {
	return nil
}

type kv struct{ k, v []byte }
type memBatch struct {
	db     *GoMemDB
	writes []kv
	size   int
}

//NewBatch new
func (db *GoMemDB) NewBatch(sync bool) Batch {
	return &memBatch{db: db}
}

func (b *memBatch) Set(key, value []byte) {
	//println("-b-", string(key)[0:4], common.ToHex(key))
	b.writes = append(b.writes, kv{CopyBytes(key), CopyBytes(value)})
	b.size += len(value)
}

func (b *memBatch) Delete(key []byte) {
	b.writes = append(b.writes, kv{CopyBytes(key), CopyBytes(nil)})
	b.size++
}

func (b *memBatch) Write() error {
	b.db.lock.Lock()
	defer b.db.lock.Unlock()

	for _, kv := range b.writes {
		if kv.v == nil {
			//println("[d]", string(kv.k))
			delete(b.db.db, string(kv.k))
		} else {
			//println("[i]", string(kv.k))
			b.db.db[string(kv.k)] = kv.v
		}
	}
	return nil
}

func (b *memBatch) ValueSize() int {
	return b.size
}

func (b *memBatch) Reset() {
	b.writes = b.writes[:0]
	b.size = 0
}
