func newPortRange(targetPortRange []messages.PortRange) (portRanges []models.PortRange, err error) {
	portRanges = make([]models.PortRange, len(targetPortRange))
	for i, r := range targetPortRange {
		if r.LowerPort == nil {
			log.Warn("lower port is mandatory for port-range data.")
			errMsg := fmt.Sprintf("%+v: lower port is mandatory for port-range data.", models.ValidationError)
			return nil, errors.New(errMsg)
		}
		if r.UpperPort == nil {
			r.UpperPort = r.LowerPort
		}
		portRanges[i] = models.NewPortRange(*r.LowerPort, *r.UpperPort)
	}
	return
}
/*
Parse the 'targetPortRange'/'sourcePortRange' field in a mitigationScope and return a list of PortRange objects.
package controllers
import (
	"errors"
	"strings"
	"time"
	"reflect"
	"net/http"
	"fmt"
	"net"
	"github.com/nttdots/go-dots/dots_common/messages"
	"github.com/nttdots/go-dots/dots_server/models"
	"github.com/nttdots/go-dots/dots_server/models/data"
	"github.com/nttdots/go-dots/libcoap"
	log "github.com/sirupsen/logrus"
	common "github.com/nttdots/go-dots/dots_common"
	types "github.com/nttdots/go-dots/dots_common/types/data"
	dots_config "github.com/nttdots/go-dots/dots_server/config"
	data_controllers "github.com/nttdots/go-dots/dots_server/controllers/data"
)
type MitigationRequest struct {
	Controller
}
func (m *MitigationRequest) HandleGet(request Request, customer *models.Customer) (res Response, err error) {
	log.WithField("request", request).Debug("[GET] receive message")
	var errMessage string
	_, cuid, mid, err := messages.ParseURIPath(request.PathInfo)
	if err != nil {
		errMessage = fmt.Sprintf("Failed to parse Uri-Path, error: %s", err)
		log.Warnf(errMessage)
		res = Response{
			Type: common.NonConfirmable,
			Code: common.BadRequest,
			Body: errMessage,
		}
		return res, nil
	}
	if cuid == "" {
		errMessage = "Missing required Uri-Path Parameter: cuid"
		log.Warn(errMessage)
		res = Response{
			Type: common.NonConfirmable,
			Code: common.BadRequest,
			Body: errMessage,
		}
		return
	}
	var mpp []mpPair
	mpp, err = loadMitigations(customer, cuid, mid, request.Queries)
	if err != nil {
		log.WithError(err).Error("loadMitigation failed.")
		return
	}
	scopes := make([]messages.ScopeStatus, 0)
	for _, mp := range mpp {
		if mp.mitigation.Lifetime == 0 {
			continue
		}
		var startedAt int64
		var bytesDropped, pktsDropped, bpsDropped, ppsDropped int
		log.WithField("protection", mp.protection).Debug("Protection: ")
		if mp.protection != nil {
			startedAt = mp.protection.StartedAt().Unix()
			bytesDropped = mp.protection.DroppedDataInfo().BytesDropped()
			bpsDropped = mp.protection.DroppedDataInfo().BpsDropped()
			pktsDropped = mp.protection.DroppedDataInfo().PacketDropped()
			ppsDropped = mp.protection.DroppedDataInfo().PpsDropped()
		}
		scopeStates := messages.ScopeStatus {
			MitigationId: mp.mitigation.MitigationId,
			MitigationStart: uint64(startedAt),
			Lifetime: mp.mitigation.Lifetime,
			Status: mp.mitigation.Status,
			TriggerMitigation: mp.mitigation.TriggerMitigation,
			AliasName: mp.mitigation.AliasName.List(),
			FQDN: mp.mitigation.FQDN.List(),
			URI: mp.mitigation.URI.List(),
			BytesDropped: bytesDropped,
			BpsDropped: bpsDropped,
			PktsDropped: pktsDropped,
			PpsDropped: ppsDropped }
		scopeStates.TargetProtocol = make([]int, 0, len(mp.mitigation.TargetProtocol))
		for k := range mp.mitigation.TargetProtocol {
			scopeStates.TargetProtocol = append(scopeStates.TargetProtocol, k)
		}
		scopeStates.TargetPrefix = make([]string, 0, len(mp.mitigation.TargetPrefix))
		scopeStates.TargetPortRange = make([]messages.PortRangeResponse, 0, len(mp.mitigation.TargetPortRange))
		for _, item := range mp.mitigation.TargetPrefix {
			scopeStates.TargetPrefix = append(scopeStates.TargetPrefix, item.String())
		}
		for _, item := range mp.mitigation.TargetPortRange {
			portRange := messages.PortRangeResponse{LowerPort: item.LowerPort, UpperPort: item.UpperPort}
			scopeStates.TargetPortRange = append(scopeStates.TargetPortRange, portRange)
		}
		scopeStates.SourcePrefix = make([]string, 0, len(mp.mitigation.SourcePrefix))
		scopeStates.SourcePortRange = make([]messages.PortRangeResponse, 0, len(mp.mitigation.SourcePortRange))
		scopeStates.SourceICMPTypeRange = make([]messages.ICMPTypeRangeResponse, 0, len(mp.mitigation.SourceICMPTypeRange))
		for _, item := range mp.mitigation.SourcePrefix {
			scopeStates.SourcePrefix = append(scopeStates.SourcePrefix, item.String())
		}
		for _, item := range mp.mitigation.SourcePortRange {
			portRange := messages.PortRangeResponse{LowerPort: item.LowerPort, UpperPort: item.UpperPort}
			scopeStates.SourcePortRange = append(scopeStates.SourcePortRange, portRange)
		}
		for _, item := range mp.mitigation.SourceICMPTypeRange {
			typeRange := messages.ICMPTypeRangeResponse{LowerType: item.LowerType, UpperType: item.UpperType}
			scopeStates.SourceICMPTypeRange = append(scopeStates.SourceICMPTypeRange, typeRange)
		}
		scopeStates.AclList = make([]messages.ACL, 0, len(mp.mitigation.ControlFilteringList))
		for _, item := range mp.mitigation.ControlFilteringList {
			aclList := messages.ACL{AclName: item.ACLName, ActivationType: item.ActivationType}
			scopeStates.AclList = append(scopeStates.AclList, aclList)
		}
		scopeStates.TotalTraffic = convertToTelemetryTrafficResponse(mp.mitigation.TelemetryTotalTraffic)
		scopeStates.TotalAttackTraffic = convertToTelemetryTrafficResponse(mp.mitigation.TelemetryTotalAttackTraffic)
		if !reflect.DeepEqual(models.GetModelsTelemetryTotalAttackConnection(&mp.mitigation.TelemetryTotalAttackConnection), models.GetModelsTelemetryTotalAttackConnection(nil)) {
			scopeStates.TotalAttackConnection = convertToTelemetryTotalAttackConnectionResponse(mp.mitigation.TelemetryTotalAttackConnection)
		} else {
			scopeStates.TotalAttackConnection = nil
		}
		scopeStates.AttackDetail = convertToTelemetryAttackDetailResponse(mp.mitigation.TelemetryAttackDetail)
		scopes = append(scopes, scopeStates)
	}
	if len(scopes) == 0 {
		if mid != nil {
			if len(request.Queries) > 0 {
				errMessage = fmt.Sprintf("Not found any mitigation with cuid: %s, mid: %v, queries: %+v", cuid, *mid, request.Queries)
			} else {
				errMessage = fmt.Sprintf("Not found any mitigation with cuid: %s, mid: %v", cuid, *mid)
			}
		} else {
			if len(request.Queries) > 0 {
				errMessage = fmt.Sprintf("Not found any mitigations with cuid: %s, queries: %+v", cuid, request.Queries)
			} else {
				errMessage = fmt.Sprintf("Not found any mitigations with cuid: %s", cuid)
			}
		}
		log.Error(errMessage)
		res = Response{
			Type: common.NonConfirmable,
			Code: common.NotFound,
			Body: errMessage,
		}
		return
	}
	res = Response{
		Type: common.NonConfirmable,
		Code: common.Content,
		Body: messages.MitigationResponse { MitigationScope: messages.MitigationScopeStatus { Scopes: scopes }},
	}
	return
}
func (m *MitigationRequest) HandlePut(request Request, customer *models.Customer) (res Response, err error) {
	log.WithField("request", request).Debug("HandlePut")
	var errorMessage string
	if request.Body == nil {
		errorMessage = "Request body must be provided for PUT method"
		log.Warn(errorMessage)
		res = Response {
			Type: common.NonConfirmable,
			Code: common.BadRequest,
			Body: errorMessage,
		}
		return
	}
	body := request.Body.(*messages.MitigationRequest)
	log.WithField("message", body.String()).Debug("[PUT] receive message")
	cdid, cuid, mid, err := messages.ParseURIPath(request.PathInfo)
	if err != nil {
		errorMessage = fmt.Sprintf("Failed to parse Uri-Path, error: %s", err)
		log.Warn(errorMessage)
		goto ResponseNG
	}
	if  mid == nil || cuid == "" {
		errorMessage = "Missing required Uri-Path Parameter(cuid, mid)."
		log.Warn(errorMessage)
		goto ResponseNG
	}
	if len(body.MitigationScope.Scopes) != 1  {
		errorMessage = "Request body must contain only one scope"
		log.Warn(errorMessage)
		goto ResponseNG
	} else {
		if *mid == 0 {
			mitigations, err := loadMitigations(customer, cuid, nil, nil)
			if err != nil {
				log.WithError(err).Error("Mitigations load error.")
				return Response{}, err
			}
			for _, mitigation := range mitigations {
				if mitigation.mitigation.IsActive() {
					errorMessage = fmt.Sprintf ("The mitigation request (mid=%+v) is not accepted in non-peace time because the mitigation (mid=%+v) is active",
												*mid, mitigation.mitigation.MitigationId)
					log.Warn(errorMessage)
					goto ResponseNG
				}
			}
			for _, mitigation := range mitigations {
				if !mitigation.mitigation.IsActive() && mitigation.mitigation.TriggerMitigation == false {
					log.Debugf("Remove inactive mitigation request: mid=%+v", mitigation.mitigation.MitigationId)
					UpdateMitigationStatus(customer.Id, body.EffectiveClientIdentifier(),
						mitigation.mitigation.MitigationId, mitigation.mitigation.MitigationScopeId, models.Terminated, true)
				}
			}
		}
		if body.EffectiveClientIdentifier() != "" || body.EffectiveClientDomainIdentifier() != "" || body.EffectiveMitigationId() != nil {
			errorMessage = "Client Identifier, Client Domain Identifier and Mitigation Id are forbidden in body request"
			log.Warn(errorMessage)
			goto ResponseNG
		}
		body.UpdateClientIdentifier(cuid)
		body.UpdateClientDomainIdentifier(cdid)
		body.UpdateMitigationId(mid)
		var currentScope *models.MitigationScope
		currentScope, err = models.GetMitigationScope(customer.Id, body.EffectiveClientIdentifier(), *mid, models.AnyMitigationScopeId)
		if err != nil {
			log.WithError(err).Error("MitigationScope load error.")
			return Response{}, err
		}
		if currentScope != nil && currentScope.Lifetime == 0 {
			currentScope = nil
		}
		isIfMatchOption := false
		var indexIfMatch int
		for i:=0; i<len(request.Options); i++ {
			if request.Options[i].Key == libcoap.OptionIfMatch {
				isIfMatchOption = true
				indexIfMatch = i
				break;
			}
		}
		if isIfMatchOption {
			log.Debug("Handle efficacy update.")
			valid, errMessage := validateForEfficacyUpdate(request.Options[indexIfMatch].Value, customer, body, currentScope)
			errorMessage = errMessage
			if !valid {
				goto ResponseNG
			}
		}
		var conflictInfo *models.ConflictInformation
		scope := body.MitigationScope.Scopes[0]
		if !isIfMatchOption && scope.SourcePrefix != nil {
			log.Debug("Handle Signal Channel Call Home")
			valid, errMessage := validateForCallHome(customer, scope)
			errorMessage = errMessage
			if !valid {
				goto ResponseNG
			}
			isConflict, err := CheckConfictWithDataChannelAcceptList(customer, cuid, scope.SourcePrefix)
			if err != nil {
				log.Errorf("Failed to check conflict with data channel acl accept list. Error: %+v", err)
				return Response{}, err
			}
			if isConflict {
				log.Error("Existed data channel acl accept list")
				conflictInfo = &models.ConflictInformation {
					ConflictCause:  models.WHITELIST_ACL_COLLISION,
					ConflictScope:  nil,
				}
				goto ResponseConflict
			}
		} else if scope.SourcePrefix == nil && (scope.SourcePortRange != nil || scope.SourceICMPTypeRange != nil) {
			errorMessage = fmt.Sprintf("The signal channel MUST NOT contain 'source-port-range' or 'source-icmp-type-range'")
			goto ResponseNG
		}
		if !isIfMatchOption && scope.AclList != nil && len(scope.AclList) != 0 {
			log.Debugf("Handle Signal Channel Control Filtering")
			if currentScope != nil {
				errorMessage = "A new 'mid' MUST be used"
				log.Error(errorMessage)
				goto ResponseNG
			}
			res, err := HandleControlFiltering(customer, cuid, mid, scope.AclList)
			if err != nil {
				log.Error("Failed to Handle Control Filtering.")
				return Response{}, err
			}
			if res != nil { return *res, nil }
		} else if !isIfMatchOption && currentScope != nil {
			log.Debugf("Handle refresh the current mitigation")
			isInvalid, errMessage := checkRepeatParameters(customer, body, currentScope)
			errorMessage = errMessage
			if isInvalid {
				goto ResponseNG
			}
		}
		if currentScope == nil && !isIfMatchOption {
			isActive, msg, err := checkActiveForCurrentCuid(customer, cuid)
			if err != nil {
				return Response{}, err
			}
			if isActive {
				errorMessage = msg
				goto ResponseNG
			}
			conflictInfo, err = CreateMitigation(body, customer, nil, isIfMatchOption)
			if err != nil {
				if strings.Contains(err.Error(), models.ValidationError) {
					errorMessage = fmt.Sprint(err)
					goto ResponseNG
				}
				log.Error("Failed to Create Mitigation.")
				return Response{}, err
			}
			if conflictInfo != nil {
				goto ResponseConflict
			}
			res = Response{
				Type: common.NonConfirmable,
				Code: common.Created,
				Body: messages.NewMitigationResponsePut(body, nil),
			}
			return res, nil
		} else if currentScope != nil  {
			config := dots_config.GetServerSystemConfig().LifetimeConfiguration
			if currentScope.Status == models.ActiveButTerminating {
				body.MitigationScope.Scopes[0].Lifetime = &config.MaxActiveButTerminatingPeriod
			}
			conflictInfo, err = CreateMitigation(body, customer, currentScope, isIfMatchOption)
			if err != nil {
				errorMessage = fmt.Sprintf("%s", err)
				if strings.Contains(err.Error(), models.ValidationError) {
					goto ResponseNG
				}
				log.Error("Failed to Create Mitigation.")
				return Response{}, err
			}
			if conflictInfo != nil {
				goto ResponseConflict
			}
			res = Response {
				Type: common.NonConfirmable,
				Code: common.Changed,
				Body: messages.NewMitigationResponsePut(body, nil),
			}
			return res, nil
		} else {
			log.Warnf("Not found any mitigation request (cuid=%+v, mid=%+v) for efficacy update", cuid, *mid)
			goto ResponseNG
		}
	ResponseConflict:
		res = Response {
			Type: common.NonConfirmable,
			Code: common.Conflict,
			Body: messages.NewMitigationResponsePut(body, conflictInfo.ParseToResponse()),
		}
		return res, nil
	}
ResponseNG:
	res = Response {
		Type: common.NonConfirmable,
		Code: common.BadRequest,
		Body: errorMessage,
	}
	return res, nil
}
func (m *MitigationRequest) HandleDelete(request Request, customer *models.Customer) (res Response, err error) {
	log.WithField("request", request).Debug("[DELETE] receive message")
	_, cuid, mid, err := messages.ParseURIPath(request.PathInfo)
	if err != nil {
		errMessage := fmt.Sprintf("Failed to parse Uri-Path, error: %s", err)
		log.Warnf(errMessage)
		res = Response{
			Type: common.NonConfirmable,
			Code: common.BadRequest,
			Body: errMessage,
		}
		return res, nil
	}
	if mid == nil || cuid == "" {
		errMessage := "Missing required Uri-Path Parameter(cuid, mid)."
		log.Warn(errMessage)
		res = Response{
			Type: common.NonConfirmable,
			Code: common.BadRequest,
			Body: errMessage,
		}
		return res, nil
	}
	var mitigationScope *models.MitigationScope
	mitigationScope, err = models.GetMitigationScope(customer.Id, cuid, *mid, models.AnyMitigationScopeId)
	if err != nil {
		log.WithError(err).Error("MitigationScope load error.")
		return Response{}, err
	}
	if mitigationScope == nil {
		goto Response
	}
	if mitigationScope.Status <= 4 && mitigationScope.Lifetime != 0 {
		config := dots_config.GetServerSystemConfig().LifetimeConfiguration
		mitigationScope.Lifetime = config.ActiveButTerminatingPeriod
		mitigationScope.Status = models.ActiveButTerminating
		err = models.UpdateMitigationScope(*mitigationScope, *customer, false)
		if err != nil {
			log.WithError(err).Error("MitigationScope update error.")
			return Response{}, err
		}
	} else {
		goto Response
	}
Response:
	res = Response{
		Type: common.NonConfirmable,
		Code: common.Deleted,
		Body: "Deleted",
	}
	return
}
func newMitigationScope(req messages.Scope, c *models.Customer, clientIdentifier string, clientDomainIdentifier string, isIfMatchOption bool) (m *models.MitigationScope, err error) {
	log.Debugf("newMitigationScope req=%+v, c=%+v, clientIdentifier=%+v, clientDomainIdentifier=%+v", req, c, clientIdentifier, clientDomainIdentifier)
	m = models.NewMitigationScope(c, clientIdentifier)
	m.MitigationId = *req.MitigationId
	m.TargetProtocol.AddList(req.TargetProtocol)
	m.FQDN.AddList(req.FQDN)
	m.URI.AddList(req.URI)
	m.AliasName.AddList(req.AliasName)
	if req.Lifetime == nil {
		log.Warn("lifetime is mandatory field")
		errMsg := fmt.Sprintf("%+v: lifetime is mandatory field", models.ValidationError)
		return nil, errors.New(errMsg)
	}
	m.Lifetime = *req.Lifetime
	if req.AttackStatus != nil {
		m.AttackStatus = *req.AttackStatus
	}
	if req.TriggerMitigation == nil {
		m.TriggerMitigation = true
	} else {
		m.TriggerMitigation = *req.TriggerMitigation
	}
	m.TargetPrefix, err = newPrefix(req.TargetPrefix)
	if err != nil {
		return
	}
	m.ClientDomainIdentifier = clientDomainIdentifier
	m.TargetPortRange, err = newPortRange(req.TargetPortRange)
	if err != nil {
		return
	}
	m.SourcePrefix, err = newPrefix(req.SourcePrefix)
	if err != nil {
		return
	}
	m.SourcePortRange, err = newPortRange(req.SourcePortRange)
	if err != nil {
		return
	}
	m.SourceICMPTypeRange, err = newICMPTypeRange(req.SourceICMPTypeRange)
	if err != nil {
		return
	}
	m.ControlFilteringList = newControlFiltering(req.AclList)
	if isIfMatchOption {
		m.TelemetryTotalAttackTraffic, err = models.NewTelemetryTotalAttackTraffic(req.TotalAttackTraffic)
		if err != nil {
			return
		}
		m.TelemetryAttackDetail, err = models.NewTelemetryAttackDetail(req.AttackDetail)
		if err != nil {
			return
		}
	}
	return
}
func newPrefix(targetPrefix []string) (prefixes []models.Prefix, err error) {
	prefixes = make([]models.Prefix, len(targetPrefix))
	for i, cidr := range targetPrefix {
		prefix, err := models.NewPrefix(cidr)
		if err != nil {
			log.Warnf("%+v", err)
			errMsg := fmt.Sprintf("%+v: %+v", models.ValidationError, err)
			return nil, errors.New(errMsg)
		}
		prefixes[i] = prefix
	}
	return
}