#include <libfilezilla/glue/wx.hpp>

#include <wx/textctrl.h>
#include <wx/bookctrl.h>
#include <wx/valtext.h>
#include <wx/valgen.h>
#include <wx/statline.h>
#include <wx/simplebook.h>
#include <wx/log.h>

#include "generatecertificatedialog.hpp"
#include "locale.hpp"

#include "helpers.hpp"
#include "glue.hpp"
#include "tls_param_editor.hpp"
#include "textvalidatorex.hpp"

#include "../filezilla/util/parser.hpp"

GenerateCertificateDialog::GenerateCertificateDialog()
{
}

namespace {

// FIXME: This is to work-around what seems to be a bug in clang,
// which otherwise generates a call to the fz::tls_param destructor which ends up being undefined.
void reset(fz::tls_param &p)
{
	p = {};
}

}

bool GenerateCertificateDialog::Create(wxWindow *parent, const wxString &title, wxWindowID winid, const wxPoint &pos, const wxSize &size, long style, const wxString &name)
{
	if (!wxDialogEx::Create(parent, winid, title, pos, size, style, name))
		return false;

	CreateButtons(wxOK | wxCANCEL);

	GetBookCtrl() | [&](auto p) {
		wxPage(p) | [&](auto p){
			wxVBox(p, 0) = {
				wxLabel(p, _S("D&istinguished name:")),
				dn_ctrl_ = new wxTextCtrl(p, wxID_ANY),

				wxLabel(p, _S("&Hostnames (separate them with blanks):")),
				wxSizerFlags(1) >>= hostnames_ctrl_ = new wxTextCtrl(p, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE | wxTE_RICH2),

				wxLabel(p, _S("Private &key:")),
				key_book_ctrl_ = wxCreate<wxChoicebook>(p, wxID_ANY) | [&](auto p) {
					wxPage(wxValidateOnlyIfCurrent)(p, _S("Provided")) | [&](auto p) {
						wxVBox(p, 0) = {
							key_ctrl_ = new TlsParamEditor(p, TLS_PE_BLOB | TLS_PE_FILEPATH | TLS_PE_PKCS11URL, _S("Private key")),
							wxLabel(p, _S("Private key &password (stored in plaintext):")),
							key_pass_ctrl_ = new wxTextCtrl(p, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PASSWORD)
						};
					};

					wxPage(wxValidateOnlyIfCurrent)(p, _S("Generated by the server"), true) | [&](auto *p) {
						wxTransferDataFromWindow(p, [&] {
							if (key_) {
								reset(*key_);
								//*key_ = {};
							}

							return true;
						});
					};
				}
			};

			dn_ctrl_->GetPrevSibling()->Show(false);
			dn_ctrl_->Show(false);

			hostnames_ctrl_->GetPrevSibling()->Show(false);
			hostnames_ctrl_->Show(false);

			wxTransferDataFromWindow(p, [&] {
				if (dn_) {
					*dn_ = fz::to_utf8(dn_ctrl_->GetValue().Trim(true).Trim(false));
				}

				return true;
			});

			wxTransferDataFromWindow(p, [&] {
				if (hostnames_) {
					auto hostnames = fz::strtok(fz::to_utf8(hostnames_ctrl_->GetValue().Trim(true).Trim(false)), " \n\r\t");
					if (hostnames.size() < minimum_number_of_hostnames_) {
						wxMsg::Error(_F("You must input at least %d hostnames.", minimum_number_of_hostnames_));
						return false;
					}

					for (auto &h: hostnames) {
						auto error = fx::ValidateHostname(fz::to_wxString(h), at_least_2nd_level_);
						if (!error.empty()) {
							wxMsg::Error(_S("Invalid hostname '%s'"), h).Ext(_S("%s"), error).Wait();
							return false;
						}
					}

					*hostnames_ = std::move(hostnames);
				}

				return true;
			});
		};
	};

	LayoutDialog();

	return true;
}

void GenerateCertificateDialog::SetKey(fz::tls_param *key, fz::native_string *password, TlsParamEditor::RetrieveDeobfuscatedBlobFunc func, fz::util::fs::path_format server_path_format)
{
	key_ = key;
	password_ = password;

	key_ctrl_->SetValue(key_, server_path_format);
	key_ctrl_->SetRetrieveDeobfuscatedBlobFunction(std::move(func));

	if (password_) {
		key_pass_ctrl_->SetValidator(TextValidatorEx(wxFILTER_NONE, password_));
	}
	else {
		key_pass_ctrl_->SetValidator(wxValidator());
	}

	key_book_ctrl_->GetPrevSibling()->Show(key_ != nullptr);
	key_book_ctrl_->Show(key_ != nullptr);
	key_book_ctrl_->GetContainingSizer()->Layout();

	TransferDataToWindow();
}

void GenerateCertificateDialog::SetDistinguishedName(std::string *dn)
{
	dn_ = dn;
	dn_ctrl_->GetPrevSibling()->Show(dn_ != nullptr);
	dn_ctrl_->Show(dn_ != nullptr);
	dn_ctrl_->GetContainingSizer()->Layout();

	TransferDataToWindow();
}

void GenerateCertificateDialog::SetHostnames(std::vector<std::string> *hostnames, std::size_t minimum_number_of_hostnames, bool at_least_2dn_level)
{
	hostnames_ = hostnames;
	minimum_number_of_hostnames_ = minimum_number_of_hostnames;
	at_least_2nd_level_ = at_least_2dn_level;

	hostnames_ctrl_->GetPrevSibling()->Show(hostnames_ != nullptr);
	hostnames_ctrl_->Show(hostnames_ != nullptr);
	hostnames_ctrl_->GetContainingSizer()->Layout();

	TransferDataToWindow();
}


wxBookCtrlBase *GenerateCertificateDialog::CreateBookCtrl()
{
	return wxCreate<wxSimplebook>(this);
}

bool GenerateCertificateDialog::TransferDataToWindow()
{
	if (!wxDialogEx::TransferDataToWindow()) {
		return false;
	}

	if (dn_) {
		dn_ctrl_->SetValue(fz::to_wxString(*dn_));
	}
	else {
		dn_ctrl_->Clear();
	}

	if (hostnames_) {
		hostnames_ctrl_->SetValue(fz::join<wxString>(*hostnames_));
	}
	else {
		hostnames_ctrl_->Clear();
	}

	return true;
}

