// Code generated by go run ./hardfork_gen/main.go hardfork.json hardfork_gen.go; DO NOT EDIT.

package config

import (
	"fmt"
	"reflect"

	"github.com/aergoio/aergo/v2/types"
)

var (
	MainNetHardforkConfig = &HardforkConfig{
		V2: types.BlockNo(19611555),
		V3: types.BlockNo(111499715),
		V4: types.BlockNo(173677571),
		V5: types.BlockNo(196150000),
	}
	TestNetHardforkConfig = &HardforkConfig{
		V2: types.BlockNo(18714241),
		V3: types.BlockNo(100360545),
		V4: types.BlockNo(140020000),
		V5: types.BlockNo(155300000),
	}
	AllEnabledHardforkConfig = &HardforkConfig{
		V2: types.BlockNo(0),
		V3: types.BlockNo(0),
		V4: types.BlockNo(0),
		V5: types.BlockNo(0),
	}
)

const hardforkConfigTmpl = `[hardfork]
v2 = "{{.Hardfork.V2}}"
v3 = "{{.Hardfork.V3}}"
v4 = "{{.Hardfork.V4}}"
v5 = "{{.Hardfork.V5}}"
`

type HardforkConfig struct {
	V2 types.BlockNo `mapstructure:"v2" description:"a block number of the hardfork version 2"`
	V3 types.BlockNo `mapstructure:"v3" description:"a block number of the hardfork version 3"`
	V4 types.BlockNo `mapstructure:"v4" description:"a block number of the hardfork version 4"`
	V5 types.BlockNo `mapstructure:"v5" description:"a block number of the hardfork version 5"`
}

type HardforkDbConfig map[string]types.BlockNo

func (dc HardforkDbConfig) FixDbConfig(hConfig HardforkConfig) HardforkDbConfig {
	v := reflect.ValueOf(hConfig)
	for i := 0; i < v.NumField(); i++ {
		k := v.Type().Field(i).Name
		if _, exist := dc[k]; !exist {
			dc[k] = hConfig.Height(k)
		}
	}
	return dc
}


func (c *HardforkConfig) IsV2Fork(h types.BlockNo) bool {
	return isFork(c.V2, h)
}

func (c *HardforkConfig) IsV3Fork(h types.BlockNo) bool {
	return isFork(c.V3, h)
}

func (c *HardforkConfig) IsV4Fork(h types.BlockNo) bool {
	return isFork(c.V4, h)
}

func (c *HardforkConfig) IsV5Fork(h types.BlockNo) bool {
	return isFork(c.V5, h)
}

func (c *HardforkConfig) CheckCompatibility(dbCfg HardforkDbConfig, h types.BlockNo) error {
	if err := c.validate(); err != nil {
		return err
	}
	if (isFork(c.V2, h) || isFork(dbCfg["V2"], h)) && c.V2 != dbCfg["V2"] {
		return newForkError("V2", h, c.V2, dbCfg["V2"])
	}
	if (isFork(c.V3, h) || isFork(dbCfg["V3"], h)) && c.V3 != dbCfg["V3"] {
		return newForkError("V3", h, c.V3, dbCfg["V3"])
	}
	if (isFork(c.V4, h) || isFork(dbCfg["V4"], h)) && c.V4 != dbCfg["V4"] {
		return newForkError("V4", h, c.V4, dbCfg["V4"])
	}
	if (isFork(c.V5, h) || isFork(dbCfg["V5"], h)) && c.V5 != dbCfg["V5"] {
		return newForkError("V5", h, c.V5, dbCfg["V5"])
	}
	return checkOlderNode(5, h, dbCfg)
}

func (c *HardforkConfig) Version(h types.BlockNo) int32 {
	v := reflect.ValueOf(*c)
	for i := v.NumField() - 1; i >= 0; i-- {
		if v.Field(i).Uint() <= h {
			return int32(i + 2)
		}
	}
	return int32(0)
}

func (c *HardforkConfig) Height(verStr string) types.BlockNo {
	v := reflect.ValueOf(c)
	f := reflect.Indirect(v).FieldByName(verStr)
	return types.BlockNo(f.Uint())
}

func (c *HardforkConfig) validate() error {
	prev := uint64(0)
	v := reflect.ValueOf(*c)
	for i := 0; i < v.NumField(); i++ {
		curr := v.Field(i).Uint()
		if prev > curr {
			return fmt.Errorf("version %d has a lower block number: %d, %d(v%d)", i+2, curr, prev, i+1)
		}
		prev = curr
	}
	return nil
}
