/* GMM (C) 2018 Stephane Charette <stephanecharette@gmail.com>
 * $Id: TabCanvas.hpp 2688 2018-12-07 21:20:05Z stephane $
 */

#pragma once

#include "GMM.hpp"


/** The number of "buckets" needed to show the moisture levels.  Normally will be 17, used to define buckets for 8%
 * through to 24%.  This is used at compile time to allocate a number of text fields and labels shown at the bottom
 * of each tab.
 */
#define number_of_buckets 17

/** Only a small number of buckets are created, the first of which is 8%, and incrementing by 1 until all buckets
 * have been assigned.  Normally goes from 8% to 24%.
 */
#define percentage_of_first_bucket 8

class TabCanvas : public Component, public Timer, public Thread
{
	public:

		TabCanvas(const std::string & name);

		virtual ~TabCanvas(void);

		virtual void resized(void);

		/// Inherited from Timer.  Used to redraw the chart.
		virtual void timerCallback(void);

		virtual void periodic_update(void);

		virtual void calculate_averages_and_std_deviations(void);

		virtual Image draw_chart(const size_t width, const size_t height);

		/// Inherited from Thread.  Used to handle the serial device.
		virtual void run(void);

		/// Secondary thread which is started to handle the serial device.
		virtual void device_thread(void);

		virtual void write_mc_file(void);

		virtual void write_summary_file(void);

		virtual void read_all_mc_files(void);

		virtual void open_serial_device(const std::string & device_name);

		virtual void close_serial_device(void);

		virtual std::string read_from_device(VBytes & read_buffer);

		virtual std::string get_simulated_string(VBytes & read_buffer);

		virtual void read_opc_values_from_csv(void);

		virtual void parse_opc_console_output(void);

		virtual void update_kiln_run_pkg(void);

		/// Lock this mutex when modifying some of the key variables such as @ref run_doubles, @ref run_sum, @ref run_average, and @ref run_std_dev.
		CriticalSection numbers_and_calculations_mutex;

		const std::string prefix;

		size_t				opc_sequence_number;
		const std::string	opc_output_filename;
		const std::string	opc_register_kiln;
		const std::string	opc_register_run;
		const std::string	opc_register_pkg;

		/** Used to determine if this tab is the currently-selected tab in the notebook.  Is updated by the Notebook
		 * object whenever a new tab gets focus.  @see @ref Notebook::currentTabChanged()
		 */
		bool		tab_is_active;

		bool		export_image;

		std::time_t time_since_gmm_started;	///< This one shoudln't be a "per tab" variable, but I want to keep the timestamps together in one place.
		std::time_t time_since_kiln_changed;
		std::time_t time_since_run_changed;
		std::time_t time_since_pkg_changed;
		std::time_t time_since_last_board;
		std::time_t time_since_last_board_warning;

		/** Keep track of the number of boards when the warning was issued.  This is used to prevent
		 * multiple warnings being issued on a tab where there have been zero updates (package has stopped).
		 */
		size_t number_of_boards_when_warning_was_last_issued;

		/// Prevent showing a 2nd async warning message window if one is already shown to the user.  This gets cleared when the message window is dismissed.
		bool warning_message_is_already_on_screen;

		/// Determines how often the timer should trigger.  This is used to redraw the chart and update the screen.
		int			timer_frequency_in_milliseconds;

		HANDLE		comm_handle;

		int			current_kiln;
		int			current_run;
		int			current_pkg;

		int			new_kiln;
		int			new_run;
		int			new_pkg;

		/// Count the number of boards in each bucket.
		size_t run_moisture_bucket[number_of_buckets];	///< These values are shown in @ref run_distribution[]
		size_t pkg_moisture_bucket[number_of_buckets];	///< These values are shown in @ref pkg_distribution[]

		LDouble		run_doubles;
		LDouble		pkg_doubles;

		/// The sum of moisture levels for all packages within the current run.  This is updated at every board, and used to find the average and standard deviation.
		double		run_sum;

		/// Similar to @ref run_sum but for the current package.
		double		pkg_sum;

		/// The average moisture content for all packages within the current run.  This is updated at every board.
		double		run_average;

		/// Similar to @ref run_average but for the current package.
		double		pkg_average;

		double		run_std_dev;
		double		pkg_std_dev;

		Label		kiln_num_label;
		TextEditor	kiln_num_editor;

		Label		run_label;
		TextEditor	run_editor;

		Label		pkg_label;
		TextEditor	pkg_editor;

		Label		run_number_of_boards_label;				///< "Boards:"
		TextEditor	run_number_of_boards_editor;
		Label		run_average_moisture_label;				///< "Average:"
		TextEditor	run_average_moisture_editor;
		Label		run_std_dev_moisture_label;				///< "Std. dev:"
		TextEditor	run_std_dev_moisture_editor;

		// where "total" means the entire run, and "local" means the package
		Label		pkg_number_of_boards_label;				///< "Boards:"
		TextEditor	pkg_number_of_boards_editor;
		Label		pkg_average_moisture_label;				///< "Average:"
		TextEditor	pkg_average_moisture_editor;
		Label		pkg_std_dev_moisture_label;				///< "Std. dev:"
		TextEditor	pkg_std_dev_moisture_editor;

		Label		run_header;									///< "Run:"
		Label		pkg_header;									///< "Pkg:"

		TextEditor	run_distribution	[number_of_buckets];	///< These text fields are populated using the numbers in @ref run_moisture_content[].
		Label		percentages			[number_of_buckets];	///< 8%, 9%, 10%, 11%, ...
		TextEditor	pkg_distribution	[number_of_buckets];	///< These text fields are populated using the numbers in @ref pkg_moisture_content[].

		ImageComponent chart;

		VStr		warnings_and_errors;

		std::string opc_via_csv_filename;
		std::regex opc_via_csv_regex;
};
