package multiaddr

import (
	
	
)

// Action is an enum modelling all possible filter actions.
type Action int32

const (
	ActionNone Action = iota // zero value.
	ActionAccept
	ActionDeny
)

type filterEntry struct {
	f      net.IPNet
	action Action
}

// Filters is a structure representing a collection of accept/deny
// net.IPNet filters, together with the DefaultAction flag, which
// represents the default filter policy.
//
// Note that the last policy added to the Filters is authoritative.
type Filters struct {
	DefaultAction Action

	mu      sync.RWMutex
	filters []*filterEntry
}

// NewFilters constructs and returns a new set of net.IPNet filters.
// By default, the new filter accepts all addresses.
func () *Filters {
	return &Filters{
		DefaultAction: ActionAccept,
		filters:       make([]*filterEntry, 0),
	}
}

func ( *Filters) ( net.IPNet) (int, *filterEntry) {
	 := .String()
	for ,  := range .filters {
		if .f.String() ==  {
			return , 
		}
	}
	return -1, nil
}

// AddFilter adds a rule to the Filters set, enforcing the desired action for
// the provided IPNet mask.
func ( *Filters) ( net.IPNet,  Action) {
	.mu.Lock()
	defer .mu.Unlock()

	if ,  := .find();  != nil {
		.action = 
	} else {
		.filters = append(.filters, &filterEntry{, })
	}
}

// RemoveLiteral removes the first filter associated with the supplied IPNet,
// returning whether something was removed or not. It makes no distinction
// between whether the rule is an accept or a deny.
func ( *Filters) ( net.IPNet) ( bool) {
	.mu.Lock()
	defer .mu.Unlock()

	if ,  := .find();  != -1 {
		.filters = append(.filters[:], .filters[+1:]...)
		return true
	}
	return false
}

// AddrBlocked parses a ma.Multiaddr and, if a valid netip is found, it applies the
// Filter set rules, returning true if the given address should be denied, and false if
// the given address is accepted.
//
// If a parsing error occurs, or no filter matches, the Filters'
// default is returned.
//
// TODO: currently, the last filter to match wins always, but it shouldn't be that way.
//
//	Instead, the highest-specific last filter should win; that way more specific filters
//	override more general ones.
func ( *Filters) ( Multiaddr) ( bool) {
	var (
		 net.IP
		 bool
	)

	ForEach(, func( Component) bool {
		switch .Protocol().Code {
		case P_IP6ZONE:
			return true
		case P_IP6, P_IP4:
			 = true
			 = net.IP(.RawValue())
			return false
		default:
			return false
		}
	})

	if ! {
		return .DefaultAction == ActionDeny
	}

	.mu.RLock()
	defer .mu.RUnlock()

	 := .DefaultAction
	for ,  := range .filters {
		if .f.Contains() {
			 = .action
		}
	}

	return  == ActionDeny
}

func ( *Filters) ( net.IPNet) ( Action,  bool) {
	if ,  := .find();  != nil {
		return .action, true
	}
	return ActionNone, false
}

// FiltersForAction returns the filters associated with the indicated action.
func ( *Filters) ( Action) ( []net.IPNet) {
	.mu.RLock()
	defer .mu.RUnlock()

	for ,  := range .filters {
		if .action ==  {
			 = append(, .f)
		}
	}
	return 
}