
funcdef void MenuSelectCallBack(void);

enum MenuStates {
    MENUSTATE_OPEN = 0,
    MENUSTATE_CLOSED,
    MENUSTATE_OPENING,
    MENUSTATE_CLOSING
}
const int MaxMenuItems = 6;

//Text Menus
class Menu {
	int state = MENUSTATE_CLOSED;
	int index = 0;
	int closeTime = 0;
	int openTime = 0;
	int numItems;
	Input input;
	array<MenuItem> items; //0 = bottom = Max = Top
	MenuSelectCallBack @onPressedLeft;
	MenuSelectCallBack @onPressedRight;
	
// - Level Progress
	// - 5 out 5 Monkeys Found
	// - Found/Missing Pistol Challenge Key
	// - Pistol Challenge complete/Incomplete (has upgrade)
// Weapon Upgrades
	// - Has Upgrade
	//------------------------------------------------------------------------------------------------------------------------
    Menu() {
		input = Input();
		for (int i = 0; i < MaxMenuItems; i++) {
			items.insertLast(MenuItem());
		}
		numItems = MaxMenuItems;
    }
	//------------------------------------------------------------------------------------------------------------------------
	void StartMenu(int newNumItems) {
		numItems = newNumItems;
		ClearItems();
		SetOnPressedLeft(null);
		SetOnPressedRight(null);
		index = 0;
	}
	//------------------------------------------------------------------------------------------------------------------------
	// Sets the text to "" and callback functions to null for all items
	//------------------------------------------------------------------------------------------------------------------------
	void ClearItems() {
		for (int i = 0; i < MaxMenuItems; i++) {
			SetItem(i, "", null);
		}
	}
	//------------------------------------------------------------------------------------------------------------------------
	void SetOnPressedLeft(MenuSelectCallBack @newOnPressedLeft) {
		@onPressedLeft = @newOnPressedLeft;
	}
	//------------------------------------------------------------------------------------------------------------------------
	void SetOnPressedRight(MenuSelectCallBack @newOnPressedRight) {
		@onPressedRight = @newOnPressedRight;
	}
	//------------------------------------------------------------------------------------------------------------------------
	void SetItem(int itemIndex, const kStr &in text, MenuSelectCallBack @selectItemFunc = null) {
		if (itemIndex >= 0 and itemIndex < int(items.length())) {
			items[itemIndex].Set(text, @selectItemFunc);
		}
	}
	//------------------------------------------------------------------------------------------------------------------------
	int MaxSelectableItems() {
		return numItems;
	}
	//------------------------------------------------------------------------------------------------------------------------
	void Open() {
		SetPlayerFlagNoMovement(true);
		state = MENUSTATE_OPENING;
		index = 0;
		closeTime = 0;
		openTime = 30;
	}
	//------------------------------------------------------------------------------------------------------------------------
	void Close() {
		if (IsOpen()) {
			state = MENUSTATE_CLOSING;
			closeTime = 30;
		}
	}
	//------------------------------------------------------------------------------------------------------------------------
	bool IsOpen() {
		return state == MENUSTATE_OPEN;
	}
	//------------------------------------------------------------------------------------------------------------------------
	bool IsClosed() {
		return state == MENUSTATE_CLOSED;
	}
	//------------------------------------------------------------------------------------------------------------------------
	bool IsOpening() {
		return state == MENUSTATE_OPENING;
	}
	//------------------------------------------------------------------------------------------------------------------------
	bool IsClosing() {
		return state == MENUSTATE_CLOSING;
	}
	//------------------------------------------------------------------------------------------------------------------------
	void OnClosed() {
		SetPlayerFlagNoMovement(false);
	}
	//------------------------------------------------------------------------------------------------------------------------
	void Update() {
		//update closing/opening
		if (IsOpening()) {
			openTime--;
			if (openTime <= 0) {
				state = MENUSTATE_OPEN;
			}
		} else if (IsClosing()) {
			closeTime--;
			if (closeTime <= 0) {
				state = MENUSTATE_CLOSED;
				OnClosed();
			}
		}
		
		//input
		if (IsOpen()) {
			input.Update();
			if (input.BackwardDown()) {
				Game.PlaySound("sounds/shaders/generic_89_jump_swish_1.ksnd");
				index--;
				if (index < 0) {
					index = Math::Max(MaxSelectableItems() - 1, 0);
				}
			} else if (input.ForwardDown()) {
				Game.PlaySound("sounds/shaders/generic_89_jump_swish_1.ksnd");
				index++;
				if (index >= MaxSelectableItems()) {
					index = 0;
				}
			} else if (input.JumpDown() or input.AttackDown()) {
				items[index].Select();
			} else if (input.StrafeLeftDown()) {
				if (onPressedLeft !is null) {
					Game.PlaySound("sounds/shaders/generic_89_jump_swish_1.ksnd");
					onPressedLeft();
				}
			} else if (input.StrafeRightDown()) {
				if (onPressedRight !is null) {
					Game.PlaySound("sounds/shaders/generic_89_jump_swish_1.ksnd");
					onPressedRight();
				}
			}
		}
		
		//display item text
		if (IsOpen() or IsOpening()) {
			for (int i = 0; i < MaxMenuItems; i++) {
				Game.PrintLine((index == i ? "- " : "") + items[i].label + (index == i ? " -" : ""), i, 10);
			}
		}
	}
	//------------------------------------------------------------------------------------------------------------------------
};
