// Internalrequest deals with internal requests and makes sure corresponding elevator will be used to answer the request
func Internalrequest(localip string, Elevatorlist []extra.Elevator, request Network.Request) {
	var statelist = make(map[string]Network.Info)
	infolist := Network.GetInfoList()
	for host, info := range infolist {
		statelist[host] = info
	}
Internalloop:
	for i := 0; i < 4; i++ { // N_FLOORS ca marche pas
		for _, elevator := range Elevatorlist {
			if info, ok := statelist[elevator.Address]; ok {
				if i != 0 && (info.State == "UP" && info.PreviousFloor+i == request.Floor) || (info.State == "DOWN" && info.PreviousFloor-i == request.Floor) {
					if statelist[elevator.Address].Ipsource == localip {
						internalrequest = request
					} else {
						delete(statelist, elevator.Address)
						continue Internalloop
					}
				}
			}
		}
		for _, elevator := range Elevatorlist {
			if info, ok := statelist[elevator.Address]; ok {
				if info.State == "IDLE" && (info.PreviousFloor == request.Floor+i || info.PreviousFloor == request.Floor-i) {
					if statelist[elevator.Address].Ipsource == localip {
						internalrequest = request
					} else {
						delete(statelist, elevator.Address)
						continue Internalloop
					}
				}
			}
		}
	}

}
// Nextrequest will provide the best elevator for each request, using the three above functions
func Nextrequest(localip string, Elevatorlist []extra.Elevator) Network.Request {
	var statelist = make(map[string]Network.Info)
	infolist := Network.GetInfoList()
	for host, info := range infolist {
		statelist[host] = info
	}
	requestlist := Network.GetRequestList()

loop:
	for _, request := range requestlist {
		if !InternalOrExternal(request) {
			go Externalrequest(localip, Elevatorlist, request)
			return externalrequest
			continue loop
		} else {
			go Internalrequest(localip, Elevatorlist, request)
			return internalrequest
			continue loop
		}
	}
	return Network.NoRequest[0]
}
// Externalrequest is designed to return the best elevator for an external request
func Externalrequest(localip string, Elevatorlist []extra.Elevator, request Network.Request) {
	var statelist = make(map[string]Network.Info)
	infolist := Network.GetInfoList()
	for host, info := range infolist {
		statelist[host] = info
	}
Externalloop:
	for _, elevator := range Elevatorlist {
		if info, ok := statelist[elevator.Address]; ok {
			if ((info.State == "UP" || info.State == "IDLE") && info.PreviousFloor <= request.Floor) || ((info.State == "DOWN" || info.State == "IDLE") && info.PreviousFloor >= request.Floor) {
				if info.Ipsource == request.Ipsource {
					if info.Ipsource == localip {
						return request
					} else {
						delete(statelist, elevator.Address)
						continue Externalloop
					}
				}
			}
		}
	}

	for _, elevator := range Elevatorlist {
		if info, ok := statelist[elevator.Address]; ok {
			if (info.State == "UP" && info.PreviousFloor >= request.Floor) || (info.State == "DOWN" && info.PreviousFloor <= request.Floor) {
				if info.Ipsource == request.Ipsource {
					if info.Ipsource == localip {
						return request
					} else {
						delete(statelist, elevator.Address)
						continue Externalloop
					}
				}
			}
		}
	}
}
//This function does a BFS-search through all orders to find the most effective solution
func Nextrequest(myip string, Elevatorlist []misc.Elevator) Network.Request {
	var statelist = make(map[string]Network.Info)
	infolist := Network.GetInfoList()
	for host, info := range infolist {
		statelist[host] = info
	}
	requestlist := Network.GetRequestList()
insideloop:
	for _, request := range requestlist {
		if request.Direction != Elevator.BUTTON_COMMAND {
			continue insideloop
		}
		for _, elevator := range Elevatorlist {
			if info, ok := statelist[Elevator.Address]; ok {
				if ((info.State == "UP" || info.State == "IDLE") && info.LastFloor <= request.Floor) || ((info.State == "DOWN" || info.State == "IDLE") && info.LastFloor >= request.Floor) {
					if info.Source == request.Source {
						if info.Source == myip {
							return request
						} else {
							delete(statelist, Elevator.Address)
							continue insideloop
						}
					}
				}
			}
		}
		for _, elevator := range Elevatorlist {
			if info, ok := statelist[Elevator.Address]; ok {
				if (info.State == "UP" && info.LastFloor >= request.Floor) || (info.State == "DOWN" && info.LastFloor <= request.Floor) {
					if info.Source == request.Source {
						if info.Source == myip {
							return request
						} else {
							delete(statelist, Elevator.Address)
							continue insideloop
						}
					}
				}
			}
		}
	}
requestloop:
	for _, request := range requestlist {
		if request.Direction == Elevator.BUTTON_COMMAND {
			continue requestloop
		}
		for i := 0; i < Elevator.N_FLOORS; i++ {
			for _, elevator := range Elevatorlist {
				if info, ok := statelist[Elevator.Address]; ok {
					if i != 0 && (info.State == "UP" && info.LastFloor+i == request.Floor) || (info.State == "DOWN" && info.LastFloor-i == request.Floor) {
						if statelist[Elevator.Address].Source == myip {
							return request
						} else {
							delete(statelist, Elevator.Address)
							continue requestloop
						}
					}
				}
			}
			for _, elevator := range Elevatorlist {
				if info, ok := statelist[Elevator.Address]; ok {
					if info.State == "IDLE" && (info.LastFloor == request.Floor+i || info.LastFloor == request.Floor-i) {
						if statelist[Elevator.Address].Source == myip {
							return request
						} else {
							delete(statelist, Elevator.Address)
							continue requestloop
						}
					}
				}
			}
		}
	}
	return Network.EmptyRequest[0]
}