#include <stdio.h>
#include <string.h>

#include "constants.h"
#include "helper_functions.h"
#include "passenger.h"

// MENU OPTIONS FOR MAIN MENU

#define ADD_PASSENGER 1
#define LOOKUP_PASSENGER_BY_NAME 2
#define LOOKUP_PASSENGER_BY_SEAT 3
#define DISPLAY_ALL_PASSENGERS 4
#define DISPLAY_SEATING_CHART 5
#define QUIT 6

// MENU OPTIONS FOR EDIT MENU
const int ASSIGN_SEAT = 1;
const int CHECK_BAG = 2;
const int RETURN_TO_MAIN_MENU = 3;

// AIRPLANE SEATING CONSTRAINTS
const int ROWS = 1;
const int SEATS_PER_ROW = 4;
const char FIRST_SEAT = 'A';

// DISPLAY AND PROMPTING FUNCTIONS (implemented below)
int main_menu_and_prompt();
int edit_menu_and_prompt();

// HELPER FUNCTIONS (implemented below)
void initialize_seating(struct passenger all_passengers[ROWS*SEATS_PER_ROW], struct passenger * seating_chart[][SEATS_PER_ROW]);
struct passenger * lookup_passenger_by_name(struct passenger * all_passengers);
void display_all_passengers(struct passenger * all_passengers);
void edit_passenger(struct passenger * passenger_to_edit, struct passenger * seating_chart[][SEATS_PER_ROW]);
struct passenger * lookup_passenger_by_seat(struct passenger * seating_chart[][SEATS_PER_ROW]);
void display_seating_chart(struct passenger * seating_chart[][SEATS_PER_ROW]);

// AIRPLANE DYNAMIC VARIABLES
int passenger_count = 0;

int main() {


	printf("\n");
	// TASK: Use an array to track a list of all passengers and 
	// a 2D array to represent a seating chart
	struct passenger all_passengers[ROWS*SEATS_PER_ROW];
	struct passenger * seating_chart[ROWS][SEATS_PER_ROW];

	// TASK: initialize_seating_chart
	initialize_seating(all_passengers, seating_chart);

	int choice = 0; 

	// Loop until user quits
	do {
		choice = main_menu_and_prompt();

		switch(choice) {
			case ADD_PASSENGER:
				printf("ADD PASSENGER\n\n");

				// TASK: create_new_passenger (using function which also prompts for input)
				struct passenger new_passenger;

				printf("Enter passenger name: ");
			        read_string(new_passenger.name, MAX_BUFFER_SIZE);
				new_passenger.num_bags_checked = 0;
				new_passenger.seat_row = NO_SEAT;

				// TASK: add new passenger to list of all passengers
				all_passengers[passenger_count] = new_passenger;
				passenger_count++;

				printf("\nPASSENGER ADDED\n\n");

				break;
			case LOOKUP_PASSENGER_BY_NAME:
				printf("LOOKUP PASSENGER BY NAME\n\n");

				// TASK: lookup_passenger_by_name
				struct passenger * passenger_to_edit = lookup_passenger_by_name(all_passengers);
	 
				// TASK: edit_passenger (print passenger info, display edit menu, implement edit options)
				edit_passenger(passenger_to_edit, seating_chart);

				break;
			case LOOKUP_PASSENGER_BY_SEAT:
				printf("LOOKUP PASSENGER BY SEAT\n\n");
	 
				// TASK: lookup_passenger_by_seat (using function wich also prompts for row and seat to look up)
				passenger_to_edit = lookup_passenger_by_seat(seating_chart);
	 
				// TASK: edit_passenger (same as above)
				edit_passenger(passenger_to_edit, seating_chart);
				
				break;
			case DISPLAY_ALL_PASSENGERS:
				printf("DISPLAY ALL PASSENGERS\n\n");
	 
				// TASK: display_all_passengers (list of all passengers, w/ or w/o seats)
				display_all_passengers(all_passengers);

				printf("\n");
				break;
			case DISPLAY_SEATING_CHART:
				printf("DISPLAY SEATING CHART\n\n");
	 
				// TASK: display_seating_chart as formatted 2D matrix
				display_seating_chart(seating_chart);

				break;
			case QUIT:
				// Let it fall through; do-while will catch it

				break;
			default:
				printf("INVALID OPTION: %d\n\n", choice);
				break;
		}
	} while (choice != QUIT);

	printf("Adios! Bon Voyage\n");

	return 0;
}		

/*
Print main menu and prompt for a choice (no input validation)
@return user's choice of the menu options
*/
int main_menu_and_prompt()
{
	printf("************WELCOME TO CS AIRWAYS****************\n");
	printf("%d. Add passenger\n", ADD_PASSENGER);
	printf("%d. Look up passenger by name\n", LOOKUP_PASSENGER_BY_NAME);
	printf("%d. Look up passenger by seat\n",LOOKUP_PASSENGER_BY_SEAT);
	printf("%d. Display all passengers\n", DISPLAY_ALL_PASSENGERS);
	printf("%d. Display seating chart\n", DISPLAY_SEATING_CHART);
	printf("%d. Quit\n", QUIT);
	printf("Choice: ");

	int choice = read_integer();

	while (choice == ERROR) {
		printf("Invalid Option. Please try again.\n");
		choice = read_integer();
	}

	printf("\n**************************************************\n");

	return choice;
}

/*
Print passenger edit menu and prompt for a choice (no input validation)
@return user's choice of the menu options
*/
int edit_menu_and_prompt()
{
	printf("%d. Assign seat\n", ASSIGN_SEAT);
	printf("%d. Check bag\n", CHECK_BAG);
	printf("%d. Return to main menu\n", RETURN_TO_MAIN_MENU);
	printf("Choice: ");

	int choice = read_integer();
	
	printf("\n");

	return choice;
}

/*
Prompt for a passenger name
@return a multi-word string input by user
*/
char * prompt_for_name(char * destination)
{
	printf("Passenger name: ");

	read_string(destination, MAX_BUFFER_SIZE);
}

/*
Prompt for a row number (no input validation)
@return row input by user
*/
int prompt_for_row()
{
	printf("Row number: ");
	int row = read_integer();
	return row;
}

/*
Prompt for a seat in a row  (no input validation)
@return seat input by user
*/
char prompt_for_seat_in_row()
{
	printf("Seat in row: ");
	char seat_in_row = (char) read_char();
	return seat_in_row;
}

/*
Set all values in seating_chart to NULL
@param seating_chart 2D matrix representing seating chart
*/
void initialize_seating(struct passenger all_passengers[ROWS*SEATS_PER_ROW], struct passenger * seating_chart[][SEATS_PER_ROW]){

	for (int i = 0; i < ROWS * SEATS_PER_ROW; i++) {
		strcpy(all_passengers[i].name, "NO PASSENGER");
		all_passengers[i].num_bags_checked = 0;
		all_passengers[i].seat_row = NO_SEAT;
		all_passengers[i].seat_in_row = '\0';
	}

	// TASK: fill the seating_chart with NULL
	for (int row = 0; row < ROWS; row++) {
		for (int seat = 0; seat < SEATS_PER_ROW; seat++) {
			seating_chart[row][seat] = NULL;
		}
	}
}

/*
Prompt for name to lookup, lookup name in list of all passenger
@param all_passengers list to search for user-inputted name
@return pointer to Passenger object representing passenger
*/
struct passenger * lookup_passenger_by_name(struct passenger * all_passengers) {
	char name[MAX_BUFFER_SIZE];
	prompt_for_name(name);

	// TASK: find passenger in list matching full_name and return a pointer to the passenger
	for (int i = 0; i < passenger_count; i++) {
		if (strcmp(all_passengers[i].name,name) == 0) {
			return &(all_passengers[i]);
		}
	}

	// return NULL if not found
	return NULL;
}

/*
Prompt for row, seat to lookup, lookup seat in seating chart
@param seating_chart 2D matrix to search for user-inputted row and name
@return pointer to Passenger object representing passenger (NULL if seat unoccupied)
*/
struct passenger * lookup_passenger_by_seat(struct passenger * seating_chart[][SEATS_PER_ROW]) {
	int row = prompt_for_row();
	char seat_in_row = prompt_for_seat_in_row();

	// TASK: return a passenger pointer representing the person at row and seat_in_row (NULL if no one is there)
	// NOTE: a char is really just an int, so to get the seat index from the seat name (e.g., 'A'),
	//       we can subtract the integer representing 'A' from the integer representing the seat
	//       For example, 'A' - 'A' is 0; 'B' - 'A' = 1; 'C' - 'A' = 2; etc. This is because the integer
	//       representation of the capital letters are consecutive integers (e.g., 'A' = 64, 'B' = 65, etc)
	int seat_index = seat_in_row - FIRST_SEAT;

	return seating_chart[row][seat_index];
}


/*
Given a passenger pointer, edit a passenger according to user-input instructions
Note that this involves printing a menu of edit options, and may require modifying the seating chart
@param passenger the passenger to edit
@param seating_chart the 2D matrix of Passenger pointers representing the seating chart
*/
void edit_passenger(struct passenger * passenger_to_edit, struct passenger * seating_chart[][SEATS_PER_ROW])
{
	// TASK: Return if passenger is NULL
	if (!passenger_to_edit) {
		printf("\nNO PASSENGER FOUND\n\n");
		return;
	}

	// Otherwise, print edit menu
	printf("\n************EDIT PASSENGER************\n\n");;

	// TASK: Start with passenger summary (to_string is fine)
	printf("Name: %s\nBags: %d\n", passenger_to_edit->name, passenger_to_edit->num_bags_checked);
	if (passenger_to_edit->seat_row == NO_SEAT){
		printf("SEAT: NONE\n\n");
	} else {
		printf("SEAT: %d%c\n\n", passenger_to_edit->seat_row,passenger_to_edit->seat_in_row);
	}

	// Print menu options (assign seat, check bag) and prompt for choice
	int choice = edit_menu_and_prompt();

	if (choice == ASSIGN_SEAT)
	{
		int row = prompt_for_row();
		char seat_in_row = prompt_for_seat_in_row();
		
		printf("\n");

		// TASK: Check if seat is taken
		// NOTE: the NOTE in the lookup_passenger_by_seat function explains how to find a seat
		//       index from the seat label (e.g., 'A')
		int seat_index = seat_in_row - FIRST_SEAT;
		if (seating_chart[row][seat_index] != NULL)
		{
			// sorry, charlie, no assignment
			printf("SEAT IS TAKEN\n\n");
		}
		// make sure row and seat_in_row are valid
		else if (row < 0 || row >= ROWS || seat_index < 0 || seat_index >= SEATS_PER_ROW)
		{
			printf("INVALID SEAT ENTERED\n\n");
		}
		// else assign the seat
		else
		{
			// TASK: If passenger is already assigned a seat
			if (passenger_to_edit->seat_row != NO_SEAT)
			{
				// TASK: Free the seat
				// NOTE: the NOTE in the lookup_passenger_by_seat function explains how to find a seat
				//       index from the seat label (e.g., 'A')
				int old_seat_index = passenger_to_edit->seat_in_row - FIRST_SEAT;
				seating_chart[passenger_to_edit->seat_row][old_seat_index] = NULL;
			}
			// TASK: Update the seating assignment with the new assignment
			seating_chart[row][seat_index] = passenger_to_edit;
			// TASK: Update the passenger object's seat assignemnt to the new assignment
			passenger_to_edit->seat_row = row;
			passenger_to_edit->seat_in_row = seat_in_row;
		}
	}
	else if (choice == CHECK_BAG)
	{
		//TASK: Check a bag
		passenger_to_edit->num_bags_checked++;

		printf("Bag Checked\n\n");
	}
	// else if choice == RETURN_TO_MAIN_MENU (we don't need to implement this; why?)
}

/*
Print list of all passenger names to the console
@param all_passengers list of all passengers
*/
void display_all_passengers(struct passenger * all_passengers)
{
	// TASK: Display all passengers (just to_string() is fine)
	for (int i = 0; i < passenger_count; i++)
	{
		printf("%d.%s\n",i+1, all_passengers[i].name);
	}
}

/*
Print a formatted version of the seating chart (to look like a plane) to the console
Prints 'X' for occupied seats and '_' for unnoccupied seats
Also prints row and seat labels for easy reference
@param seating_chart current seating chart
*/
void display_seating_chart(struct passenger * seating_chart[][SEATS_PER_ROW])
{
        //First print a row of seat labels (e.g., A, B, C, D)
	printf("    ");
	for (int seat = 0; seat < SEATS_PER_ROW; seat++)
	{
		if (seat == SEATS_PER_ROW / 2)
		{
			printf("   ");
		}
                // NOTE: the NOTE in the lookup_passenger_by_seat function explains
                //       the relationship between the seat label (e.g., 'A') and the seat index (e.g., 0)
		char seat_char = FIRST_SEAT + seat;
		printf("%c ",seat_char);
	}
	printf("\n");

        // Print the 2D seating chart matrix
	for (int row = 0; row < ROWS; row++)
	{
		printf("%d | ",row); // row label and left cabin wall
		for (int seat = 0; seat < SEATS_PER_ROW; seat++)
		{
			if (seat == SEATS_PER_ROW / 2)
			{
				printf("   "); // aisle
			}
			if (seating_chart[row][seat] == NULL) // if seat is unoccupied
			{
				printf("_ "); // unoccupied
			}
			else
			{
				printf("X "); // occupied
			}
		}
		printf("|\n"); // right cabin wall
	}

	printf("\n");
}

