/* GPC (C) 2017-2018 Stephane Charette <stephanecharette@gmail.com>
 * $Id: SessionComponentTransfer.cpp 2516 2018-04-07 15:47:48Z stephane $
 */

#include "GPC.hpp"


SessionComponentTransfer::SessionComponentTransfer(SessionComponent &sc) :
	ThreadWithProgressWindow(sc.session_record.field[SessionRecord::EField::kIjsFilename], true, false, 10000, "", &sc),
	parent(sc)
{
	return;
}


SessionComponentTransfer::~SessionComponentTransfer(void)
{
	return;
}


void SessionComponentTransfer::run(void)
{
	const std::string name = parent.session_record.field[SessionRecord::EField::kPrinterName];
	bool success = false;
	std::string msg;

	const bool send_ijs = cfg().get_bool("also_send_ijs_file");

	try
	{
		const std::string	idx			= std::to_string(parent.session_record.printer_number);
		const std::string	ip_address	= cfg().get_str("print_controller_" + idx + "_ip_address"	);
		const int			tcp_port	= cfg().get_int("print_controller_" + idx + "_tcp_port"		);
		LOG_MSG("printer index #" << idx << " means we need to connect to ip address " << ip_address << " tcp port " << tcp_port);

		BinaryProtocolConnection incjet(ip_address, tcp_port);

		double current_task_count			= 0;
		const double total_number_of_tasks	=
				0.5 +							// small extra amount so we don't pause on 100% at the end
				1.0 +							// connecting
				1.0 +							// initiate communication
				1.0 +							// send eof
				parent.print_job.ijbs.size() +	// send ijb
				(send_ijs ? 1.0 : 0.0);

		if (threadShouldExit()) { return; }

		setStatusMessage("Connecting...");
		setProgress( (++current_task_count) / total_number_of_tasks);
		msg = "Failed to connect to " + name + ".";
		incjet.connect();

		if (threadShouldExit()) { return; }

		setProgress( (++current_task_count) / total_number_of_tasks);
		msg = "Failed to establish communication with " + name + ".";
		incjet.initiate_communications();

		if (threadShouldExit()) { return; }

		if (send_ijs)
		{
			setStatusMessage("Sending IJS file...");
			setProgress( (++current_task_count) / total_number_of_tasks);
			msg = "Failed to send .ijs file to " + name + ".";
			incjet.send_file(true, parent.print_job.ijs.contents);
		}

		for (const auto & ijb : parent.print_job.ijbs)
		{
			if (threadShouldExit()) { return; }

			const std::string filename = ijb.rec->short_name;
			setStatusMessage("Sending " + filename + "...");
			setProgress( (++current_task_count) / total_number_of_tasks);
			msg = "Failed to send .ijb file " + filename + " to " + name + ".";
			incjet.send_file(false, ijb.contents);
		}

		if (threadShouldExit()) { return; }

		setStatusMessage("Finishing up...");
		setProgress( (++current_task_count) / total_number_of_tasks);
		msg = "Failed to send end-of-file to " + name + ".";
		incjet.send_eof();

		success = true;
	}
	catch (const std::exception &e)
	{
		LOG_MSG("failed to transfer: " << msg);
		LOG_MSG("exception caught: " << e.what());
	}
	catch (...)
	{
		LOG_MSG("unknown exception caught");
	}

	if (success)
	{
		const size_t number_of_uses = 1 + std::stoi(parent.session_record.field[SessionRecord::EField::kNumberOfUses]);
		parent.session_record.field[SessionRecord::EField::kNumberOfUses] = std::to_string(number_of_uses);
		parent.session_record.recentlyUsedEpoch = std::time(nullptr);
		parent.session_record.initialize();
		parent.session_record.schedule_sessions_to_be_saved();
		summaryWnd().canvas.table.repaint();

		msg = "The ";
		if (send_ijs)
		{
			msg += "print job and ";
		}
		msg += std::to_string(parent.print_job.ijbs.size()) + " bitmaps were successfully transferred to " + name + ".\n\n"
				"Use count was incremented to " + std::to_string(number_of_uses) + " and the last-used timestamp was updated.";

		AlertWindow::showMessageBoxAsync(
			AlertWindow::AlertIconType::InfoIcon,
			"Success!",
			msg);
	}
	else
	{
		AlertWindow::showMessageBoxAsync(
			AlertWindow::AlertIconType::WarningIcon,
			parent.session_record.field[SessionRecord::EField::kIjsFilename],
			msg + "\n\n" + "Please try again, or see the log file for details.");
	}

	// sometimes the progress thread window remains visible after run()
	// has finished, so be explicit about when it should be hidden
	getAlertWindow()->setVisible(false);

	return;
}
