package vm

import (
	"bytes"
	"go-ethereum-advance/common"
	"sort"
)

var TempRWSet = NewCacheSet()


type RWRecord struct {
	ReadRecord  map[common.Hash][]byte
	WriteRecord map[common.Hash][]byte
	level   int
}

func NewRWRecord() *RWRecord {
	return &RWRecord{
		ReadRecord: make(map[common.Hash][]byte),
		WriteRecord: make(map[common.Hash][]byte),
	}
}

func (rw *RWRecord) Level() int {
	return rw.level
}

func (rw *RWRecord) SetReadRecord(rKey common.Hash,rValue []byte) {
	rw.ReadRecord[rKey] = rValue
}

func (rw *RWRecord) SetWriteRecord(wKey common.Hash,wValue []byte)  {
	rw.WriteRecord[wKey] = wValue
}

func (rw *RWRecord) SetCurrentRecordLevel(level int) {
	rw.level = level
}

type CacheSet struct {
	cache  map[common.Hash]*RWRecord
	Order  []common.Hash
	maxLevel int
}

func NewCacheSet() *CacheSet {
	return &CacheSet{
		cache: make(map[common.Hash]*RWRecord),
		Order: make([]common.Hash,0),
	}
}

func (c *CacheSet) GetMaxLevel() int {
	return c.maxLevel
}

func (c *CacheSet) SetCache(txHash common.Hash,record *RWRecord)  {
	 _,ok := c.cache[txHash]
	if !ok {
		c.cache[txHash] = record
		c.Order = append(c.Order,txHash)
	}
}


func (c *CacheSet) SetCacheWithReadRecord(txHash common.Hash,key common.Hash,value []byte,level int)  {
	record,ok := c.cache[txHash]
	if !ok {
		record = NewRWRecord()
		c.Order = append(c.Order,txHash)
	}
	record.SetReadRecord(key,value)
	record.SetCurrentRecordLevel(level)
	if c.maxLevel < level {
		c.maxLevel = level
	}
	c.SetCache(txHash,record)
}

func (c *CacheSet) SetCacheWithWriteRecord(txHash common.Hash,key common.Hash,value []byte,level int)  {
	record,ok := c.cache[txHash]
	if !ok {
		record = NewRWRecord()
		c.Order = append(c.Order,txHash)
	}
	record.SetWriteRecord(key,value)
	record.SetCurrentRecordLevel(level)
	if c.maxLevel < level {
		c.maxLevel = level
	}
	c.SetCache(txHash,record)
}

func (c *CacheSet) GetRecordsWithLevel(level int) *CacheSet {
	newC := NewCacheSet()
	for txHash,record := range c.cache{
		if record.Level() == level {
			newC.SetCache(txHash,record)
		}
	}
	//按照交易哈希进行排序
	sort.Sort(newC)
	return newC
}

func (c *CacheSet) GetRecordWithTxHash(txHash common.Hash) (*RWRecord,bool) {
	v,ok := c.cache[txHash]
	return  v,ok
}


func (c *CacheSet) Len() int {
	return len(c.Order)
}

func (c *CacheSet) Less(i,j int) bool {
	iItem := c.Order[i]
	jItem := c.Order[j]
	//0 if a==b, -1 if a < b, and +1 if a > b.
	v := bytes.Compare(iItem.Bytes(),jItem.Bytes())
	if v == -1 {
		return true
	}
	return false
}

func (c *CacheSet) Swap(i,j int) {
	c.Order[i],c.Order[j] = c.Order[j],c.Order[i]
}