#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <vector>
#define ll long long
using namespace std;
const int maxn = 10010;
int n, T;
ll Tdef, Tmax, Tmin;
map<string, int> NameToID;
int cnt;
string Name[maxn];
string sender, receiver, type;
int rTime, rIP, rOverdue;
bool Illegal() {
// 遇到这些情况,不处理
if (receiver != Name[1] && receiver != "*" && type != "REQ")
// 接收主机为本机或 *,但类型不是 Request
return true;
if (type != "REQ" && type != "DIS")
// 类型不是 Discover 或 Request
return true;
if (type == "DIS" && receiver == Name[1])
// 接收主机是本机,且类型为 Discover
return true;
if (type != "DIS" && receiver == "*")
// 接收主机为 *,且类型不是 Discover
return true;
return false;
}
enum IPState {
// 描述某个 IP 的状态
NOT_DISTRIBUTED, // 未分配
READY_FOR_DISTRIBUTION, // 待分配
DISTRIBUTED, // 占用
OVERDUE // 过期
};
struct IP {
IPState state;
int owner;
int overdue;
IP() {
state = NOT_DISTRIBUTED;
owner = 0;
overdue = 0;
}
} ip[maxn];
int NumOfIP;
int IPHeld[maxn];
int distributeIP(int owner) {
// 为发送主机分配地址
// 发送主机有 IP,直接返回
if (IPHeld[owner]) {
return IPHeld[owner];
}
// 否则,寻找最小状态为未分配的 IP 地址
for (int i = 1; i <= n; ++i) {
if (ip[i].state == READY_FOR_DISTRIBUTION && ip[i].overdue <= rTime) {
// 待分配 IP 到期变为未分配
ip[i].state = NOT_DISTRIBUTED;
ip[i].overdue = 0;
IPHeld[ip[i].owner] = 0;
ip[i].owner = 0;
}
if (ip[i].state == NOT_DISTRIBUTED) {
return i;
}
}
// 否则,寻找最小状态为过期的 IP 地址
for (int i = 1; i <= n; ++i) {
if (ip[i].state == DISTRIBUTED && ip[i].overdue <= rTime) {
// 已分配 IP 过期变为过期 IP
ip[i].state = OVERDUE;
ip[i].overdue = 0;
}
if (ip[i].state == OVERDUE) {
return i;
}
}
// 否则,不处理该报文
return 0;
}
void receiveDiscover() {
// 接收到 Discover 报文
int s = NameToID[sender];
int curIP = distributeIP(s);
if (!curIP) // 分配失败,不处理
return;
ip[curIP].state = READY_FOR_DISTRIBUTION; // IP 设为待分配
IPHeld[ip[curIP].owner] = 0; // 原本占用的主机不在占用
IPHeld[s] = curIP; // 记录发送主机持有的 IP
ip[curIP].owner = s; // 标记该 IP 被发送主机持有
// 设置过期时刻
if (rOverdue == 0)
ip[curIP].overdue = rTime + Tdef;
else {
if (rOverdue < rTime + Tmin) {
ip[curIP].overdue = rTime + Tmin;
} else if (rOverdue > rTime + Tmax) {
ip[curIP].overdue = rTime + Tmax;
} else {
ip[curIP].overdue = rOverdue;
}
}
// 向主机发送 Offer 报文
cout << Name[1] << " " << Name[s] << " OFR " << curIP << " "
<< ip[curIP].overdue << "\n";
}
void receiveRequest() {
// 接收到 Request 报文
int s = NameToID[sender];
// 不是本机
if (receiver != Name[1]) {
if (IPHeld[s] && ip[IPHeld[s]].state == READY_FOR_DISTRIBUTION) {
ip[IPHeld[s]].state = NOT_DISTRIBUTED;
ip[IPHeld[s]].overdue = 0;
ip[IPHeld[s]].owner = 0;
IPHeld[s] = 0;
}
return;
}
// 更新发送主机持有的 IP 的状态
if (IPHeld[s] && ip[IPHeld[s]].overdue <= rTime) {
if (ip[IPHeld[s]].state == READY_FOR_DISTRIBUTION) {
ip[IPHeld[s]].state = NOT_DISTRIBUTED;
ip[IPHeld[s]].owner = 0;
ip[IPHeld[s]].overdue = 0;
IPHeld[s] = 0;
} else if (ip[IPHeld[s]].state == DISTRIBUTED) {
ip[IPHeld[s]].state = OVERDUE;
ip[IPHeld[s]].overdue = 0;
}
}
// 检查 IP 是否在池内且占有者是发送主机
if (!IPHeld[s] || IPHeld[s] != rIP) {
cout << Name[1] << " " << Name[s] << " NAK " << rIP << " " << 0 << "\n";
return;
}
// IP 地址状态设为占用
ip[rIP].state = DISTRIBUTED;
// 设置过期时刻
if (rOverdue == 0)
ip[rIP].overdue = rTime + Tdef;
else {
if (rOverdue < rTime + Tmin) {
ip[rIP].overdue = rTime + Tmin;
} else if (rOverdue > rTime + Tmax) {
ip[rIP].overdue = rTime + Tmax;
} else {
ip[rIP].overdue = rOverdue;
}
}
// 向主机发送 ACK 报文
cout << Name[1] << " " << Name[s] << " ACK " << rIP << " "
<< ip[rIP].overdue << "\n";
}
int main() {
// 读入数据,其中 Name[1] 是本机名称,本机编号为 1
cin >> n >> Tdef >> Tmax >> Tmin >> Name[1];
NameToID[Name[1]] = ++cnt;
scanf("%d", &T);
while (T--) {
cin >> rTime >> sender >> receiver >> type >> rIP >> rOverdue;
if (!NameToID.count(sender)) {
NameToID[sender] = ++cnt;
Name[cnt] = sender;
}
if (Illegal())
continue;
if (type == "REQ")
receiveRequest();
else if (type == "DIS")
receiveDiscover();
}
return 0;
}