package types

import (
	"bytes"
	"encoding/binary"
	"encoding/json"
	"errors"
	"fmt"
	"math/big"
	"reflect"
	"strconv"

	"github.com/aergoio/aergo/v2/internal/enc/base58"
	"github.com/aergoio/aergo/v2/internal/merkle"
	"github.com/golang/protobuf/jsonpb"
	"github.com/minio/sha256-simd"
	"github.com/willf/bloom"
)

const (
	successStatus = iota
	createdStatus
	errorStatus
	recreatedStatus
)

func NewReceipt(contractAddress []byte, status string, jsonRet string) *Receipt {
	return &Receipt{
		ContractAddress: contractAddress[:33],
		Status:          status,
		Ret:             jsonRet,
	}
}

func (r *Receipt) marshalBody(b *bytes.Buffer, isMerkle bool) error {
	l := make([]byte, 8)
	b.Write(r.ContractAddress)
	var status byte
	switch r.Status {
	case "SUCCESS":
		status = successStatus
	case "CREATED":
		status = createdStatus
	case "ERROR":
		status = errorStatus
	case "RECREATED":
		status = recreatedStatus
	default:
		return errors.New("unsupported status in receipt")
	}
	b.WriteByte(status)
	if !isMerkle || status != errorStatus {
		binary.LittleEndian.PutUint32(l[:4], uint32(len(r.Ret)))
		b.Write(l[:4])
		b.WriteString(r.Ret)
	}
	b.Write(r.TxHash)

	binary.LittleEndian.PutUint32(l[:4], uint32(len(r.FeeUsed)))
	b.Write(l[:4])
	b.Write(r.FeeUsed)
	binary.LittleEndian.PutUint32(l[:4], uint32(len(r.CumulativeFeeUsed)))
	b.Write(l[:4])
	b.Write(r.CumulativeFeeUsed)

	if len(r.Bloom) == 0 {
		b.WriteByte(0)
	} else {
		b.WriteByte(1)
		b.Write(r.Bloom)
	}
	binary.LittleEndian.PutUint32(l[:4], uint32(len(r.Events)))
	b.Write(l[:4])

	return nil
}

func (r *Receipt) marshalBodyV2(b *bytes.Buffer, isMerkle bool) error {
	l := make([]byte, 8)
	b.Write(r.ContractAddress)
	var status byte
	switch r.Status {
	case "SUCCESS":
		status = successStatus
	case "CREATED":
		status = createdStatus
	case "ERROR":
		status = errorStatus
	case "RECREATED":
		status = recreatedStatus
	default:
		return errors.New("unsupported status in receipt")
	}
	b.WriteByte(status)
	if !isMerkle || status != errorStatus {
		binary.LittleEndian.PutUint32(l[:4], uint32(len(r.Ret)))
		b.Write(l[:4])
		b.WriteString(r.Ret)
	}
	b.Write(r.TxHash)

	binary.LittleEndian.PutUint32(l[:4], uint32(len(r.FeeUsed)))
	b.Write(l[:4])
	b.Write(r.FeeUsed)
	binary.LittleEndian.PutUint32(l[:4], uint32(len(r.CumulativeFeeUsed)))
	b.Write(l[:4])
	b.Write(r.CumulativeFeeUsed)
	binary.LittleEndian.PutUint64(l[:], r.GasUsed)
	b.Write(l)

	if r.FeeDelegation {
		b.WriteByte(1)
	} else {
		b.WriteByte(0)
	}
	if len(r.Bloom) == 0 {
		b.WriteByte(0)
	} else {
		b.WriteByte(1)
		b.Write(r.Bloom)
	}
	binary.LittleEndian.PutUint32(l[:4], uint32(len(r.Events)))
	b.Write(l[:4])

	return nil
}

func (r *Receipt) marshalStoreBinary() ([]byte, error) {
	var b bytes.Buffer

	err := r.marshalBody(&b, false)
	if err != nil {
		return nil, err
	}
	for _, ev := range r.Events {
		evB, err := ev.marshalStoreBinary(r)
		if err != nil {
			return nil, err
		}
		b.Write(evB)
	}

	return b.Bytes(), nil
}

func (r *Receipt) marshalStoreBinaryV2() ([]byte, error) {
	var b bytes.Buffer

	err := r.marshalBodyV2(&b, false)
	if err != nil {
		return nil, err
	}
	for _, ev := range r.Events {
		evB, err := ev.marshalStoreBinary(r)
		if err != nil {
			return nil, err
		}
		b.Write(evB)
	}

	return b.Bytes(), nil
}

func (r *Receipt) unmarshalBody(data []byte) ([]byte, uint32) {
	r.ContractAddress = data[:33]
	status := data[33]
	switch status {
	case successStatus:
		r.Status = "SUCCESS"
	case createdStatus:
		r.Status = "CREATED"
	case errorStatus:
		r.Status = "ERROR"
	case recreatedStatus:
		r.Status = "RECREATED"
	}
	pos := uint32(34)
	l := binary.LittleEndian.Uint32(data[pos:])
	pos += 4
	r.Ret = string(data[pos : pos+l])
	pos += l
	r.TxHash = data[pos : pos+32]
	pos += 32
	l = binary.LittleEndian.Uint32(data[pos:])
	pos += 4
	r.FeeUsed = data[pos : pos+l]
	pos += l
	l = binary.LittleEndian.Uint32(data[pos:])
	pos += 4
	r.CumulativeFeeUsed = data[pos : pos+l]
	pos += l
	bloomCheck := data[pos]
	pos += 1
	if bloomCheck == 1 {
		r.Bloom = data[pos : pos+BloomBitByte]
		pos += BloomBitByte
	}
	pos += l
	evCount := binary.LittleEndian.Uint32(data[pos:])

	return data[pos+4:], evCount
}

func (r *Receipt) unmarshalBodyV2(data []byte) ([]byte, uint32) {
	r.ContractAddress = data[:33]
	status := data[33]
	switch status {
	case successStatus:
		r.Status = "SUCCESS"
	case createdStatus:
		r.Status = "CREATED"
	case errorStatus:
		r.Status = "ERROR"
	case recreatedStatus:
		r.Status = "RECREATED"
	}
	pos := uint32(34)
	l := binary.LittleEndian.Uint32(data[pos:])
	pos += 4
	r.Ret = string(data[pos : pos+l])
	pos += l
	r.TxHash = data[pos : pos+32]
	pos += 32
	l = binary.LittleEndian.Uint32(data[pos:])
	pos += 4
	r.FeeUsed = data[pos : pos+l]
	pos += l
	l = binary.LittleEndian.Uint32(data[pos:])
	pos += 4
	r.CumulativeFeeUsed = data[pos : pos+l]
	pos += l
	ll := binary.LittleEndian.Uint64(data[pos:])
	r.GasUsed = ll
	pos += 8
	if data[pos] == 1 {
		r.FeeDelegation = true
	}
	pos += 1
	bloomCheck := data[pos]
	pos += 1
	if bloomCheck == 1 {
		r.Bloom = data[pos : pos+BloomBitByte]
		pos += BloomBitByte
	}
	pos += l
	evCount := binary.LittleEndian.Uint32(data[pos:])

	return data[pos+4:], evCount
}

func (r *Receipt) unmarshalStoreBinary(data []byte) ([]byte, error) {
	evData, evCount := r.unmarshalBody(data)

	r.Events = make([]*Event, evCount)
	var err error
	for i := uint32(0); i < evCount; i++ {
		var ev Event
		evData, err = ev.unmarshalStoreBinary(evData, r)
		if err != nil {
			return nil, err
		}
		r.Events[i] = &ev
	}
	return evData, nil
}

func (r *Receipt) unmarshalStoreBinaryV2(data []byte) ([]byte, error) {
	evData, evCount := r.unmarshalBodyV2(data)

	r.Events = make([]*Event, evCount)
	var err error
	for i := uint32(0); i < evCount; i++ {
		var ev Event
		evData, err = ev.unmarshalStoreBinary(evData, r)
		if err != nil {
			return nil, err
		}
		r.Events[i] = &ev
	}
	return evData, nil
}

func (r *Receipt) MarshalBinaryTest() ([]byte, error) {
	return r.marshalStoreBinaryV2()
}

func (r *Receipt) MarshalMerkleBinary() ([]byte, error) {
	var b bytes.Buffer

	err := r.marshalBody(&b, true)
	if err != nil {
		return nil, err
	}

	for _, ev := range r.Events {
		evB, err := ev.MarshalMerkleBinary()
		if err != nil {
			return nil, err
		}
		b.Write(evB)
	}

	return b.Bytes(), nil
}

func (r *Receipt) MarshalMerkleBinaryV2() ([]byte, error) {
	var b bytes.Buffer

	err := r.marshalBodyV2(&b, true)
	if err != nil {
		return nil, err
	}

	for _, ev := range r.Events {
		evB, err := ev.MarshalMerkleBinary()
		if err != nil {
			return nil, err
		}
		b.Write(evB)
	}

	return b.Bytes(), nil
}

func (r *Receipt) UnmarshalBinaryTest(data []byte) error {
	_, err := r.unmarshalStoreBinaryV2(data)
	return err
}

func (r *Receipt) ReadFrom(data []byte) ([]byte, error) {
	evData, evCount := r.unmarshalBody(data)

	r.Events = make([]*Event, evCount)
	var err error
	for i := uint32(0); i < evCount; i++ {
		var ev Event
		evData, err = ev.UnmarshalBinary(evData)
		if err != nil {
			return nil, err
		}
		r.Events[i] = &ev
	}
	return evData, nil
}

func (r *Receipt) MarshalJSONPB(*jsonpb.Marshaler) ([]byte, error) {
	return json.Marshal(r)
}

func (r *Receipt) MarshalJSON() ([]byte, error) {
	var b bytes.Buffer
	b.WriteString(`{"BlockNo":`)
	b.WriteString(fmt.Sprintf("%d", r.BlockNo))
	b.WriteString(`,"BlockHash":"`)
	b.WriteString(base58.Encode(r.BlockHash))
	b.WriteString(`","contractAddress":"`)
	b.WriteString(EncodeAddress(r.ContractAddress))
	b.WriteString(`","status":"`)
	b.WriteString(r.Status)
	if len(r.Ret) == 0 {
		b.WriteString(`","ret": ""`)
	} else if r.Status == "ERROR" {
		js, _ := json.Marshal(r.Ret)
		b.WriteString(`","ret": `)
		b.WriteString(string(js))
	} else {
		b.WriteString(`","ret": `)
		b.WriteString(r.Ret)
	}
	b.WriteString(`,"txHash":"`)
	b.WriteString(base58.Encode(r.TxHash))
	b.WriteString(`","txIndex":`)
	b.WriteString(fmt.Sprintf("%d", r.TxIndex))
	b.WriteString(`,"from":"`)
	b.WriteString(EncodeAddress(r.From))
	b.WriteString(`","to":"`)
	b.WriteString(EncodeAddress(r.To))
	b.WriteString(`","feeUsed":`)
	b.WriteString(new(big.Int).SetBytes(r.FeeUsed).String())
	b.WriteString(`,"gasUsed":`)
	b.WriteString(strconv.FormatUint(r.GasUsed, 10))
	b.WriteString(`,"feeDelegation":`)
	if r.FeeDelegation {
		b.WriteString("true")
	} else {
		b.WriteString("false")
	}
	b.WriteString(`,"events":[`)
	for i, ev := range r.Events {
		if i != 0 {
			b.WriteString(`,`)
		}
		bEv, err := ev.MarshalJSON()
		if err != nil {
			return nil, err
		}
		b.Write(bEv)
	}
	b.WriteString(`]}`)
	return b.Bytes(), nil
}

func (r *Receipt) GetHash() []byte {
	h := sha256.New()
	b, _ := r.MarshalMerkleBinary()
	h.Write(b)
	return h.Sum(nil)
}

func (r *Receipt) BloomFilter(fi *FilterInfo) bool {
	if r.Bloom == nil {
		return false
	}

	var buffer bytes.Buffer
	l := make([]byte, 8)
	binary.BigEndian.PutUint64(l, BloomBitBits)
	buffer.Write(l)
	binary.BigEndian.PutUint64(l, BloomHashKNum)
	buffer.Write(l)
	binary.BigEndian.PutUint64(l, BloomBitBits)
	buffer.Write(l)
	buffer.Write(r.Bloom)

	var bf bloom.BloomFilter
	_, err := bf.ReadFrom(&buffer)
	if err != nil {
		return true
	}

	if bf.Test(fi.ContractAddress) || bf.Test([]byte(fi.EventName)) {
		return true
	}
	return false
}

func (r *Receipt) SetMemoryInfo(blkHash []byte, blkNo BlockNo, txIdx int32) {
	r.BlockNo = blkNo
	r.BlockHash = blkHash
	r.TxIndex = txIdx

	for _, e := range r.Events {
		e.SetMemoryInfo(r, blkHash, blkNo, txIdx)
	}
}

type bloomFilter bloom.BloomFilter

func (bf *bloomFilter) GetHash() []byte {
	h := sha256.New()
	b, _ := ((*bloom.BloomFilter)(bf)).GobEncode()
	h.Write(b)
	return h.Sum(nil)
}

type ReceiptMerkle struct {
	receipt        *Receipt
	blockNo        BlockNo
	hardForkConfig BlockVersionner
}

func (rm *ReceiptMerkle) GetHash() []byte {
	h := sha256.New()
	var b []byte
	if rm.hardForkConfig.IsV2Fork(rm.blockNo) {
		b, _ = rm.receipt.MarshalMerkleBinaryV2()
	} else {
		b, _ = rm.receipt.MarshalMerkleBinary()
	}
	h.Write(b)
	return h.Sum(nil)
}

type Receipts struct {
	bloom          *bloomFilter
	receipts       []*Receipt
	blockNo        BlockNo
	hardForkConfig BlockVersionner
}

func (rs *Receipts) Get() []*Receipt {
	if rs == nil {
		return nil
	}
	return rs.receipts
}

func (rs *Receipts) GetBlockNo() BlockNo {
	if rs == nil {
		return 0
	}
	return rs.blockNo
}

func (rs *Receipts) Set(receipts []*Receipt) {
	rs.receipts = receipts
}

func (rs *Receipts) SetHardFork(hardForkConfig BlockVersionner, blockNo BlockNo) {
	rs.hardForkConfig = hardForkConfig
	rs.blockNo = blockNo
}

const BloomBitByte = 256
const BloomBitBits = BloomBitByte * 8
const BloomHashKNum = 3

func (rs *Receipts) MergeBloom(bf *bloom.BloomFilter) error {
	if rs.bloom == nil {
		rs.bloom = (*bloomFilter)(bloom.New(BloomBitBits, BloomHashKNum))
	}

	return (*bloom.BloomFilter)(rs.bloom).Merge(bf)
}

func (rs *Receipts) BloomFilter(fi *FilterInfo) bool {
	if rs.bloom == nil {
		return false
	}
	bf := (*bloom.BloomFilter)(rs.bloom)
	if bf.Test(fi.ContractAddress) || bf.Test([]byte(fi.EventName)) {
		return true
	}
	return false
}

func (rs *Receipts) MerkleRoot() []byte {
	if rs == nil {
		return merkle.CalculateMerkleRoot(nil)
	}
	rsSize := len(rs.receipts)
	if rs.bloom != nil {
		rsSize++
	}
	mes := make([]merkle.MerkleEntry, rsSize)
	for i, r := range rs.receipts {
		mes[i] = &ReceiptMerkle{r, rs.blockNo, rs.hardForkConfig}
	}
	if rs.bloom != nil {
		mes[rsSize-1] = rs.bloom
	}
	return merkle.CalculateMerkleRoot(mes)
}

func (rs *Receipts) MarshalBinary() ([]byte, error) {
	var b bytes.Buffer
	l := make([]byte, 4)

	if rs.bloom != nil {
		b.WriteByte(1)
		bloomB, err := (*bloom.BloomFilter)(rs.bloom).GobEncode()
		if err != nil {
			return nil, err
		}
		b.Write(bloomB[24:])
	} else {
		b.WriteByte(0)
	}
	binary.LittleEndian.PutUint32(l, uint32(len(rs.receipts)))
	b.Write(l)
	var rB []byte
	var err error
	for _, r := range rs.receipts {
		if rs.hardForkConfig.IsV2Fork(rs.blockNo) {
			rB, err = r.marshalStoreBinaryV2()
		} else {
			rB, err = r.marshalStoreBinary()
		}
		if err != nil {
			return nil, err
		}
		b.Write(rB)
	}

	return b.Bytes(), nil
}

func (rs *Receipts) UnmarshalBinary(data []byte) error {
	checkBloom := data[0]
	pos := 1
	if checkBloom == 1 {
		var buffer bytes.Buffer
		var bf bloom.BloomFilter
		l := make([]byte, 8)
		binary.BigEndian.PutUint64(l, BloomBitBits)
		buffer.Write(l)
		binary.BigEndian.PutUint64(l, BloomHashKNum)
		buffer.Write(l)
		binary.BigEndian.PutUint64(l, BloomBitBits)
		buffer.Write(l)
		buffer.Write(data[pos : pos+BloomBitByte])
		_, err := bf.ReadFrom(&buffer)
		if err != nil {
			return err
		}
		pos += BloomBitByte
		rs.bloom = (*bloomFilter)(&bf)
	}
	rCount := binary.LittleEndian.Uint32(data[pos:])
	pos += 4
	rs.receipts = make([]*Receipt, rCount)
	unread := data[pos:]
	var err error
	for i := uint32(0); i < rCount; i++ {
		var r Receipt
		if rs.hardForkConfig.IsV2Fork(rs.blockNo) {
			unread, err = r.unmarshalStoreBinaryV2(unread)
		} else {
			unread, err = r.unmarshalStoreBinary(unread)
		}
		if err != nil {
			return err
		}
		rs.receipts[i] = &r
	}
	return nil
}

func (ev *Event) marshalCommonBinary(b *bytes.Buffer) {
	l := make([]byte, 4)
	b.Write(ev.ContractAddress)
	binary.LittleEndian.PutUint32(l, uint32(len(ev.EventName)))
	b.Write(l)
	b.WriteString(ev.EventName)

	binary.LittleEndian.PutUint32(l, uint32(len(ev.JsonArgs)))
	b.Write(l)
	b.WriteString(ev.JsonArgs)

	b.Write(ev.TxHash)

	binary.LittleEndian.PutUint32(l, uint32(ev.EventIdx))
	b.Write(l)
}

func (ev *Event) MarshalBinary() ([]byte, error) {
	var b bytes.Buffer
	l := make([]byte, 8)
	ev.marshalCommonBinary(&b)

	b.Write(ev.BlockHash)
	binary.LittleEndian.PutUint64(l[:], ev.BlockNo)
	b.Write(l)
	binary.LittleEndian.PutUint32(l[:4], uint32(ev.TxIndex))
	b.Write(l[:4])
	return b.Bytes(), nil
}

func (ev *Event) marshalStoreBinary(r *Receipt) ([]byte, error) {
	var b bytes.Buffer
	l := make([]byte, 4)
	if bytes.Equal(r.ContractAddress, ev.ContractAddress) {
		b.WriteByte(0)
	} else {
		b.Write(ev.ContractAddress)
	}
	binary.LittleEndian.PutUint32(l, uint32(len(ev.EventName)))
	b.Write(l)
	b.WriteString(ev.EventName)

	binary.LittleEndian.PutUint32(l, uint32(len(ev.JsonArgs)))
	b.Write(l)
	b.WriteString(ev.JsonArgs)

	binary.LittleEndian.PutUint32(l, uint32(ev.EventIdx))
	b.Write(l)
	return b.Bytes(), nil
}

func (ev *Event) unmarshalStoreBinary(data []byte, r *Receipt) ([]byte, error) {
	var pos uint32
	if data[0] == 0 {
		ev.ContractAddress = r.ContractAddress
		pos += 1
	} else {
		ev.ContractAddress = data[:33]
		pos += 33
	}
	l := binary.LittleEndian.Uint32(data[pos:])
	pos += 4
	ev.EventName = string(data[pos : pos+l])
	pos += l

	l = binary.LittleEndian.Uint32(data[pos:])
	pos += 4
	ev.JsonArgs = string(data[pos : pos+l])
	pos += l

	ev.EventIdx = int32(binary.LittleEndian.Uint32(data[pos:]))
	pos += 4

	return data[pos:], nil
}

func (ev *Event) MarshalMerkleBinary() ([]byte, error) {
	var b bytes.Buffer
	ev.marshalCommonBinary(&b)
	return b.Bytes(), nil
}

func (ev *Event) UnmarshalBinary(data []byte) ([]byte, error) {
	pos := uint32(33)
	ev.ContractAddress = data[:pos]

	l := binary.LittleEndian.Uint32(data[33:])
	pos += 4
	ev.EventName = string(data[pos : pos+l])
	pos += l

	l = binary.LittleEndian.Uint32(data[pos:])
	pos += 4
	ev.JsonArgs = string(data[pos : pos+l])
	pos += l

	ev.TxHash = data[pos : pos+32]
	pos += 32

	ev.EventIdx = int32(binary.LittleEndian.Uint32(data[pos:]))
	pos += 4

	ev.BlockHash = data[pos : pos+32]
	pos += 32

	ev.BlockNo = binary.LittleEndian.Uint64(data[pos:])
	pos += 8

	ev.TxIndex = int32(binary.LittleEndian.Uint32(data[pos:]))

	return data[pos+4:], nil
}

func (ev *Event) MarshalJSON() ([]byte, error) {
	var b bytes.Buffer
	b.WriteString(`{"contractAddress":"`)
	b.WriteString(EncodeAddress(ev.ContractAddress))
	b.WriteString(`","eventName":"`)
	b.WriteString(ev.EventName)
	b.WriteString(`","Args":`)
	b.WriteString(ev.JsonArgs)
	b.WriteString(`,"txHash":"`)
	b.WriteString(base58.Encode(ev.TxHash))
	b.WriteString(`","EventIdx":`)
	b.WriteString(fmt.Sprintf("%d", ev.EventIdx))
	b.WriteString(`,"BlockHash":"`)
	b.WriteString(base58.Encode(ev.BlockHash))
	b.WriteString(`","BlockNo":`)
	b.WriteString(fmt.Sprintf("%d", ev.BlockNo))
	b.WriteString(`,"TxIndex":`)
	b.WriteString(fmt.Sprintf("%d", ev.TxIndex))
	b.WriteString(`}`)
	return b.Bytes(), nil
}

func (ev *Event) SetMemoryInfo(receipt *Receipt, blkHash []byte, blkNo BlockNo, txIdx int32) {
	ev.TxHash = receipt.TxHash
	ev.TxIndex = txIdx
	ev.BlockHash = blkHash
	ev.BlockNo = blkNo
}

func checkSameArray(value []interface{}, check []interface{}) bool {
	if len(value) != len(check) {
		return false
	}
	for i, v := range value {
		if checkValue(v, check[i]) == false {
			return false
		}
	}
	return true
}

func checkSameMap(value map[string]interface{}, check map[string]interface{}) bool {
	if len(value) != len(check) {
		return false
	}
	for k, v := range value {
		if checkValue(v, check[k]) == false {
			return false
		}
	}
	return true
}

func checkValue(value interface{}, check interface{}) bool {
	if reflect.TypeOf(value) != reflect.TypeOf(check) {
		return false
	}
	switch value.(type) {
	case string:
		if value.(string) != check.(string) {
			return false
		}
	case float64:
		if value.(float64) != check.(float64) {
			return false
		}
	case bool:
		if value.(bool) != check.(bool) {
			return false
		}
	case json.Number:
		if value.(json.Number) != check.(json.Number) {
			return false
		}
	case nil:
		return true
	case []interface{}:
		return checkSameArray(value.([]interface{}), check.([]interface{}))
	case map[string]interface{}:
		return checkSameMap(value.(map[string]interface{}), check.(map[string]interface{}))
	default:
		return false
	}

	return true
}

func (ev *Event) Filter(filter *FilterInfo, argFilter []ArgFilter) bool {
	if filter.ContractAddress != nil && !bytes.Equal(ev.ContractAddress, filter.ContractAddress) {
		return false
	}
	if len(filter.EventName) != 0 && ev.EventName != filter.EventName {
		return false
	}
	if argFilter != nil {
		var args []interface{}
		err := json.Unmarshal([]byte(ev.JsonArgs), &args)
		if err != nil {
			return false
		}
		argLen := len(args)
		for _, filter := range argFilter {
			if filter.argNo >= argLen {
				return false
			}
			value := args[filter.argNo]
			check := filter.value
			if checkValue(value, check) == false {
				return false
			}
		}
	}
	ev.ContractAddress = AddressOrigin(ev.ContractAddress)
	return true
}

type ArgFilter struct {
	argNo int
	value interface{}
}

const MAXBLOCKRANGE = 10000
const padprefix = 0x80

func AddressPadding(addr []byte) []byte {
	id := make([]byte, AddressLength)
	id[0] = padprefix
	copy(id[1:], addr)
	return id
}
func AddressOrigin(addr []byte) []byte {
	if addr[0] == padprefix {
		addr = addr[1:bytes.IndexByte(addr, 0)]
	}
	return addr
}

func (fi *FilterInfo) ValidateCheck(to uint64) error {
	if fi.ContractAddress == nil {
		return errors.New("invalid contractAddress:" + string(fi.ContractAddress))
	}
	if len(fi.ContractAddress) < AddressLength {
		fi.ContractAddress = AddressPadding(fi.ContractAddress)
	} else if len(fi.ContractAddress) != AddressLength {
		return errors.New("invalid contractAddress:" + string(fi.ContractAddress))
	}
	if fi.RecentBlockCnt > 0 {
		if fi.RecentBlockCnt > MAXBLOCKRANGE {
			return errors.New(fmt.Sprintf("too large value at recentBlockCnt %d (max %d)",
				fi.RecentBlockCnt, MAXBLOCKRANGE))
		}

	} else {
		if fi.Blockfrom+MAXBLOCKRANGE < to {
			return errors.New(fmt.Sprintf("too large block range(max %d) from %d to %d",
				MAXBLOCKRANGE, fi.Blockfrom, to))
		}
	}
	return nil
}

func (fi *FilterInfo) GetExArgFilter() ([]ArgFilter, error) {
	if len(fi.ArgFilter) == 0 {
		return nil, nil
	}

	var argMap map[string]interface{}
	err := json.Unmarshal(fi.ArgFilter, &argMap)
	if err != nil {
		return nil, errors.New("invalid json format:" + err.Error())
	}

	argFilter := make([]ArgFilter, len(argMap))
	i := 0
	for key, value := range argMap {
		idx, err := strconv.ParseInt(key, 10, 32)
		if err != nil || idx < 0 {
			return nil, errors.New("invalid argument number:" + key)
		}
		argFilter[i].argNo = int(idx)
		argFilter[i].value = value
		i++
	}
	if i > 0 {
		return argFilter[:i], nil
	}
	return nil, nil
}
