/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
#+
#+     Glade / Gtk Programming
#+
#+     Copyright (C) 2019 by Kevin C. O'Kane
#+
#+     Kevin C. O'Kane
#+     kc.okane@gmail.com
#+     https://www.cs.uni.edu/~okane
#+     http://threadsafebooks.com/
#+
#+ 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, write to the Free Software
#+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#+
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

// May 14, 2019

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <ctype.h>
#include <math.h>

int		showArc = 0; // show filled-in arc along with needle?
double		Load;
guint		width=100, height=50; // initial dimensions of meter

void    on_destroy() {
                gtk_main_quit();
                }

//-------------------------------------------------------------
//	main timer process
//	called every 1000 milliseconds to update the meter
//-------------------------------------------------------------

gboolean	timer_handler() {

//--------------------------------
//	read the system load data
//--------------------------------

	FILE *f1 = fopen("/proc/loadavg", "r");
	fscanf(f1, "%lf", &Load); 
	fclose(f1);
 
        gtk_widget_queue_draw (draw2);

        return TRUE;	// please return
        }

//--------------------------
//	draw meters
//--------------------------

void	needles(cairo_t *cr, double hor, double ver, double len, double t1) {

	double x, x1, x2, y, y1, y2;
	double X;

	if (t1 > M_PI) t1 = M_PI; // limit is M_PI (PI)

//------------------------------------------------------------------------------
//	color is same as needle until past needle point and then color is gray
//------------------------------------------------------------------------------

	X = 0.0; // this will increment by 1/20 of the arc

	cairo_set_source_rgb(cr, 1.0, 0.0, 0.3);	// yellow

	cairo_set_line_width(cr, 2.5);

//--------------------------------------------
//	Draw all short and long hash marks
//	21 marks - includes 1st and last
//	Center of arcs is (hor,ver).
//--------------------------------------------

	for (int i = 0; i< 21; i++ ) {

		if (X > t1) cairo_set_source_rgb(cr, 0.8, 0.8, 0.8);	// gray from now on

		if (! (i % 2) ) { // long hash marks

			cairo_arc (cr, hor, ver, len + 10.0, -M_PI, -M_PI + X);	// outer point of hash mark
			cairo_get_current_point (cr, &x, &y);

			cairo_arc (cr, hor, ver, len, -M_PI, -M_PI + X);	// nearer point of hash mark
			cairo_get_current_point (cr, &x1, &y1);
	
			cairo_new_path (cr);
			cairo_move_to(cr, x, y);
			cairo_line_to (cr, x1, y1 );
			cairo_stroke (cr);
			}

		else { // short hash marks
			cairo_arc (cr, hor, ver, len + 2.0, -M_PI, -M_PI + X); // further point
			cairo_get_current_point (cr, &x, &y);

			cairo_arc (cr, hor, ver, len - 1.0, -M_PI, -M_PI + X); // nearer point length
			cairo_get_current_point (cr, &x1, &y1);

			cairo_new_path (cr); // draw the mark
			cairo_move_to(cr, x, y);
			cairo_line_to (cr, x1, y1 );
			cairo_stroke (cr);
			}

		X = X + M_PI / 20.0; // advance point on arc
		}

//----------------
//	draw needle
//----------------

	cairo_set_source_rgb(cr, 1.0, 1.0, 0.3);	// yellow

//-------------------------------------
//	arc from left horizon to t1
//-------------------------------------

	cairo_arc (cr, hor, ver, len, -M_PI, -M_PI + t1);

//----------------------------------------
//	get coordinates of point on arc
//----------------------------------------

	cairo_get_current_point (cr, &x, &y);

//-----------------------------------------------
//	draw a line from the origin to the point
//-----------------------------------------------

	cairo_new_path (cr);
	cairo_move_to(cr, x, y);
	cairo_line_to (cr, hor, ver ); // (hor,ver) becomes current point (see below)
	cairo_stroke (cr);

//--------------
//	arcs
//--------------

        if (showArc) { 

//--------------------------------------------
//		draw arc from left horizon to t1
//--------------------------------------------

//--------------------------------------------------------------------------
//		"If there is a current point, an initial line segment will 
//		be added to the path to connect the current point to the 
//		beginning of the arc." Current point from above is (hor,ver)
//--------------------------------------------------------------------------

                cairo_arc (cr, hor, ver, len - 2.0, -M_PI, -M_PI + t1);
                cairo_line_to (cr, hor, ver );
                cairo_fill(cr); 
                cairo_stroke (cr);

                }

//----------------------------
//	central circular dot
//----------------------------

//--------------------------------------------------------------------
//	following adds line from current point to arc as well.
//	current point is the last cairo_line_to above (the origin)
//--------------------------------------------------------------------

	cairo_set_source_rgb(cr, 1.0, 1.0, 0.3);	// yellow
        cairo_arc (cr, hor, ver, 4.0, -M_PI, M_PI ); // full circle
        cairo_line_to (cr, hor, ver );
        cairo_fill(cr); // fill in arc

	}

//-----------------------------
//
//	draw meters
//
//-----------------------------

gboolean on_draw2_draw (GtkDrawingArea *widget, cairo_t *cr) {

	double hor, ver, len;

//	Load is from 0.0 to 1.0; Full meter semi-circle range is M_PI

	double t1 = (Load ) * M_PI;

        if (t1 > M_PI) t1 = M_PI; // limit

//--------------------------------------------------------------------
//	width and height set in on_window_configure_event() below
//	initial values are from initial signal and derived from
//	defaults size set in Glade (100,70). Negative ver adjustments
//	mean up.
//--------------------------------------------------------------------

//	center point halfway with a small margin for the left edge

	hor = (width - 10) / 2 + 4;

	ver = height;
	len = height - 35;

//	leave 20 pixels beneath the meter for a label

        needles(cr, hor, ver - 20, len, t1 ); // draw meter

	cairo_move_to (cr, hor - 25.0, ver - 4.0 ); // add caption
	cairo_show_text(cr, "CPU Load");
	cairo_stroke (cr);

	return FALSE;
	}

//----------------------------------------------
//	capture GDK size drag configure event
//----------------------------------------------

void on_window_configure_event(GtkWidget *win, GdkEvent *e) {

	static int w = 0, h = 0; // prior values

	width = e->configure.width;
	height = e->configure.height;

//-----------------------------------------------
//	accelerate shrinkage to speed things up
//-----------------------------------------------

	if (width < w || height < h) {  // getting smaller?
		width = width - 5;
		height = height - 5;
		}

	w = width; h = height; // remember old values

	gtk_widget_set_size_request (GTK_WIDGET(draw2), width - 4 , height - 4 );

	}
