/*
 * typedef.h
 * This file is part of galvani.
 * Copyright (C) 2020-2024 Burkard Lutz <b.lutz@online.de>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef TYPEDEF_H
#define TYPEDEF_H

#include <libserial/SerialPort.h>

//Typedef

enum typ {TIME,DMM,DEVICE,LINEAR,EXP,PH,PEAK,SPEKTRUM};		//Real device / simulation
//Symbols for value points
enum symbol {none,cross,square,diamond,circle};
enum linestyle {solid,pointed,dashed};
enum thermoval {no,CuNi,NiCr};
enum mfkt {DCV,ACV,DCmA,ACmA,DCA,ACA,Res,Cond,pH,Temp};	//functions for remote setup of dmm

//Data classes
class m_record	// measurement results
{
	public:
		std::string funktion;
		double digits;
		std::string unit;
};

class mw_data	//x,y value pair
{
	public:
		double x;
		double y;
};


class peak_data		//peak in chromatogram
{
	public:
		mw_data max;	//x- and y-value of peak-maximum
		unsigned long long int mpos;	//position of maximum in Array
		unsigned long long int xb1;		//start (Basis)
		unsigned long long int xb2;		//end (Basis)
		double area;	//peak Area
		double percent;	//percentage (concentration)
};

class diffmax		//maximum of differential function with gauss parameter
{
	public:
		mw_data max;	//x- and y-value of maximum
		double P;		//amplitude (peak height)
		double m;		//mean value
		double b;		//standard deviation, half of peak diameter in half amplitude
		unsigned long long int xm;		//position

};

class polyreg_data	//coefficients of polynom y = a0 + a1*x + a2*x² + a3*x³
{
	public:
		double a0 = 0;
		double a1 = 0;
		double a2 = 0;
		double a3 = 0;
};

class acid_data		//pks-data of acids used for simulation of titration curves
{
	public:
		std::string name;
		int npks;	//number of pks values
		double pks[3];
};


// Class definitions

class PrintOP : public Gtk::PrintOperation
{
	public:

		bool printoption_title = true;
		bool printoption_comment = true;
		bool printoption_diag = true;
		bool printoption_result = true;
		
		Glib::RefPtr<Gtk::PrintOperation> print_op;
		Glib::RefPtr<Gtk::PageSetup> print_page;
		Gtk::PrintOperationAction print_action;
		void begin_print (const Glib::RefPtr<Gtk::PrintContext>& print_context);//initialize printing
		void draw_page(const Glib::RefPtr<Gtk::PrintContext>& print_context, int page_nr);	//draw printpage on cairo context
		
		PrintOP();
		virtual ~PrintOP();

	
	private:

		Gtk::Switch titlesw, commentsw, diagsw, resultsw;
		Gtk::PageOrientation orientation;
		Glib::RefPtr<Gtk::PrintSettings> print_settings;
		Cairo::RefPtr<Cairo::Surface> diag_sf;
		Cairo::RefPtr<Cairo::Context> print_ct, diag_ct;
		Glib::RefPtr<Pango::Layout> page_layout;
		Glib::RefPtr<Pango::LayoutLine> layout_line;
		Glib::ustring report_title, report_comment, report_results;
		Pango::FontDescription font;
		double pg_scale;
		std::vector<int> PageBreaks;
		double page_width;
		double page_height;
		double dpi;	//print resolution 
		double top_margin, bottom_margin, left_margin, right_margin; //document margins in pt

		void set_printoptions(Gtk::Widget* printpage_options);					//set items on printpage
		void draw_pagelayout(Glib::RefPtr<Pango::Layout> page_layout, double start, int page_nr); //construct printpage
		Gtk::Widget* create_custom_widget();									//create printoptions (elements on print page)
 };

class Diagramm : public Gtk::DrawingArea
{
	int x, y;
	
	public:
  	Diagramm(GtkDrawingArea* cobject, const Glib::RefPtr<Gtk::Builder> &builder);
	
		double axcol_r=0.0, axcol_g=0.0, axcol_b=0.0;
		double gridcol_r=0.5, gridcol_g=0.5, gridcol_b=0.5;
		double bkcol_r=0.95, bkcol_g=0.95, bkcol_b=0.94; 
		double xycol_r=1.0, xycol_g=0.0, xycol_b=0.0;
		double funktcol_r=0.0, funktcol_g=0.0, funktcol_b=1.0;
		int margin, width, height; 						
		int pxmin, pymin, pxmax, pymax; 		//pixel
		double xmin=0.0, ymin=0.0, xmax=10.0, ymax=1.0, x_n, y_n;	//x,y coordinate system
		double xminval, xmaxval, yminval,ymaxval;	//minima and maxima of values
		double xabsmax, yabsmax; 			//absolute maxima
		double xscale=10.0, yscale=1.0;		//x,y-Scale (10s, 1V)
		double xrange=1.0, yrange=1.0;				//scale factor for range
		double dx,dy;						//Axes Fragmentation (scale divisions)
		double dxax=0.01, dyax=0.01;		//Axes Fragmentation: scale factor
		int ax_dx=10, ax_dy=10;				//Axes Fragmentation: resolution
		int axp,n,pos;						//arbitrary point on axis for drawing grid
		bool grid=true;						//draw grid?
		bool autoscale=true;
		bool showzero=false;
		bool showtitle=true;
		int grid_dx=5, grid_dy=5;			//grid: resolution
		symbol mw_symbol=none;				//Symbol for value point
		bool symbol_filled=true;
		int symw=5;							//symbol magnitude in pixel
		bool mw_line=true;					//draw line to connect points
		bool mw_curve=false;				//draw curve to connect points
		linestyle mw_linestyle=solid;		//line style
		bool reset_diag=true;
		bool m_started=false;
		bool show_peaklimits=true;
		bool show_peakarea=true;
		bool show_baseline=true;
		bool coord_saved = false;
		int mtime=1000;						//measurement interval in milliseconds
		sigc::connection timeout_handler;	//on_draw: timeout-handler
		bool start_mt();			//on_draw: start Timeout
		bool stop_mt();				//on_draw: stop Timeout
		std::string img_filename;
		std::string funktion_x;		//functions and units for x,y-values
		std::string unit_x;
		std::string funktion_y;
		std::string unit_y;
		
		void reset_diagscale ();
						
		friend void eval_data ();
		friend void show_diag ();
		friend void PrintOP::begin_print (const Glib::RefPtr<Gtk::PrintContext>& print_context);
		friend void PrintOP::draw_page(const Glib::RefPtr<Gtk::PrintContext>& print_context, int page_nr);
		friend void export_diag ();
		
		
	Diagramm();	

	virtual ~Diagramm();

protected:
  //Override default signal handler:
  	bool on_draw(const Cairo::RefPtr<Cairo::Context>& ccontext) override;
	void draw_background (const Cairo::RefPtr<Cairo::Context> &ccontext);
	void draw_coord (const Cairo::RefPtr<Cairo::Context> &ccontext);
	int scale_x (double x);
	int scale_y (double y);
	void draw_cross (const Cairo::RefPtr<Cairo::Context> &ccontext, int symwidth);
	void draw_square (const Cairo::RefPtr<Cairo::Context> &ccontext, int symwidth, bool filled);
	void draw_diamond (const Cairo::RefPtr<Cairo::Context> &ccontext, int symwidth, bool filled);
	void draw_circle (int x, int y, int symwidth, bool filled, const Cairo::RefPtr<Cairo::Context> &ccontext);
	void draw_symbol (int x, int y, symbol symb, int symwidth, bool filled, const Cairo::RefPtr<Cairo::Context> &ct);
	void draw_xyline (const Cairo::RefPtr<Cairo::Context> &ccontext);
	void draw_xycurve (const Cairo::RefPtr<Cairo::Context> &ccontext);
	void draw_xysymbol (const Cairo::RefPtr<Cairo::Context> &ccontext); //-> &ct!
	void draw_lin_regression(const Cairo::RefPtr<Cairo::Context> &ct);
	void draw_diff_funktion (const Cairo::RefPtr<Cairo::Context> &ct);
	void draw_peak_integration (const Cairo::RefPtr<Cairo::Context> &ct);
	void draw_selection_frame (double x_1, double y_1, double x_2, double y_2, const Cairo::RefPtr<Cairo::Context> &ct);
	void find_xy_minmax ();
	void set_unit();		//select unit prefix and multiply value by appropiate faktor
	void set_coord_limits ();
	double get_xcoord (double xp);
	double get_ycoord (double yp);
	bool on_motion_notify_event (GdkEventMotion *motion);
	bool on_button_press_event (GdkEventButton *pos);
	bool on_button_release_event (GdkEventButton *pos);
	
	bool on_timeout(); 
	Cairo::RefPtr<Cairo::ImageSurface> diag_sf;
	Cairo::RefPtr<Cairo::Context> diag_ct;
	Glib::RefPtr<Pango::Layout> diag_layout;
		

private:
	Cairo::RefPtr<Cairo::Surface> sf;
	Pango::FontDescription font;
	double scale_width, scale_height;
	double scalefactor = 4.0;
	int diag_width, diag_height;
	double xmin_new, xmax_new, ymin_new, ymax_new;
	bool selection_frame = false;
	std::string downgrade_unit (std::string unit);
	std::string upgrade_unit (std::string unit);
	
};

class Ctrl_string
{
	public:
		mfkt fkt;			//parameter function
		std::string ctrl; 	//string to send to dmm for setting up funktion
};

class Multimeter
{
	public:
		std::string dmm_name; 	//type of device
		std::string int_face;	//interface
		LibSerial::SerialPort dmm_port;	//connection to serial port (RS232C)
		int usb_port;			//connection to usb port
		typ dmm_typ;
		
		//Connection Parameters 
		LibSerial::BaudRate dmm_baud;
		LibSerial::CharacterSize dmm_charsize;
		LibSerial::FlowControl	dmm_flowcontrol;
		LibSerial::StopBits dmm_stopbits;
		LibSerial::Parity dmm_parity;
		bool dmm_polling;		//send character to device for gaining values?
		bool scpi;		// can we communicate by scpi commands?
		bool usb;		// connect to usb port?
		int num_bytes;	// number of bytes transmitted
		int num_val;	// number of values transmitted 
		size_t ms_timeout;  // milliseconds

		//Variables
		std::string m_funkt;	//measurement function
		std::string m_range;	//value range
		bool connected = false;	//is dmm connected to serial interface?
		bool remote_cfg = false;	//can dmm be configured remote?
		Ctrl_string remote_ctrl_strings [10];	//control strings to configure dmm
		double va = 10;  //parameters of titration (concentration and volume of titrand and titrator)
		double ca = 1.0;
		double cb = 1.0;
		
		//Functions
		void connect_dmm (std::string int_face);
		bool connect_usb (std::string port);
		void disconnect_dmm ();
		void writeto_dmm (std::string wstr);
		std::string readfrom_dmm ();
		m_record read_dmm ();
		m_record get_std_unit (m_record messw);
		m_record get_mwert_dmm (std::string mwert);	// Voltcraft, Metex and others
		m_record get_mwert_impo_dmi4 (std::string mwert);	//Impo DMI4
		m_record get_mwert_scpi (std::string mwert);		// dmm with scpi
		std::string get_scpi_funkt();			// read measuring funktion from dmm with scpi
		std::string get_baud();
		std::string get_charsize();
		std::string get_flowcontrol();
		std::string get_stopbits();
		std::string get_parity();
		void set_baud(std::string baudrate);
		void set_charsize(std::string charactersize);
		void set_flowcontrol(std::string flowcontrol);
		void set_stopbits(std::string stopbits);
		void set_parity(std::string parity);
		void setup (std::string funkt, std::string range);
		void set_ctrlstr (mfkt funktion, std::string ctrl);
		std::string get_ctrlstr (mfkt funktion);
		void set_tit_data (int npks);

	Multimeter ();

	virtual ~Multimeter ();

	protected:
		int random_nr (int min, int max);	//compute random number between min and max
		double sim_linear (double x);
		double sim_exp (double x);
		double sim_ph (double x);
		double sim_peak (double x);
		double sim_spekt (double x);
		m_record read_mm ();
		m_record read_device ();
		m_record read_lutron_ph207 ();

	private:
		//Parameter for Simulation
		double m;	//linear slope
		double a;	//intercept of exp-funktion
		double k;	//slope of exp-funktion
		double P[20];	// peak magnitude
		double rt[20];	//retention time (at peak maximum)
		double b[20];	// half width of peak in half amplitude
		double drift;	//drift of base line
		int n;		//number of peaks
		int npks;	//number of pks-values
		double pks1, pks2, pks3;		//pKs-values
};

class Messung
{
	public:
		std::string datum;
		std::string title;
		std::string funktion_x;
		std::string funktion_y;	
		std::string unit_x;
		std::string unit_y;
		std::string comment;
		std::string evalresults;

	Messung ();
	
	virtual ~Messung();

	std::string upgrade_unit (std::string unit);
	std::string downgrade_unit (std::string unit);
	
};



#endif