// Arup Guha
// 8/27/2013
// Solution to Computer Science Program #1: Organ Donation

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define SIZE 20
#define BLOODTYPESIZE 4
#define NOTFOUND -1

typedef struct {
    int month;
    int day;
    int year;
} dateT;

typedef struct {
    int hour;
    int minute;
} timeT;

typedef struct {
    char name[SIZE];
    char organname[SIZE];
    char bloodtype[BLOODTYPESIZE];
    dateT dateAdded;
    timeT timeAdded;
    int received;
} organT;


organT* readInput(int n);
void readRecord(organT* ptrOrgan);
void setDate(organT* ptrOrgan, char* date);
void setTime(organT* ptrOrgan, char* myTime);
int datecmp(const dateT* d1, const dateT* d2);
int timecmp(const timeT* t1, const timeT* t2);
int organcmp(const organT* o1, const organT* o2);
int findBest(organT* organs, int size, char* myorgan, char* mybloodtype);
int isMatch(const organT* waiting, const char* donorOrgan, const char* donorBlood);

int main() {

    // Read in the wait list.
    int n;
    scanf("%d", &n);
    organT* organs = (organT*)readInput(n);

    int numOrgans, i;
    scanf("%d", &numOrgans);

    // Process each received organ.
    for (i=0; i<numOrgans; i++) {

        // Read in the organ received and find the recipient.
        char organ[SIZE], bloodtype[BLOODTYPESIZE];
        scanf("%s%s", organ, bloodtype);
        int ID = findBest(organs, n, organ, bloodtype);

        // Output the result.
        if (ID == NOTFOUND)
            printf("No match found\n");
        else {
            printf("%s %s\n", organs[ID].name, organs[ID].organname);
            organs[ID].received = 1;
        }
    }

    free(organs);

    return 0;
}

// Reads in n organ records and returns a pointer to the array that stores them.
organT* readInput(int n) {

    int i;
    organT* list = malloc(sizeof(organT)*n);

    for (i=0; i<n; i++)
        readRecord(&list[i]);

    return list;
}

// Reads in a single record into the organ pointed to by ptrOrgan.
void readRecord(organT* ptrOrgan) {
    char dateStr[SIZE], timeStr[SIZE];
    scanf("%s%s%s%s%s", ptrOrgan->name, ptrOrgan->organname, ptrOrgan->bloodtype, dateStr, timeStr);
    setDate(ptrOrgan, dateStr);
    setTime(ptrOrgan, timeStr);
    ptrOrgan->received = 0;
}

// Given the date stored in a string, stores it appropriately in the organ pointed to by ptrOrgan
void setDate(organT* ptrOrgan, char* date) {
    char* tmpPtr = strtok(date, "/");
    ptrOrgan->dateAdded.month = atoi(tmpPtr);
    tmpPtr = strtok(NULL, "/");
    ptrOrgan->dateAdded.day = atoi(tmpPtr);
    tmpPtr = strtok(NULL, "/");
    ptrOrgan->dateAdded.year = atoi(tmpPtr);
}

// Given the time stored in a string, stores it appropriately in the organ pointed to by ptrOrgan
void setTime(organT* ptrOrgan, char* myTime) {
    char* tmpPtr = strtok(myTime, ":");
    ptrOrgan->timeAdded.hour = atoi(tmpPtr);
    tmpPtr = strtok(NULL, ":");
    ptrOrgan->timeAdded.minute = atoi(tmpPtr);
}

// Returns a negative integer if the date pointed to by d1 comes before the one pointed to
// by d2, 0 if they are equal and 1 if the date pointed to by d1 comes after the one pointed to by d2.
int datecmp(const dateT* d1, const dateT* d2) {
    if (d1->year != d2->year)
        return d1->year - d2->year;
    if (d1->month != d2->month)
        return d1->month - d2->month;
    return d1->day - d2->day;
}

// Returns a negative integer if the time pointed to by t1 comes before the one pointed to
// by t2, 0 if they are equal and 1 if the time pointed to by t1 comes after the one pointed to by t2.
int timecmp(const timeT* t1, const timeT* t2) {
    if (t1->hour != t2->hour)
        return t1->hour - t2->hour;
    return t1->minute - t2->minute;
}

// Returns a negative integer if the organ pointed to by o1 has been waiting longer than the
// organ pointed to by o2, 0 if equal, and a positive integer otherwise.
int organcmp(const organT* o1, const organT* o2) {
    int firstcmp = datecmp(&(o1->dateAdded), &(o2->dateAdded));
    if (firstcmp != 0)
        return firstcmp;
    return timecmp(&(o1->timeAdded), &(o2->timeAdded));
}

// Returns 1 iff the organ pointed to by waiting matches the one specified by donorOrgan, donorBlood.
int isMatch(const organT* waiting, const char* donorOrgan, const char* donorBlood) {
    return strcmp(waiting->organname, donorOrgan) == 0 &&
           strcmp(waiting->bloodtype, donorBlood) == 0 &&
           waiting->received == 0;
}

// Given the full list of organs, its size, and a donor organ and blood type, this
// function returns the index where the best matching donor is found.
int findBest(organT* organs, int size, char* donorOrgan, char* donorBlood) {

    int retval = NOTFOUND;
    int i;

    // Go through the whole list.
    for (i=0; i<size; i++) {

        // See if we have a match.
        if (isMatch(&organs[i], donorOrgan, donorBlood)) {

            // Update if this is the first match or the best match so far.
            if (retval == NOTFOUND || organcmp(&organs[i], &organs[retval]) < 0)
                retval = i;

        }
    }

    return retval;
}
