/*
 * Created by Mike "MjnMixael" Nelson for The FreeSpace 2 Source Code Project.
 * You may not sell or otherwise commercially exploit the source or things you
 * create based on the source.
 */

// CustomDataDlg.cpp : implementation file
//
#include "stdafx.h"
#include "FRED.h"
#include "customdatadlg.h"


#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#define NO_RESET_FOCUS 0
#define RESET_FOCUS 1

/////////////////////////////////////////////////////////////////////////////
// CustomDataDlg dialog

CustomDataDlg::CustomDataDlg(SCP_map<SCP_string, SCP_string>* data_ptr, CWnd* pParent /*=nullptr*/)
	: CDialog(CustomDataDlg::IDD, pParent), m_target_data(data_ptr)
{
}

void CustomDataDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_CUSTOM_DATA_LISTER, m_data_lister);
}

// see https://stackoverflow.com/questions/17828258/how-to-prevent-mfc-dialog-closing-on-enter-and-escape-keys
// This is needed because despite the override of the normal OK and Cancel routes, Enter will still be recognized
BOOL CustomDataDlg::PreTranslateMessage(MSG* pMsg)
{
	if (pMsg->message == WM_KEYDOWN) {
		if (pMsg->wParam == VK_RETURN || pMsg->wParam == VK_ESCAPE) {
			return TRUE; // Do not process further
		}
	}
	return CDialog::PreTranslateMessage(pMsg);
}

BEGIN_MESSAGE_MAP(CustomDataDlg, CDialog)
ON_BN_CLICKED(IDC_CUSTOM_ADD, OnPairAdd)
ON_BN_CLICKED(IDC_CUSTOM_REMOVE, OnPairRemove)
ON_BN_CLICKED(IDC_CUSTOM_UPDATE, OnPairUpdate)

ON_BN_CLICKED(ID_OK, OnButtonOk)
ON_BN_CLICKED(ID_CANCEL, OnButtonCancel)
ON_WM_CLOSE()

ON_LBN_SELCHANGE(IDC_CUSTOM_DATA_LISTER, OnListerSelectionChange)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CustomDataDlg message handlers

BOOL CustomDataDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// grab the existing list of custom data pairs and duplicate it. We only update it if the user clicks OK.
	Assertion(m_target_data != nullptr, "Custom Data target is nullptr. Get a coder!");
	m_custom_data = *m_target_data;

	update_data_lister();

	// Send default name and values into dialog box
	UpdateData(FALSE);

	return TRUE; // return TRUE unless you set the focus to a control
				 // EXCEPTION: OCX Property Pages should return FALSE
}

void CustomDataDlg::OnButtonOk()
{
	// now we set the custom data to our copy
	Assertion(m_target_data != nullptr, "Custom Data target is nullptr. Get a coder!");
	*m_target_data = m_custom_data;

	CDialog::OnOK();
}

void CustomDataDlg::OnButtonCancel()
{
	if (query_modified()) {
		int z = MessageBox("Do you want to keep your changes?", "Close", MB_ICONQUESTION | MB_YESNOCANCEL);
		if (z == IDCANCEL) {
			return;
		}

		if (z == IDYES) {
			OnButtonOk();
			return;
		}
	}

	CDialog::OnCancel();
}

// this is called when you hit the enter key
void CustomDataDlg::OnOK()
{
	// override MFC default behavior and do nothing
}

// this is called when you hit the escape key
void CustomDataDlg::OnCancel()
{
	// override MFC default behavior and do nothing
}

// this is called when you hit the Close button
void CustomDataDlg::OnClose()
{
	OnButtonCancel();
}

void CustomDataDlg::OnListerSelectionChange()
{
	const int index = m_data_lister.GetCurSel();

	if (index == LB_ERR) {
		// TODO: clear key and data text  edit boxes?
		return;
	}

	Assert(m_data_lister.GetCount() > 0);
	Assert(index >= 0 && index < static_cast<int>(m_custom_data.size()));

	const SCP_string& key = m_lister_keys[index];

	update_text_edit_boxes(key, m_custom_data[key]);
	update_help_text("No help text provided");

	for (size_t i = 0; i < Default_custom_data.size(); i++) {
		if (Default_custom_data[i].key == key) {
			update_help_text(Default_custom_data[i].description);
		}
	}

}

void CustomDataDlg::OnPairAdd()
{
	add_pair_entry(static_cast<int>(m_custom_data.size()));
}

void CustomDataDlg::add_pair_entry(const int insert_index)
{
	if (!edit_boxes_have_valid_data(false)) {
		return;
	}

	CEdit* data_edit = (CEdit*)GetDlgItem(IDC_CUSTOM_DATA);
	CString data_str;
	data_edit->GetWindowText(data_str);

	CEdit* key_edit = (CEdit*)GetDlgItem(IDC_CUSTOM_KEY);
	CString key_str;
	key_edit->GetWindowText(key_str);
	m_custom_data.emplace(key_str, data_str);

	update_data_lister();
	update_text_edit_boxes("", "");
}

void CustomDataDlg::OnPairRemove()
{
	const int index = m_data_lister.GetCurSel();

	if (index == LB_ERR) {
		MessageBox("Nothing selected! You must select something to remove!");
		return;
	}

	const auto& key = m_lister_keys[index];
	m_custom_data.erase(key);

	update_data_lister();
	update_help_text("");
}

void CustomDataDlg::OnPairUpdate()
{
	if (!edit_boxes_have_valid_data(true)) {
		return;
	}

	const int index = m_data_lister.GetCurSel();

	if (index == LB_ERR) {
		MessageBox("Nothing selected! Use Add to enter new data");
		return;
	}

	const auto& key = m_lister_keys[index];
	m_custom_data.erase(key);

	CEdit* data_edit = (CEdit*)GetDlgItem(IDC_CUSTOM_DATA);
	CString data_str;
	data_edit->GetWindowText(data_str);
	
	CEdit* key_edit = (CEdit*)GetDlgItem(IDC_CUSTOM_KEY);
	CString key_str;
	key_edit->GetWindowText(key_str);
	m_custom_data[SCP_string(key_str)] = data_str;

	update_data_lister();
	update_text_edit_boxes("", "");
}

bool CustomDataDlg::edit_boxes_have_valid_data(bool dup_key_ok)
{
	if (!data_edit_box_has_valid_data()) {
		return false;
	}
	if (!key_edit_box_has_valid_data(dup_key_ok)) {
		return false;
	}

	return true;
}

bool CustomDataDlg::key_edit_box_has_valid_data(bool dup_key_ok)
{

	CEdit* key_edit = (CEdit*)GetDlgItem(IDC_CUSTOM_KEY);
	CString key_str;
	key_edit->GetWindowText(key_str);

	if (key_str.IsEmpty()) {
		MessageBox("You have not entered a key!");
		return false;
	}

	if (key_str.Find(" ") != -1) {
		MessageBox("Keys cannot contain spaces!");
		return false;
	}

	// Only check for duplicate keys if there are other keys to check!
	if (m_lister_keys.size() > 0) {

		const int index = m_data_lister.GetCurSel();
		SCP_string this_key = "";

		// If we're here then we're updating a pair and the key can be "duplicated"
		// because it's not actually being changed
		if (dup_key_ok && SCP_vector_inbounds(m_lister_keys, index)) {
			this_key = m_lister_keys[index];
		}

		if (strcmp(this_key.c_str(), key_str)) {
			for (const auto& pair : m_custom_data) {
				const CString key = pair.first.c_str();
				if (key == key_str) {
					MessageBox("Keys must be unique!");
					return false;
				}
			}
		}
	}

	return true;
}

bool CustomDataDlg::data_edit_box_has_valid_data()
{
	CEdit* data_edit = (CEdit*)GetDlgItem(IDC_CUSTOM_DATA);
	CString data_str;
	data_edit->GetWindowText(data_str);

	if (data_str.IsEmpty()) {
		MessageBox("You have not entered any data!");
		return false;
	}

	return true;
}

void CustomDataDlg::update_data_lister()
{
	m_data_lister.ResetContent();
	m_lister_keys.clear();

	for (const auto& pair : m_custom_data) {
		m_lister_keys.emplace_back(pair.first);
		const SCP_string lister_entry = pair.first + " - " + pair.second;
		m_data_lister.AddString(lister_entry.c_str());
	}

	m_data_lister.EnableWindow(m_data_lister.GetCount() > 0);
}

void CustomDataDlg::update_text_edit_boxes(const SCP_string& key, const SCP_string& data)
{
	CEdit* key_edit = (CEdit*)GetDlgItem(IDC_CUSTOM_KEY);
	key_edit->SetWindowText(key.c_str());

	CEdit* data_edit = (CEdit*)GetDlgItem(IDC_CUSTOM_DATA);
	data_edit->SetWindowText(data.c_str());
}

void CustomDataDlg::update_help_text(const SCP_string& description)
{
	CEdit* desc_edit = (CEdit*)GetDlgItem(IDC_CUSTOM_DATA_DESC);
	desc_edit->SetWindowText(description.c_str());

}

bool CustomDataDlg::query_modified() const
{
	Assertion(m_target_data != nullptr, "Custom Data target is nullptr. Get a coder!");
	return *m_target_data != m_custom_data;
}
