package transcut

import (
	"go-ethereum-advance/common"
	"go-ethereum-advance/core/types"
	"sync"
)

//type ContractItem interface {
//	SetElement(txHash common.Hash,addr common.Address)
//	GetKey()  common.Hash
//	UpdateRecord(addr string)
//	GetRecordMarkValue(addr string) uint32
//	GetAddress() common.Address
//}
//
//type TransactionMarkMap struct {
//	tsMarkMap map[common.Hash]*list.Element
//	tsList    *list.List
//}
//
//func NewTransactionMarkMap() *TransactionMarkMap {
//	return &TransactionMarkMap{
//		tsMarkMap: make(map[common.Hash]*list.Element),
//		tsList: list.New(),
//	}
//}
//
///**批次交易的标记记录**/
//func (t *TransactionMarkMap) Exists(data ContractItem) bool {
//	_,exist := t.tsMarkMap[data.GetKey()]
//	return exist
//}
//
///**向标记记录里面添加数据项**/
//func (t *TransactionMarkMap) Push(data ContractItem) {
//	ele := t.tsList.PushBack(data)
//	t.tsMarkMap[data.GetKey()] = ele
//}
//
///**向标记记录里面删除数据项**/
//func (t *TransactionMarkMap) Remove(data ContractItem)  {
//	t.tsList.Remove(t.tsMarkMap[data.GetKey()])
//	delete(t.tsMarkMap,data.GetKey())
//}
//
//func (t *TransactionMarkMap) CleanUp() {
//	t.tsList= list.New()
//	t.tsMarkMap = make(map[common.Hash]*list.Element)
//}
//
//func (t *TransactionMarkMap) Size() int {
//	return t.tsList.Len()
//}
//
//func (t *TransactionMarkMap) Walk(cb func(data ContractItem)) {
//	for ele := t.tsList.Front();ele != nil;ele = ele.Next() {
//		cb(ele.Value.(ContractItem))
//	}
//}
//
//type Element struct {
//	txHash   common.Hash
//	address  common.Address
//	record   map[string]uint32
//	lock     sync.RWMutex
//}
//
//func NewElement() *Element {
//	return &Element{
//		record: make(map[string]uint32),
//	}
//}
//
//func (e *Element) GetKey() common.Hash {
//	txData := e.txHash.Bytes()
//	addData := e.address.Bytes()
//	data := BytesCombine(txData,addData)
//	return common.BytesToHash(data)
//}
//
//func (e *Element) GetAddress() common.Address{
//	return e.address
//}
//
//func BytesCombine(pBytes ...[]byte) []byte {
//	length := len(pBytes)
//	s := make([][]byte,length)
//	for ind :=0;ind< length;ind++ {
//		s[ind] = pBytes[ind]
//	}
//	sep := []byte("")
//	return bytes.Join(s,sep)
//}
//
///**设置值**/
//func (e *Element) SetElement(txHash common.Hash,addr common.Address)  {
//	e.txHash = txHash
//	e.address = addr
//}
//
///**更新合约地址下的标记数值**/
//func (e *Element) UpdateRecord(addr string)  {
//	e.lock.Lock()
//	defer e.lock.Unlock()
//	value,ok := e.record[addr]
//	if ok {
//		value++
//	}else {
//		value = 1
//	}
//	e.record[addr] = value
//}
//
///**获取对应合约地址下的标记数值**/
//func (e *Element) GetRecordMarkValue(addr string) uint32 {
//	e.lock.RLock()
//	defer e.lock.RUnlock()
//	value,ok := e.record[addr]
//	if ok {
//		return value
//	}
//	return 0
//}

/**from的标记**/
type Item struct {
	tx    *types.Transaction
	mark  uint32
}

type FromMarkCache struct {
	fromCache  map[common.Address][]*Item
	toCache    map[common.Address]struct{}
	maxLevel   uint32
	lock       sync.RWMutex
}

func NewFromMarkCache() *FromMarkCache{
	return &FromMarkCache{
		fromCache: make(map[common.Address][]*Item),
		toCache: make(map[common.Address]struct{}),
	}
}

/**放入到标记档中标记无需设置
	0x0001 -> 0x0002  0
	0x0001 -> 0x0003  1
	0x0004 -> 0x0001  2
-------------------------------
	0x0001 -> 0x0002  0
	0x0002 -> 0x0003  1
      0x0001 -> 0x0004  2
-------------------------------
	0x0001 -> 0x0002  0
      0x0003 -> 0x0005  0
	0x0004 -> 0x0006  0
	0x0002 -> 0x0003  1
**/
func (f *FromMarkCache) SetMarkCache(addr common.Address,data *Item) {
	f.lock.Lock()
	defer f.lock.Unlock()
	v,ok := f.fromCache[addr]
	dataTo := data.tx.To()
	if ok {
		data.mark = f.maxLevel+1
		f.maxLevel = data.mark
		v = append(v,data)
		f.toCache[*dataTo] = struct{}{}
	}else {
		v = make([]*Item,0)
		//如果交易的from不在cache中
		//1.需要判断to是否在以前交易的from中
		//2.需要判断to是否在以前交易的to中
		//3.如果都没有就则标记应为0
		_,ok = f.fromCache[*dataTo]
		if ok {
			data.mark = f.maxLevel+1
			f.maxLevel = data.mark
			f.toCache[*dataTo] = struct{}{}
		}else {
			_,ok = f.toCache[*dataTo]
			if ok {
				data.mark = f.maxLevel+1
				f.maxLevel = data.mark
			}
			f.toCache[*dataTo] = struct{}{}
		}
		v = append(v,data)
	}
	f.fromCache[addr] = v
}

/**找到某个层级的所有交易**/
func (f *FromMarkCache) GetLevelTxsWithMark(index uint32) []*types.Transaction {
	f.lock.RLock()
	defer f.lock.RUnlock()
	arr := make([]*types.Transaction,0)
	for _,v := range f.fromCache{
		for _,data := range v{
			if data.mark == index {
				arr = append(arr,data.tx)
			}
		}
	}
	return arr
}


func (f *FromMarkCache) GetMaxLevel() uint32 {
	return f.maxLevel+1
}

