GuiGamelistOptions::~GuiGamelistOptions()
{
	// save and apply sort
	SystemData* system = getGamelist()->getCursor()->getSystem();
	FileData* root = system->getRootFolder();
	system->sortId = mListSort->getSelectedId(); // this will break if mListSort isn't in the same order as FileSorts:typesArr
	root->sort(*mListSort->getSelected()); // will also recursively sort children

	// notify that the root folder was sorted
	getGamelist()->onFileChanged(root, FILE_SORTED);
}
void GuiGamelistOptions::openMetaDataEd()
{
	// open metadata editor
	FileData* file = getGamelist()->getCursor();
	ScraperSearchParams p;
	p.game = file;
	p.system = file->getSystem();
	mWindow->pushGui(new GuiMetaDataEd(mWindow, &file->metadata, file->metadata.getMDD(), p, file->getPath().filename().string(), 
		std::bind(&IGameListView::onFileChanged, getGamelist(), file, FILE_METADATA_CHANGED), [this, file] { 
			getGamelist()->remove(file);
	}));
}
void GuiGamelistOptions::openMetaDataEd()
{
	// open metadata editor
	FileData* file = getGamelist()->getCursor();
	ScraperSearchParams p;
	p.game = file;
	p.system = file->getSystem();
	mWindow->pushGui(new GuiMetaDataEd(mWindow, &file->metadata, file->metadata.getMDD(), p, file->getPath().filename().string(), 
		std::bind(&IGameListView::onFileChanged, getGamelist(), file, FILE_METADATA_CHANGED), [this, file] { 
			boost::filesystem::remove(file->getPath()); //actually delete the file on the filesystem
			file->getParent()->removeChild(file); //unlink it so list repopulations triggered from onFileChanged won't see it
			getGamelist()->onFileChanged(file, FILE_REMOVED); //tell the view
			delete file; //free it
	}));
}
void GuiGamelistOptions::jumpToLetter()
{
	char letter = mJumpToLetterList->getSelected();
	IGameListView* gamelist = getGamelist();

	// this is a really shitty way to get a list of files
	const std::vector<FileData*>& files = gamelist->getCursor()->getParent()->getChildren();
	
	long min = 0;
	long max = files.size() - 1;
	long mid = 0;

	while(max >= min)
	{
		mid = ((max - min) / 2) + min;

		// game somehow has no first character to check
		if(files.at(mid)->getName().empty())
			continue;

		char checkLetter = toupper(files.at(mid)->getName()[0]);

		if(checkLetter < letter)
			min = mid + 1;
		else if(checkLetter > letter)
			max = mid - 1;
		else
			break; //exact match found
	}

	gamelist->setCursor(files.at(mid));

	delete this;
}
GuiGamelistOptions::~GuiGamelistOptions()
{
	LOG(LogDebug) << "GUIGamelistOptions::~GuiGamelistOptions()";
	// apply sort
	FileData* root = getGamelist()->getCursor()->getSystem()->getRootFolder();
	root->sort(*mListSort->getSelected()); // will also recursively sort children
	
	// notify that the root folder was sorted
	
	getGamelist()->onFileChanged(root, FILE_SORTED);				
	if (mFavoriteStateChanged)
	{
		LOG(LogDebug) << "  GUIGamelistOptions::~GuiGamelistOptions(): FavoriteStateChanged, reloading GameList";
		ViewController::get()->setAllInvalidGamesList(getGamelist()->getCursor()->getSystem());
		ViewController::get()->reloadGameListView(getGamelist()->getCursor()->getSystem());
	}
}
GuiGamelistOptions::GuiGamelistOptions(Window* window, SystemData* system) : GuiComponent(window), 
	mSystem(system), 
	mMenu(window, "OPTIONS")
{
	addChild(&mMenu);

	// jump to letter
	char curChar = toupper(getGamelist()->getCursor()->getName()[0]);
	if(curChar < 'A' || curChar > 'Z')
		curChar = 'A';

	mJumpToLetterList = std::make_shared<LetterList>(mWindow, "JUMP TO LETTER", false);
	for(char c = 'A'; c <= 'Z'; c++)
		mJumpToLetterList->add(std::string(1, c), c, c == curChar);

	ComponentListRow row;
	row.addElement(std::make_shared<TextComponent>(mWindow, "JUMP TO LETTER", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
	row.addElement(mJumpToLetterList, false);
	row.input_handler = [&](InputConfig* config, Input input) {
		if(config->isMappedTo("a", input) && input.value)
		{
			jumpToLetter();
			return true;
		}
		else if(mJumpToLetterList->input(config, input))
		{
			return true;
		}
		return false;
	};
	mMenu.addRow(row);

	// sort list by
	mListSort = std::make_shared<SortList>(mWindow, "SORT GAMES BY", false);
	for(unsigned int i = 0; i < FileSorts::SortTypes.size(); i++)
	{
		const FileData::SortType& sort = FileSorts::SortTypes.at(i);
		mListSort->add(sort.description, &sort, i == system->sortId);
	}

	mMenu.addWithLabel("SORT GAMES BY", mListSort);

	// edit game metadata
	row.elements.clear();
	row.addElement(std::make_shared<TextComponent>(mWindow, "EDIT THIS GAME'S METADATA", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
	row.addElement(makeArrow(mWindow), false);
	row.makeAcceptInputHandler(std::bind(&GuiGamelistOptions::openMetaDataEd, this));
	mMenu.addRow(row);

	// center the menu
	setSize((float)Renderer::getScreenWidth(), (float)Renderer::getScreenHeight());
	mMenu.setPosition((mSize.x() - mMenu.getSize().x()) / 2, (mSize.y() - mMenu.getSize().y()) / 2);
}
GuiGamelistOptions::GuiGamelistOptions(Window* window, SystemData* system) : GuiComponent(window), 
	mSystem(system), 
	mMenu(window, "OPTIONS")
{
	LOG(LogDebug) << "GUIGamelistOptions::GuiGamelistOptions()";
	addChild(&mMenu);

	// jump to letter
	char curChar = toupper(getGamelist()->getCursor()->getName()[0]);
	if(curChar < 'A' || curChar > 'Z')
		curChar = 'A';

	mJumpToLetterList = std::make_shared<LetterList>(mWindow, "JUMP TO LETTER", false);
	for(char c = 'A'; c <= 'Z'; c++)
		mJumpToLetterList->add(std::string(1, c), c, c == curChar);

	ComponentListRow row;
	row.addElement(std::make_shared<TextComponent>(mWindow, "JUMP TO LETTER", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
	row.addElement(mJumpToLetterList, false);
	row.input_handler = [&](InputConfig* config, Input input) {
		if(config->isMappedTo("a", input) && input.value)
		{
			jumpToLetter();
			return true;
		}
		else if(mJumpToLetterList->input(config, input))
		{
			return true;
		}
		return false;
	};
	mMenu.addRow(row);

	row.elements.clear();
	row.addElement(std::make_shared<TextComponent>(mWindow, "SURPRISE ME!", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
	row.input_handler = [&](InputConfig* config, Input input) {
		if(config->isMappedTo("a", input) && input.value)
		{
			SurpriseMe();
			return true;
		}
		return false;
	};
	mMenu.addRow(row);
	
	// sort list by
	mListSort = std::make_shared<SortList>(mWindow, "SORT GAMES BY", false);
	for(unsigned int i = 0; i < FileSorts::SortTypes.size(); i++)
	{
		const FileData::SortType& sort = FileSorts::SortTypes.at(i);
		mListSort->add(sort.description, &sort, i == 0); // TODO - actually make the sort type persistent
	}

	mMenu.addWithLabel("SORT GAMES BY", mListSort);
	
	// Show favorites-only
	auto favorite_only = std::make_shared<SwitchComponent>(mWindow);
	favorite_only->setState(Settings::getInstance()->getBool("FavoritesOnly"));
	mMenu.addWithLabel("FAVORITES ONLY", favorite_only);
	addSaveFunc([favorite_only, this] { Settings::getInstance()->setBool("FavoritesOnly", favorite_only->getState()); mFavoriteStateChanged = true; });
	
	// edit game metadata - only in Full UI mode
	if(Settings::getInstance()->getString("UIMode") == "Full")
	{
		row.elements.clear();
		row.addElement(std::make_shared<TextComponent>(mWindow, "EDIT THIS GAME'S METADATA", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
		row.addElement(makeArrow(mWindow), false);
		row.makeAcceptInputHandler(std::bind(&GuiGamelistOptions::openMetaDataEd, this));
		mMenu.addRow(row);
	}

	// center the menu
	setSize((float)Renderer::getScreenWidth(), (float)Renderer::getScreenHeight());
	mMenu.setPosition((mSize.x() - mMenu.getSize().x()) / 2, (mSize.y() - mMenu.getSize().y()) / 2);
}