/**************************************************************************
 *
 * HISTOGRAM.C -  Nagios Alert Histogram CGI
 *
 * Copyright (c) 2001-2002 Ethan Galstad (nagios@nagios.org)
 * Last Modified: 10-26-2002
 *
 * License:
 * 
 * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 *************************************************************************/

#include "../common/config.h"
#include "../common/locations.h"
#include "../common/common.h"
#include "../common/objects.h"
#include "../common/statusdata.h"

#include "cgiutils.h"
#include "getcgi.h"
#include "auth.h"

#include <gd.h>			/* Boutell's GD library function */
#include <gdfonts.h>		/* GD library small font definition */


/*#define DEBUG			1*/


#define HISTOGRAM_IMAGE         "histogram.png"

/* archived state types */
#define AS_NO_DATA              0
#define AS_PROGRAM_START        1
#define AS_PROGRAM_END          2
#define AS_HOST_UP		3
#define AS_HOST_DOWN		4
#define AS_HOST_UNREACHABLE	5
#define AS_SVC_OK		6
#define AS_SVC_UNKNOWN		7
#define AS_SVC_WARNING		8
#define AS_SVC_CRITICAL		9


/* display types */
#define DISPLAY_HOST_HISTOGRAM	        0
#define DISPLAY_SERVICE_HISTOGRAM	1
#define DISPLAY_NO_HISTOGRAM    	2

/* input types */
#define GET_INPUT_NONE                  0
#define GET_INPUT_TARGET_TYPE           1
#define GET_INPUT_HOST_TARGET           2
#define GET_INPUT_SERVICE_TARGET        3
#define GET_INPUT_OPTIONS               4

/* breakdown types */
#define BREAKDOWN_MONTHLY       0
#define BREAKDOWN_DAY_OF_MONTH  1
#define BREAKDOWN_DAY_OF_WEEK   2
#define BREAKDOWN_HOURLY        3

/* modes */
#define CREATE_HTML		0
#define CREATE_IMAGE		1

/* standard report times */
#define TIMEPERIOD_CUSTOM	0
#define TIMEPERIOD_TODAY	1
#define TIMEPERIOD_YESTERDAY	2
#define TIMEPERIOD_THISWEEK	3
#define TIMEPERIOD_LASTWEEK	4
#define TIMEPERIOD_THISMONTH	5
#define TIMEPERIOD_LASTMONTH	6
#define TIMEPERIOD_THISQUARTER	7
#define TIMEPERIOD_LASTQUARTER	8
#define TIMEPERIOD_THISYEAR	9
#define TIMEPERIOD_LASTYEAR	10
#define TIMEPERIOD_LAST24HOURS	11
#define TIMEPERIOD_LAST7DAYS	12


#define MAX_ARCHIVE_SPREAD	65
#define MAX_ARCHIVE		65
#define MAX_ARCHIVE_BACKTRACKS	60

#define DRAWING_WIDTH	        550
#define DRAWING_HEIGHT	        195
#define DRAWING_X_OFFSET	60
#define DRAWING_Y_OFFSET        235

#define GRAPH_HOST_UP                   1
#define GRAPH_HOST_DOWN                 2
#define GRAPH_HOST_UNREACHABLE          4
#define GRAPH_SERVICE_OK                8
#define GRAPH_SERVICE_WARNING           16
#define GRAPH_SERVICE_UNKNOWN           32
#define GRAPH_SERVICE_CRITICAL          64

#define GRAPH_HOST_PROBLEMS             6
#define GRAPH_HOST_ALL                  7

#define GRAPH_SERVICE_PROBLEMS          112
#define GRAPH_SERVICE_ALL               120

#define GRAPH_EVERYTHING                255


#define GRAPH_SOFT_STATETYPES           1
#define GRAPH_HARD_STATETYPES           2
#define GRAPH_ALL_STATETYPES            3




extern char main_config_file[MAX_FILENAME_LENGTH];
extern char url_images_path[MAX_FILENAME_LENGTH];
extern char url_stylesheets_path[MAX_FILENAME_LENGTH];
extern char physical_images_path[MAX_FILENAME_LENGTH];

extern host *host_list;
extern service *service_list;

extern int     log_rotation_method;



authdata current_authdata;


typedef struct timeslice_data_struct{
	unsigned long    service_ok;
	unsigned long    host_up;
	unsigned long    service_critical;
	unsigned long    host_down;
	unsigned long    service_unknown;
	unsigned long    host_unreachable;
	unsigned long    service_warning;
        }timeslice_data;


timeslice_data *tsdata;


void convert_timeperiod_to_times(int);
void compute_report_times(void);
void graph_all_histogram_data(void);
void add_archived_state(int,time_t);
void read_archived_state_data(void);
void scan_log_file_for_archived_state_data(char *);
void draw_line(int,int,int,int,int);
void draw_dashed_line(int,int,int,int,int);

void document_header(int);
void document_footer(void);
int process_cgivars(void);


time_t t1;
time_t t2;

int start_second=0;
int start_minute=0;
int start_hour=0;
int start_day=1;
int start_month=1;
int start_year=2000;
int end_second=0;
int end_minute=0;
int end_hour=24;
int end_day=1;
int end_month=1;
int end_year=2000;

int display_type=DISPLAY_NO_HISTOGRAM;
int mode=CREATE_HTML;
int input_type=GET_INPUT_NONE;
int timeperiod_type=TIMEPERIOD_LAST24HOURS;
int breakdown_type=BREAKDOWN_DAY_OF_MONTH;
int compute_time_from_parts=FALSE;

int initial_states_logged=FALSE;
int assume_state_retention=TRUE;
int new_states_only=FALSE;

int last_state=AS_NO_DATA;
int program_restart_has_occurred=FALSE;

int graph_events=GRAPH_EVERYTHING;
int graph_statetypes=GRAPH_HARD_STATETYPES;

int embedded=FALSE;
int display_header=TRUE;

char *host_name="";
char *svc_description="";

gdImagePtr histogram_image=0;
int color_white=0;
int color_black=0;
int color_red=0;
int color_darkred=0;
int color_green=0;
int color_yellow=0;
int color_orange=0;
int color_lightgray=0;
FILE *image_file=NULL;

int backtrack_archives=0;
int earliest_archive=0;
time_t earliest_time;
time_t latest_time;

int image_width=900;
int image_height=320;

int total_buckets=96;



int main(int argc, char **argv){
	int result=OK;
	char temp_buffer[MAX_INPUT_BUFFER];
	char image_template[MAX_INPUT_BUFFER];
	char start_timestring[MAX_INPUT_BUFFER];
	char end_timestring[MAX_INPUT_BUFFER];
	host *temp_host;
	service *temp_service;
	int is_authorized=TRUE;
	int found=FALSE;
	int days,hours,minutes,seconds;
	char *first_service=NULL;
	int x;
	time_t t3;
	time_t current_time;
	struct tm *t;

	/* initialize time period to last 24 hours */
	time(&t2);
	t1=(time_t)(t2-(60*60*24));

	/* get the arguments passed in the URL */
	process_cgivars();

	/* reset internal CGI variables */
	reset_cgi_vars();
	
	/* read the CGI configuration file */
	result=read_cgi_config_file(DEFAULT_CGI_CONFIG_FILE);
	if(result==ERROR){
		if(mode==CREATE_HTML){
			document_header(FALSE);
			cgi_config_file_error(DEFAULT_CGI_CONFIG_FILE);
			document_footer();
		        }
		return ERROR;
	        }

	/* read the main configuration file */
	result=read_main_config_file(main_config_file);
	if(result==ERROR){
		if(mode==CREATE_HTML){
			document_header(FALSE);
			main_config_file_error(main_config_file);
			document_footer();
		        }
		return ERROR;
	        }

	/* read all object configuration data */
	result=read_all_object_configuration_data(main_config_file,READ_ALL_OBJECT_DATA);
	if(result==ERROR){
		if(mode==CREATE_HTML){
			document_header(FALSE);
			object_data_error();
			document_footer();
		        }
		return ERROR;
                }

	/* read all status data */
	result=read_all_status_data(DEFAULT_CGI_CONFIG_FILE,READ_ALL_STATUS_DATA);
	if(result==ERROR){
		if(mode==CREATE_HTML){
			document_header(FALSE);
			status_data_error();
			document_footer();
		        }
		free_memory();
		return ERROR;
                }

	document_header(TRUE);

	/* get authentication information */
	get_authentication_information(&current_authdata);

	if(compute_time_from_parts==TRUE)
		compute_report_times();

	/* make sure times are sane, otherwise swap them */
	if(t2<t1){
		t3=t2;
		t2=t1;
		t1=t3;
	        }
			

	if(mode==CREATE_HTML && display_header==TRUE){

		/* begin top table */
		printf("<table border=0 width=100%% cellspacing=0 cellpadding=0>\n");
		printf("<tr>\n");

		/* left column of the first row */
		printf("<td align=left valign=top width=33%%>\n");

		if(display_type==DISPLAY_HOST_HISTOGRAM)
			snprintf(temp_buffer,sizeof(temp_buffer)-1,"Host Alert Histogram");
		else if(display_type==DISPLAY_SERVICE_HISTOGRAM)
			snprintf(temp_buffer,sizeof(temp_buffer)-1,"Service Alert Histogram");
		else
			snprintf(temp_buffer,sizeof(temp_buffer)-1,"Host and Service Alert Histogram");
		temp_buffer[sizeof(temp_buffer)-1]='\x0';
		display_info_table(temp_buffer,FALSE,&current_authdata);

		if(display_type!=DISPLAY_NO_HISTOGRAM && input_type==GET_INPUT_NONE){

			printf("<TABLE BORDER=1 CELLPADDING=0 CELLSPACING=0 CLASS='linkBox'>\n");
			printf("<TR><TD CLASS='linkBox'>\n");

			if(display_type==DISPLAY_HOST_HISTOGRAM){
				printf("<a href='%s?host=%s&t1=%lu&t2=%lu&assumestateretention=%s'>View Trends For This Host</a><BR>\n",TRENDS_CGI,url_encode(host_name),t1,t2,(assume_state_retention==TRUE)?"yes":"no");
				printf("<a href='%s?host=%s&t1=%lu&t2=%lu&assumestateretention=%s&show_log_entries'>View Availability Report For This Host</a><BR>\n",AVAIL_CGI,url_encode(host_name),t1,t2,(assume_state_retention==TRUE)?"yes":"no");
				printf("<a href='%s?host=%s'>View Status Detail For This Host</a><BR>\n",STATUS_CGI,url_encode(host_name));
				printf("<a href='%s?host=%s'>View History For This Host</a><BR>\n",HISTORY_CGI,url_encode(host_name));
				printf("<a href='%s?host=%s'>View Notifications For This Host</a><BR>\n",NOTIFICATIONS_CGI,url_encode(host_name));
		                }
			else{
				printf("<a href='%s?host=%s",TRENDS_CGI,url_encode(host_name));
				printf("&service=%s&t1=%lu&t2=%lu&assumestateretention=%s'>View Trends For This Service</a><BR>\n",url_encode(svc_description),t1,t2,(assume_state_retention==TRUE)?"yes":"no");
				printf("<a href='%s?host=%s",AVAIL_CGI,url_encode(host_name));
				printf("&service=%s&t1=%lu&t2=%lu&assumestateretention=%s&show_log_entries'>View Availability Report For This Service</a><BR>\n",url_encode(svc_description),t1,t2,(assume_state_retention==TRUE)?"yes":"no");
				printf("<A HREF='%s?host=%s&",HISTORY_CGI,url_encode(host_name));
				printf("service=%s'>View History This Service</A><BR>\n",url_encode(svc_description));
				printf("<A HREF='%s?host=%s&",NOTIFICATIONS_CGI,url_encode(host_name));
				printf("service=%s'>View Notifications This Service</A><BR>\n",url_encode(svc_description));
		                }

			printf("</TD></TR>\n");
			printf("</TABLE>\n");
		        }

		printf("</td>\n");

		/* center column of top row */
		printf("<td align=center valign=top width=33%%>\n");

		if(display_type!=DISPLAY_NO_HISTOGRAM && input_type==GET_INPUT_NONE){

			printf("<DIV ALIGN=CENTER CLASS='dataTitle'>\n");
			if(display_type==DISPLAY_HOST_HISTOGRAM)
				printf("Host '%s'",host_name);
			else if(display_type==DISPLAY_SERVICE_HISTOGRAM)
				printf("Service '%s' On Host '%s'",svc_description,host_name);
			printf("</DIV>\n");

			printf("<BR>\n");

			printf("<IMG SRC='%s%s' BORDER=0 ALT='%s Event Histogram'>\n",url_images_path,TRENDS_ICON,(display_type==DISPLAY_HOST_HISTOGRAM)?"Host":"Service");

			printf("<BR CLEAR=ALL>\n");

			get_time_string(&t1,start_timestring,sizeof(start_timestring)-1,SHORT_DATE_TIME);
			get_time_string(&t2,end_timestring,sizeof(end_timestring)-1,SHORT_DATE_TIME);
			printf("<div align=center class='reportRange'>%s to %s</div>\n",start_timestring,end_timestring);

			get_time_breakdown((time_t)(t2-t1),&days,&hours,&minutes,&seconds);
			printf("<div align=center class='reportDuration'>Duration: %dd %dh %dm %ds</div>\n",days,hours,minutes,seconds);
		        }

		printf("</td>\n");

		/* right hand column of top row */
		printf("<td align=right valign=bottom width=33%%>\n");

		printf("<table border=0 CLASS='optBox'>\n");

		if(display_type!=DISPLAY_NO_HISTOGRAM && input_type==GET_INPUT_NONE){

			printf("<form method=\"GET\" action=\"%s\">\n",HISTOGRAM_CGI);
			printf("<input type='hidden' name='t1' value='%lu'>\n",(unsigned long)t1);
			printf("<input type='hidden' name='t2' value='%lu'>\n",(unsigned long)t2);
			printf("<input type='hidden' name='host' value='%s'>\n",host_name);
			if(display_type==DISPLAY_SERVICE_HISTOGRAM)
				printf("<input type='hidden' name='service' value='%s'>\n",svc_description);


			printf("<tr><td CLASS='optBoxItem' valign=top align=left>Report period:</td><td CLASS='optBoxItem' valign=top align=left>Assume state retention:</td></tr>\n");
			printf("<tr><td CLASS='optBoxItem' valign=top align=left>\n");
			printf("<select name='timeperiod'>\n");
			printf("<option value=custom SELECTED>[ Current time range ]\n");
			printf("<option value=last24hours>Last 24 Hours\n");
			printf("<option value=today>Today\n");
			printf("<option value=yesterday>Yesterday\n");
			printf("<option value=thisweek>This Week\n");
			printf("<option value=last7days>Last 7 Days\n");
			printf("<option value=lastweek>Last Week\n");
			printf("<option value=thismonth>This Month\n");
			printf("<option value=lastmonth>Last Month\n");
			printf("<option value=thisyear>This Year\n");
			printf("<option value=lastyear>Last Year\n");
			printf("</select>\n");
			printf("</td><td CLASS='optBoxItem' valign=top align=left>\n");
			printf("<select name='assumestateretention'>\n");
			printf("<option value=yes %s>yes\n",(assume_state_retention==TRUE)?"SELECTED":"");
			printf("<option value=no %s>no\n",(assume_state_retention==TRUE)?"":"SELECTED");
			printf("</select>\n");
			printf("</td></tr>\n");

			printf("<tr><td CLASS='optBoxItem' valign=top align=left>Breakdown type:</td><td CLASS='optBoxItem' valign=top align=left>Initial states logged:</td></tr>\n");
			printf("<tr><td CLASS='optBoxItem' valign=top align=left>\n");
			printf("<select name='breakdown'>\n");
			printf("<option value=monthly %s>Month\n",(breakdown_type==BREAKDOWN_MONTHLY)?"SELECTED":"");
			printf("<option value=dayofmonth %s>Day of the Month\n",(breakdown_type==BREAKDOWN_DAY_OF_MONTH)?"SELECTED":"");
			printf("<option value=dayofweek %s>Day of the Week\n",(breakdown_type==BREAKDOWN_DAY_OF_WEEK)?"SELECTED":"");
			printf("<option value=hourly %s>Hour of the Day\n",(breakdown_type==BREAKDOWN_HOURLY)?"SELECTED":"");
			printf("</select>\n");
			printf("</td><td CLASS='optBoxItem' valign=top align=left>\n");
			printf("<select name='initialstateslogged'>\n");
			printf("<option value=yes %s>yes\n",(initial_states_logged==TRUE)?"SELECTED":"");
			printf("<option value=no %s>no\n",(initial_states_logged==TRUE)?"":"SELECTED");
			printf("</select>\n");
			printf("</td></tr>\n");

			printf("<tr><td CLASS='optBoxItem' valign=top align=left>Events to graph:</td><td CLASS='optBoxItem' valign=top align=left>Ignore repeated states:</td></tr>\n");
			printf("<tr><td CLASS='optBoxItem' valign=top align=left>\n");
			printf("<select name='graphevents'>\n");
			if(display_type==DISPLAY_HOST_HISTOGRAM){
				printf("<option value=%d %s>All host events\n",GRAPH_HOST_ALL,(graph_events==GRAPH_HOST_ALL)?"SELECTED":"");
				printf("<option value=%d %s>Host problem events\n",GRAPH_HOST_PROBLEMS,(graph_events==GRAPH_HOST_PROBLEMS)?"SELECTED":"");
				printf("<option value=%d %s>Host up events\n",GRAPH_HOST_UP,(graph_events==GRAPH_HOST_UP)?"SELECTED":"");
				printf("<option value=%d %s>Host down events\n",GRAPH_HOST_DOWN,(graph_events==GRAPH_HOST_DOWN)?"SELECTED":"");
				printf("<option value=%d %s>Host unreachable events\n",GRAPH_HOST_UNREACHABLE,(graph_events==GRAPH_HOST_UNREACHABLE)?"SELECTED":"");
			        }
			else{
				printf("<option value=%d %s>All service events\n",GRAPH_SERVICE_ALL,(graph_events==GRAPH_SERVICE_ALL)?"SELECTED":"");
				printf("<option value=%d %s>Service problem events\n",GRAPH_SERVICE_PROBLEMS,(graph_events==GRAPH_SERVICE_PROBLEMS)?"SELECTED":"");
				printf("<option value=%d %s>Service ok events\n",GRAPH_SERVICE_OK,(graph_events==GRAPH_SERVICE_OK)?"SELECTED":"");
				printf("<option value=%d %s>Service warning events\n",GRAPH_SERVICE_WARNING,(graph_events==GRAPH_SERVICE_WARNING)?"SELECTED":"");
				printf("<option value=%d %s>Service unknown events\n",GRAPH_SERVICE_UNKNOWN,(graph_events==GRAPH_SERVICE_UNKNOWN)?"SELECTED":"");
				printf("<option value=%d %s>Service critical events\n",GRAPH_SERVICE_CRITICAL,(graph_events==GRAPH_SERVICE_CRITICAL)?"SELECTED":"");
			        }
			printf("</select>\n");
			printf("</td><td CLASS='optBoxItem' valign=top align=left>\n");
			printf("<select name='newstatesonly'>\n");
			printf("<option value=yes %s>yes\n",(new_states_only==TRUE)?"SELECTED":"");
			printf("<option value=no %s>no\n",(new_states_only==TRUE)?"":"SELECTED");
			printf("</select>\n");
			printf("</td></tr>\n");

			printf("<tr><td CLASS='optBoxItem' valign=top align=left>State types to graph:</td><td CLASS='optBoxItem' valign=top align=left></td></tr>\n");
			printf("<tr><td CLASS='optBoxItem' valign=top align=left>\n");
			printf("<select name='graphstatetypes'>\n");
			printf("<option value=%d %s>Hard states\n",GRAPH_HARD_STATETYPES,(graph_statetypes==GRAPH_HARD_STATETYPES)?"SELECTED":"");
			printf("<option value=%d %s>Soft states\n",GRAPH_SOFT_STATETYPES,(graph_statetypes==GRAPH_SOFT_STATETYPES)?"SELECTED":"");
			printf("<option value=%d %s>Hard and soft states\n",GRAPH_ALL_STATETYPES,(graph_statetypes==GRAPH_ALL_STATETYPES)?"SELECTED":"");
			printf("</select>\n");
			printf("</td><td CLASS='optBoxItem' valign=top align=left>\n");
			printf("<input type='submit' value='Update'>\n");
			printf("</td></tr>\n");

			printf("</form>\n");
		        }

		/* display context-sensitive help */
		printf("<tr><td></td><td align=right valign=bottom>\n");
		if(display_type!=DISPLAY_NO_HISTOGRAM && input_type==GET_INPUT_NONE){
			if(display_type==DISPLAY_HOST_HISTOGRAM)
				display_context_help(CONTEXTHELP_HISTOGRAM_HOST);
			else
				display_context_help(CONTEXTHELP_HISTOGRAM_SERVICE);
		        }
		else if(display_type==DISPLAY_NO_HISTOGRAM || input_type!=GET_INPUT_NONE){
			if(input_type==GET_INPUT_NONE)
				display_context_help(CONTEXTHELP_HISTOGRAM_MENU1);
			else if(input_type==GET_INPUT_TARGET_TYPE)
				display_context_help(CONTEXTHELP_HISTOGRAM_MENU1);
			else if(input_type==GET_INPUT_HOST_TARGET)
				display_context_help(CONTEXTHELP_HISTOGRAM_MENU2);
			else if(input_type==GET_INPUT_SERVICE_TARGET)
				display_context_help(CONTEXTHELP_HISTOGRAM_MENU3);
			else if(input_type==GET_INPUT_OPTIONS)
				display_context_help(CONTEXTHELP_HISTOGRAM_MENU4);
		        }
		printf("</td></tr>\n");

		printf("</table>\n");

		printf("</td>\n");

		/* end of top table */
		printf("</tr>\n");
		printf("</table>\n");
	        }

	/* check authorization... */
	if(display_type==DISPLAY_HOST_HISTOGRAM){
		temp_host=find_host(host_name,NULL);
		if(temp_host==NULL || is_authorized_for_host(temp_host,&current_authdata)==FALSE)
			is_authorized=FALSE;
	        }
	else if(display_type==DISPLAY_SERVICE_HISTOGRAM){
		temp_service=find_service(host_name,svc_description,NULL);
		if(temp_service==NULL || is_authorized_for_service(temp_service,&current_authdata)==FALSE)
			is_authorized=FALSE;
	        }
	if(is_authorized==FALSE){

		if(mode==CREATE_HTML)
			printf("<P><DIV ALIGN=CENTER CLASS='errorMessage'>It appears as though you are not authorized to view information for the specified %s...</DIV></P>\n",(display_type==DISPLAY_HOST_HISTOGRAM)?"host":"service");

		document_footer();
		free_memory();
		return ERROR;
	        }

	if(display_type!=DISPLAY_NO_HISTOGRAM && input_type==GET_INPUT_NONE){

		/* print URL to image */
		if(mode==CREATE_HTML){

			printf("<BR><BR>\n");
			printf("<DIV ALIGN=CENTER>\n");
			printf("<IMG SRC='%s?createimage&t1=%lu&t2=%lu",HISTOGRAM_CGI,(unsigned long)t1,(unsigned long)t2);
			printf("&host=%s",url_encode(host_name));
			if(display_type==DISPLAY_SERVICE_HISTOGRAM)
				printf("&service=%s",url_encode(svc_description));
			printf("&breakdown=");
			if(breakdown_type==BREAKDOWN_MONTHLY)
				printf("monthly");
			else if(breakdown_type==BREAKDOWN_DAY_OF_MONTH)
				printf("dayofmonth");
			else if(breakdown_type==BREAKDOWN_DAY_OF_WEEK)
				printf("dayofweek");
			else
				printf("hourly");
			printf("&assumestateretention=%s",(assume_state_retention==TRUE)?"yes":"no");
			printf("&initialstateslogged=%s",(initial_states_logged==TRUE)?"yes":"no");
			printf("&newstatesonly=%s",(new_states_only==TRUE)?"yes":"no");
			printf("&graphevents=%d",graph_events);
			printf("&graphstatetypes=%d",graph_statetypes);
			printf("' BORDER=0 name='histogramimage'>\n");
			printf("</DIV>\n");
		        }

		/* read and process state data */
		else{

			/* allocate memory */
			tsdata=NULL;
			if(breakdown_type==BREAKDOWN_MONTHLY)
				total_buckets=12;
			else if(breakdown_type==BREAKDOWN_DAY_OF_MONTH)
				total_buckets=31;
			else if(breakdown_type==BREAKDOWN_DAY_OF_WEEK)
				total_buckets=7;
			else
				total_buckets=96;

			tsdata=(timeslice_data *)malloc(sizeof(timeslice_data)*total_buckets);
			if(tsdata==NULL)
				return ERROR;

			for(x=0;x<total_buckets;x++){
				tsdata[x].service_ok=0L;
				tsdata[x].service_unknown=0L;
				tsdata[x].service_warning=0L;
				tsdata[x].service_critical=0L;
				tsdata[x].host_up=0L;
				tsdata[x].host_down=0L;
				tsdata[x].host_unreachable=0L;
			        }

			/* read in all necessary archived state data */
			read_archived_state_data();

#ifdef DEBUG
			printf("Done reading archived state data.\n");
#endif

			/* location of image template */
			snprintf(image_template,sizeof(image_template)-1,"%s/%s",physical_images_path,HISTOGRAM_IMAGE);
			image_template[sizeof(image_template)-1]='\x0';

			/* allocate buffer for storing image */
			image_file=fopen(image_template,"r");
			if(image_file!=NULL){
				histogram_image=gdImageCreateFromPng(image_file);
				fclose(image_file);
			        }
			if(histogram_image==NULL)
				histogram_image=gdImageCreate(image_width,image_height);
			if(histogram_image==NULL){
#ifdef DEBUG
				printf("Error: Could not allocate memory for image\n");
#endif
				return ERROR;
	                        }

			/* allocate colors used for drawing */
			color_white=gdImageColorAllocate(histogram_image,255,255,255);
			color_black=gdImageColorAllocate(histogram_image,0,0,0);
			color_red=gdImageColorAllocate(histogram_image,255,0,0);
			color_darkred=gdImageColorAllocate(histogram_image,128,0,0);
			color_green=gdImageColorAllocate(histogram_image,0,128,0);
			color_yellow=gdImageColorAllocate(histogram_image,176,178,20);
			color_orange=gdImageColorAllocate(histogram_image,255,100,25);
			color_lightgray=gdImageColorAllocate(histogram_image,192,192,192);

			/* set transparency index */
			gdImageColorTransparent(histogram_image,color_white);

			/* make sure the graphic is interlaced */
			gdImageInterlace(histogram_image,1);

#ifdef DEBUG
			printf("Starting to graph data...\n");
#endif

			/* graph archived state histogram data */
			graph_all_histogram_data();

#ifdef DEBUG
			printf("Done graphing data.\n");
#endif

			/* use STDOUT for writing the image data... */
			image_file=stdout;

#ifdef DEBUG
			image_file=fopen("/tmp/histogram.png","w");
#endif

			/* write the image to to STDOUT */
			gdImagePng(histogram_image,image_file);
	
#ifdef DEBUG		
			fclose(image_file);
#endif

			/* free memory allocated to image */
			gdImageDestroy(histogram_image);

			/* free memory allocated for data */
			free(tsdata);
	                }
	        }


	/* show user a selection of hosts and services to choose from... */
	if(display_type==DISPLAY_NO_HISTOGRAM || input_type!=GET_INPUT_NONE){

		/* ask the user for what host they want a report for */
		if(input_type==GET_INPUT_HOST_TARGET){

			printf("<P><DIV ALIGN=CENTER>\n");
			printf("<DIV CLASS='reportSelectTitle'>Step 2: Select Host</DIV>\n");
			printf("</DIV></P>\n");

			printf("<P><DIV ALIGN=CENTER>\n");

			printf("<TABLE BORDER=0 cellspacing=0 cellpadding=10>\n");
			printf("<form method=\"GET\" action=\"%s\">\n",HISTOGRAM_CGI);
			printf("<input type='hidden' name='input' value='getoptions'>\n");

			printf("<tr><td class='reportSelectSubTitle' valign=center>Host</td>\n");
			printf("<td class='reportSelectItem' valing=center>\n");
			printf("<select name='host'>\n");

			for(temp_host=host_list;temp_host!=NULL;temp_host=temp_host->next){
				if(is_authorized_for_host(temp_host,&current_authdata)==TRUE)
					printf("<option value='%s'>%s\n",temp_host->name,temp_host->name);
			        }

			printf("</select>\n");
			printf("</td></tr>\n");

			printf("<tr><td></td><td class='reportSelectItem'>\n");
			printf("<input type='submit' value='Continue to Step 3'>\n");
			printf("</td></tr>\n");

			printf("</form>\n");
			printf("</TABLE>\n");

			printf("</DIV></P>\n");
		        }

		/* ask the user for what service they want a report for */
		else if(input_type==GET_INPUT_SERVICE_TARGET){

			printf("<SCRIPT LANGUAGE='JavaScript'>\n");
			printf("function gethostname(hostindex){\n");
			printf("hostnames=[");

			for(temp_service=service_list;temp_service!=NULL;temp_service=temp_service->next){
				if(is_authorized_for_service(temp_service,&current_authdata)==TRUE){
					if(found==TRUE)
						printf(",");
					else
						first_service=temp_service->host_name;
					printf(" \"%s\"",temp_service->host_name);
					found=TRUE;
			                }
		                }
		
			printf(" ]\n");
			printf("return hostnames[hostindex];\n");
			printf("}\n");
			printf("</SCRIPT>\n");


			printf("<P><DIV ALIGN=CENTER>\n");
			printf("<DIV CLASS='reportSelectTitle'>Step 2: Select Service</DIV>\n");
			printf("</DIV></P>\n");

			printf("<P><DIV ALIGN=CENTER>\n");
			
			printf("<TABLE BORDER=0 cellpadding=5>\n");
			printf("<form method=\"GET\" action=\"%s\" name=\"serviceform\">\n",HISTOGRAM_CGI);
			printf("<input type='hidden' name='input' value='getoptions'>\n");
			printf("<input type='hidden' name='host' value='%s'>\n",(first_service==NULL)?"unknown":first_service);

			printf("<tr><td class='reportSelectSubTitle'>Service:</td>\n");
			printf("<td class='reportSelectItem'>\n");
			printf("<select name='service' onFocus='document.serviceform.host.value=gethostname(this.selectedIndex);' onChange='document.serviceform.host.value=gethostname(this.selectedIndex);'>\n");

			for(temp_service=service_list;temp_service!=NULL;temp_service=temp_service->next){
				if(is_authorized_for_service(temp_service,&current_authdata)==TRUE)
					printf("<option value='%s'>%s;%s\n",temp_service->description,temp_service->host_name,temp_service->description);
		                }

			printf("</select>\n");
			printf("</td></tr>\n");

			printf("<tr><td></td><td class='reportSelectItem'>\n");
			printf("<input type='submit' value='Continue to Step 3'>\n");
			printf("</td></tr>\n");

			printf("</form>\n");
			printf("</TABLE>\n");

			printf("</DIV></P>\n");
		        }

		/* ask the user for report range and options */
		else if(input_type==GET_INPUT_OPTIONS){

			time(&current_time);
			t=localtime(&current_time);

			start_day=1;
			start_year=t->tm_year+1900;
			end_day=t->tm_mday;
			end_year=t->tm_year+1900;

			printf("<P><DIV ALIGN=CENTER>\n");
			printf("<DIV CLASS='reportSelectTitle'>Step 3: Select Report Options</DIV>\n");
			printf("</DIV></P>\n");

			printf("<P><DIV ALIGN=CENTER>\n");

			printf("<TABLE BORDER=0 cellpadding=5>\n");
			printf("<form method=\"GET\" action=\"%s\">\n",HISTOGRAM_CGI);
			printf("<input type='hidden' name='host' value='%s'>\n",host_name);
			if(display_type==DISPLAY_SERVICE_HISTOGRAM)
				printf("<input type='hidden' name='service' value='%s'>\n",svc_description);

			printf("<tr><td class='reportSelectSubTitle' align=right>Report Period:</td>\n");
			printf("<td class='reportSelectItem'>\n");
			printf("<select name='timeperiod'>\n");
			printf("<option value=last24hours>Last 24 Hours\n");
			printf("<option value=today>Today\n");
			printf("<option value=yesterday>Yesterday\n");
			printf("<option value=thisweek>This Week\n");
			printf("<option value=last7days SELECTED>Last 7 Days\n");
			printf("<option value=lastweek>Last Week\n");
			printf("<option value=thismonth>This Month\n");
			printf("<option value=lastmonth>Last Month\n");
			printf("<option value=thisyear>This Year\n");
			printf("<option value=lastyear>Last Year\n");
			printf("<option value=custom>* CUSTOM REPORT PERIOD *\n");
			printf("</select>\n");
			printf("</td></tr>\n");

			printf("<tr><td colspan=2 valign=top calss='reportSelectSubTitle'><i>If Custom Report Period...</i></td></tr>\n");

			printf("<tr>");
			printf("<td valign=top class='reportSelectSubTitle'>Start Date (Inclusive):</td>\n");
			printf("<td align=left valign=top class='reportSelectItem'>");
			printf("<select name='smon'>\n");
			printf("<option value='1' %s>January\n",(t->tm_mon==0)?"SELECTED":"");
			printf("<option value='2' %s>February\n",(t->tm_mon==1)?"SELECTED":"");
			printf("<option value='3' %s>March\n",(t->tm_mon==2)?"SELECTED":"");
			printf("<option value='4' %s>April\n",(t->tm_mon==3)?"SELECTED":"");
			printf("<option value='5' %s>May\n",(t->tm_mon==4)?"SELECTED":"");
			printf("<option value='6' %s>June\n",(t->tm_mon==5)?"SELECTED":"");
			printf("<option value='7' %s>July\n",(t->tm_mon==6)?"SELECTED":"");
			printf("<option value='8' %s>August\n",(t->tm_mon==7)?"SELECTED":"");
			printf("<option value='9' %s>September\n",(t->tm_mon==8)?"SELECTED":"");
			printf("<option value='10' %s>October\n",(t->tm_mon==9)?"SELECTED":"");
			printf("<option value='11' %s>November\n",(t->tm_mon==10)?"SELECTED":"");
			printf("<option value='12' %s>December\n",(t->tm_mon==11)?"SELECTED":"");
			printf("</select>\n ");
			printf("<input type='text' size='2' maxlength='2' name='sday' value='%d'> ",start_day);
			printf("<input type='text' size='4' maxlength='4' name='syear' value='%d'>",start_year);
			printf("<input type='hidden' name='shour' value='0'>\n");
			printf("<input type='hidden' name='smin' value='0'>\n");
			printf("<input type='hidden' name='ssec' value='0'>\n");
			printf("</td>\n");
			printf("</tr>\n");

			printf("<tr>");
			printf("<td valign=top class='reportSelectSubTitle'>End Date (Inclusive):</td>\n");
			printf("<td align=left valign=top class='reportSelectItem'>");
			printf("<select name='emon'>\n");
			printf("<option value='1' %s>January\n",(t->tm_mon==0)?"SELECTED":"");
			printf("<option value='2' %s>February\n",(t->tm_mon==1)?"SELECTED":"");
			printf("<option value='3' %s>March\n",(t->tm_mon==2)?"SELECTED":"");
			printf("<option value='4' %s>April\n",(t->tm_mon==3)?"SELECTED":"");
			printf("<option value='5' %s>May\n",(t->tm_mon==4)?"SELECTED":"");
			printf("<option value='6' %s>June\n",(t->tm_mon==5)?"SELECTED":"");
			printf("<option value='7' %s>July\n",(t->tm_mon==6)?"SELECTED":"");
			printf("<option value='8' %s>August\n",(t->tm_mon==7)?"SELECTED":"");
			printf("<option value='9' %s>September\n",(t->tm_mon==8)?"SELECTED":"");
			printf("<option value='10' %s>October\n",(t->tm_mon==9)?"SELECTED":"");
			printf("<option value='11' %s>November\n",(t->tm_mon==10)?"SELECTED":"");
			printf("<option value='12' %s>December\n",(t->tm_mon==11)?"SELECTED":"");
			printf("</select>\n ");
			printf("<input type='text' size='2' maxlength='2' name='eday' value='%d'> ",end_day);
			printf("<input type='text' size='4' maxlength='4' name='eyear' value='%d'>",end_year);
			printf("<input type='hidden' name='ehour' value='24'>\n");
			printf("<input type='hidden' name='emin' value='0'>\n");
			printf("<input type='hidden' name='esec' value='0'>\n");
			printf("</td>\n");
			printf("</tr>\n");

			printf("<tr><td colspan=2><br></td></tr>\n");

			printf("<tr><td class='reportSelectSubTitle' align=right>Statistics Breakdown:</td>\n");
			printf("<td class='reportSelectItem'>\n");
			printf("<select name='breakdown'>\n");
			printf("<option value=monthly>Month\n");
			printf("<option value=dayofmonth SELECTED>Day of the Month\n");
			printf("<option value=dayofweek>Day of the Week\n");
			printf("<option value=hourly>Hour of the Day\n");
			printf("</select>\n");
			printf("</td></tr>\n");

			printf("<tr><td class='reportSelectSubTitle' align=right>Events To Graph:</td>\n");
			printf("<td class='reportSelectItem'>\n");
			printf("<select name='graphevents'>\n");
			if(display_type==DISPLAY_HOST_HISTOGRAM){
				printf("<option value=%d %s>All host events\n",GRAPH_HOST_ALL,(graph_events==GRAPH_HOST_ALL)?"SELECTED":"");
				printf("<option value=%d %s>Host problem events\n",GRAPH_HOST_PROBLEMS,(graph_events==GRAPH_HOST_PROBLEMS)?"SELECTED":"");
				printf("<option value=%d %s>Host up events\n",GRAPH_HOST_UP,(graph_events==GRAPH_HOST_UP)?"SELECTED":"");
				printf("<option value=%d %s>Host down events\n",GRAPH_HOST_DOWN,(graph_events==GRAPH_HOST_DOWN)?"SELECTED":"");
				printf("<option value=%d %s>Host unreachable events\n",GRAPH_HOST_UNREACHABLE,(graph_events==GRAPH_HOST_UNREACHABLE)?"SELECTED":"");
			        }
			else{
				printf("<option value=%d %s>All service events\n",GRAPH_SERVICE_ALL,(graph_events==GRAPH_SERVICE_ALL)?"SELECTED":"");
				printf("<option value=%d %s>Service problem events\n",GRAPH_SERVICE_PROBLEMS,(graph_events==GRAPH_SERVICE_PROBLEMS)?"SELECTED":"");
				printf("<option value=%d %s>Service ok events\n",GRAPH_SERVICE_OK,(graph_events==GRAPH_SERVICE_OK)?"SELECTED":"");
				printf("<option value=%d %s>Service warning events\n",GRAPH_SERVICE_WARNING,(graph_events==GRAPH_SERVICE_WARNING)?"SELECTED":"");
				printf("<option value=%d %s>Service unknown events\n",GRAPH_SERVICE_UNKNOWN,(graph_events==GRAPH_SERVICE_UNKNOWN)?"SELECTED":"");
				printf("<option value=%d %s>Service critical events\n",GRAPH_SERVICE_CRITICAL,(graph_events==GRAPH_SERVICE_CRITICAL)?"SELECTED":"");
			        }
			printf("</select>\n");
			printf("</td></tr>\n");

			printf("<tr><td class='reportSelectSubTitle' align=right>State Types To Graph:</td>\n");
			printf("<td class='reportSelectItem'>\n");
			printf("<select name='graphstatetypes'>\n");
			printf("<option value=%d>Hard states\n",GRAPH_HARD_STATETYPES);
			printf("<option value=%d>Soft states\n",GRAPH_SOFT_STATETYPES);
			printf("<option value=%d SELECTED>Hard and soft states\n",GRAPH_ALL_STATETYPES);
			printf("</select>\n");
			printf("</td></tr>\n");

			printf("<tr><td class='reportSelectSubTitle' align=right>Assume State Retention:</td>\n");
			printf("<td class='reportSelectItem'>\n");
			printf("<select name='assumestateretention'>\n");
			printf("<option value='yes'>Yes\n");
			printf("<option value='no'>No\n");
			printf("</select>\n");
			printf("</td></tr>\n");

			printf("<tr><td class='reportSelectSubTitle' align=right>Initial States Logged:</td>\n");
			printf("<td class='reportSelectItem'>\n");
			printf("<select name='initialstateslogged'>\n");
			printf("<option value='yes'>Yes\n");
			printf("<option value='no' SELECTED>No\n");
			printf("</select>\n");
			printf("</td></tr>\n");

			printf("<tr><td class='reportSelectSubTitle' align=right>Ignore Repeated States:</td>\n");
			printf("<td class='reportSelectItem'>\n");
			printf("<select name='newstatesonly'>\n");
			printf("<option value='yes'>Yes\n");
			printf("<option value='no' SELECTED>No\n");
			printf("</select>\n");
			printf("</td></tr>\n");

			printf("<tr><td></td><td class='reportSelectItem'><input type='submit' value='Create Report'></td></tr>\n");

			printf("</form>\n");
			printf("</TABLE>\n");

			printf("</DIV></P>\n");
		        }

		/* as the user whether they want a graph for a host or service */
		else{
			printf("<P><DIV ALIGN=CENTER>\n");
			printf("<DIV CLASS='reportSelectTitle'>Step 1: Select Report Type</DIV>\n");
			printf("</DIV></P>\n");

			printf("<P><DIV ALIGN=CENTER>\n");

			printf("<TABLE BORDER=0 cellpadding=5>\n");
			printf("<form method=\"GET\" action=\"%s\">\n",HISTOGRAM_CGI);

			printf("<tr><td class='reportSelectSubTitle'><input type='radio' name='input' value='gethost'></td><td class='reportSelectItem'>Host</td></tr>\n");
			printf("<tr><td class='reportSelectSubTitle'><input type='radio' name='input' value='getservice'></td><td class='reportSelectItem'>Service</td></tr>\n");

			printf("<tr><td></td><td class='reportSelectItem'>\n");
			printf("<input type='submit' value='Continue to Step 2'>\n");
			printf("</td></tr>\n");

			printf("</form>\n");
			printf("</TABLE>\n");

			printf("</DIV></P>\n");
		        }
		
                }

	document_footer();

	/* free all other allocated memory */
	free_memory();

	return OK;
        }


void document_header(int use_stylesheet){
	char date_time[MAX_DATETIME_LENGTH];
	time_t current_time;
	time_t expire_time;

	if(mode==CREATE_HTML){
		printf("Cache-Control: no-store\n");
		printf("Pragma: no-cache\n");

		time(&current_time);
		get_time_string(&current_time,date_time,sizeof(date_time),HTTP_DATE_TIME);
		printf("Last-Modified: %s\n",date_time);

		expire_time=(time_t)0;
		get_time_string(&expire_time,date_time,sizeof(date_time),HTTP_DATE_TIME);
		printf("Expires: %s\n",date_time);

		printf("Content-type: text/html\n\n");

		if(embedded==TRUE)
			return;

		printf("<html>\n");
		printf("<head>\n");
		printf("<title>\n");
		printf("Nagios Histogram\n");
		printf("</title>\n");

		if(use_stylesheet==TRUE)
			printf("<LINK REL='stylesheet' TYPE='text/css' HREF='%s%s'>\n",url_stylesheets_path,HISTOGRAM_CSS);
	
		printf("</head>\n");

		printf("<BODY CLASS='histogram'>\n");

		/* include user SSI header */
		include_ssi_files(HISTOGRAM_CGI,SSI_HEADER);

		printf("<div id=\"popup\" style=\"position:absolute; z-index:1; visibility: hidden\"></div>\n");
	        }

	else{
		printf("Cache-Control: no-store\n");
		printf("Pragma: no-cache\n");

		time(&current_time);
		get_time_string(&current_time,date_time,sizeof(date_time),HTTP_DATE_TIME);
		printf("Last-Modified: %s\n",date_time);

		expire_time=(time_t)0L;
		get_time_string(&expire_time,date_time,sizeof(date_time),HTTP_DATE_TIME);
		printf("Expires: %s\n",date_time);

		printf("Content-Type: image/png\n\n");
	        }

	return;
        }



void document_footer(void){

	if(embedded==TRUE)
		return;

	if(mode==CREATE_HTML){

		/* include user SSI footer */
		include_ssi_files(HISTOGRAM_CGI,SSI_FOOTER);

		printf("</body>\n");
		printf("</html>\n");
	        }

	return;
        }



int process_cgivars(void){
	char **variables;
	int error=FALSE;
	int x;

	variables=getcgivars();

	for(x=0;variables[x]!=NULL;x++){

		/* do some basic length checking on the variable identifier to prevent buffer overflows */
		if(strlen(variables[x])>=MAX_INPUT_BUFFER-1){
			x++;
			continue;
		        }

		/* we found the host argument */
		else if(!strcmp(variables[x],"host")){
			x++;
			if(variables[x]==NULL){
				error=TRUE;
				break;
			        }

			host_name=(char *)malloc(strlen(variables[x])+1);
			if(host_name==NULL)
				host_name="";
			else
				strcpy(host_name,variables[x]);

			display_type=DISPLAY_HOST_HISTOGRAM;
		        }

		/* we found the node width argument */
		else if(!strcmp(variables[x],"service")){
			x++;
			if(variables[x]==NULL){
				error=TRUE;
				break;
			        }

			svc_description=(char *)malloc(strlen(variables[x])+1);
			if(svc_description==NULL)
				svc_description="";
			else
				strcpy(svc_description,variables[x]);

			display_type=DISPLAY_SERVICE_HISTOGRAM;
		        }

		/* we found first time argument */
		else if(!strcmp(variables[x],"t1")){
			x++;
			if(variables[x]==NULL){
				error=TRUE;
				break;
			        }

			t1=(time_t)strtoul(variables[x],NULL,10);
			timeperiod_type=TIMEPERIOD_CUSTOM;
		        }

		/* we found first time argument */
		else if(!strcmp(variables[x],"t2")){
			x++;
			if(variables[x]==NULL){
				error=TRUE;
				break;
			        }

			t2=(time_t)strtoul(variables[x],NULL,10);
			timeperiod_type=TIMEPERIOD_CUSTOM;
		        }

		/* we found the image creation option */
		else if(!strcmp(variables[x],"createimage")){
			mode=CREATE_IMAGE;
		        }

		/* we found the backtrack archives argument */
		else if(!strcmp(variables[x],"backtrack")){
			x++;
			if(variables[x]==NULL){
				error=TRUE;
				break;
			        }

			backtrack_archives=atoi(variables[x]);
			if(backtrack_archives<0)
				backtrack_archives=0;
			if(backtrack_archives>MAX_ARCHIVE_BACKTRACKS)
				backtrack_archives=MAX_ARCHIVE_BACKTRACKS;
		        }

		/* we found the standard timeperiod argument */
		else if(!strcmp(variables[x],"timeperiod")){
			x++;
			if(variables[x]==NULL){
				error=TRUE;
				break;
			        }

			if(!strcmp(variables[x],"today"))
				timeperiod_type=TIMEPERIOD_TODAY;
			else if(!strcmp(variables[x],"yesterday"))
				timeperiod_type=TIMEPERIOD_YESTERDAY;
			else if(!strcmp(variables[x],"thisweek"))
				timeperiod_type=TIMEPERIOD_THISWEEK;
			else if(!strcmp(variables[x],"lastweek"))
				timeperiod_type=TIMEPERIOD_LASTWEEK;
			else if(!strcmp(variables[x],"thismonth"))
				timeperiod_type=TIMEPERIOD_THISMONTH;
			else if(!strcmp(variables[x],"lastmonth"))
				timeperiod_type=TIMEPERIOD_LASTMONTH;
			else if(!strcmp(variables[x],"thisquarter"))
				timeperiod_type=TIMEPERIOD_THISQUARTER;
			else if(!strcmp(variables[x],"lastquarter"))
				timeperiod_type=TIMEPERIOD_LASTQUARTER;
			else if(!strcmp(variables[x],"thisyear"))
				timeperiod_type=TIMEPERIOD_THISYEAR;
			else if(!strcmp(variables[x],"lastyear"))
				timeperiod_type=TIMEPERIOD_LASTYEAR;
			else if(!strcmp(variables[x],"last24hours"))
				timeperiod_type=TIMEPERIOD_LAST24HOURS;
			else if(!strcmp(variables[x],"last7days"))
				timeperiod_type=TIMEPERIOD_LAST7DAYS;
			else if(!strcmp(variables[x],"custom"))
				timeperiod_type=TIMEPERIOD_CUSTOM;
			else
				timeperiod_type=TIMEPERIOD_TODAY;

	
			if(timeperiod_type!=TIMEPERIOD_CUSTOM)
				convert_timeperiod_to_times(timeperiod_type);
		        }

		/* we found time argument */
		else if(!strcmp(variables[x],"smon")){
			x++;
			if(variables[x]==NULL){
				error=TRUE;
				break;
			        }

			if(timeperiod_type!=TIMEPERIOD_CUSTOM)
				continue;

			start_month=atoi(variables[x]);
			timeperiod_type=TIMEPERIOD_CUSTOM;
			compute_time_from_parts=TRUE;
		        }

		/* we found time argument */
		else if(!strcmp(variables[x],"sday")){
			x++;
			if(variables[x]==NULL){
				error=TRUE;
				break;
			        }

			if(timeperiod_type!=TIMEPERIOD_CUSTOM)
				continue;

			start_day=atoi(variables[x]);
			timeperiod_type=TIMEPERIOD_CUSTOM;
			compute_time_from_parts=TRUE;
		        }

		/* we found time argument */
		else if(!strcmp(variables[x],"syear")){
			x++;
			if(variables[x]==NULL){
				error=TRUE;
				break;
			        }

			if(timeperiod_type!=TIMEPERIOD_CUSTOM)
				continue;

			start_year=atoi(variables[x]);
			timeperiod_type=TIMEPERIOD_CUSTOM;
			compute_time_from_parts=TRUE;
		        }

		/* we found time argument */
		else if(!strcmp(variables[x],"smin")){
			x++;
			if(variables[x]==NULL){
				error=TRUE;
				break;
			        }

			if(timeperiod_type!=TIMEPERIOD_CUSTOM)
				continue;

			start_minute=atoi(variables[x]);
			timeperiod_type=TIMEPERIOD_CUSTOM;
			compute_time_from_parts=TRUE;
		        }

		/* we found time argument */
		else if(!strcmp(variables[x],"ssec")){
			x++;
			if(variables[x]==NULL){
				error=TRUE;
				break;
			        }

			if(timeperiod_type!=TIMEPERIOD_CUSTOM)
				continue;

			start_second=atoi(variables[x]);
			timeperiod_type=TIMEPERIOD_CUSTOM;
			compute_time_from_parts=TRUE;
		        }

		/* we found time argument */
		else if(!strcmp(variables[x],"shour")){
			x++;
			if(variables[x]==NULL){
				error=TRUE;
				break;
			        }

			if(timeperiod_type!=TIMEPERIOD_CUSTOM)
				continue;

			start_hour=atoi(variables[x]);
			timeperiod_type=TIMEPERIOD_CUSTOM;
			compute_time_from_parts=TRUE;
		        }


		/* we found time argument */
		else if(!strcmp(variables[x],"emon")){
			x++;
			if(variables[x]==NULL){
				error=TRUE;
				break;
			        }

			if(timeperiod_type!=TIMEPERIOD_CUSTOM)
				continue;

			end_month=atoi(variables[x]);
			timeperiod_type=TIMEPERIOD_CUSTOM;
			compute_time_from_parts=TRUE;
		        }

		/* we found time argument */
		else if(!strcmp(variables[x],"eday")){
			x++;
			if(variables[x]==NULL){
				error=TRUE;
				break;
			        }

			if(timeperiod_type!=TIMEPERIOD_CUSTOM)
				continue;

			end_day=atoi(variables[x]);
			timeperiod_type=TIMEPERIOD_CUSTOM;
			compute_time_from_parts=TRUE;
		        }

		/* we found time argument */
		else if(!strcmp(variables[x],"eyear")){
			x++;
			if(variables[x]==NULL){
				error=TRUE;
				break;
			        }

			if(timeperiod_type!=TIMEPERIOD_CUSTOM)
				continue;

			end_year=atoi(variables[x]);
			timeperiod_type=TIMEPERIOD_CUSTOM;
			compute_time_from_parts=TRUE;
		        }

		/* we found time argument */
		else if(!strcmp(variables[x],"emin")){
			x++;
			if(variables[x]==NULL){
				error=TRUE;
				break;
			        }

			if(timeperiod_type!=TIMEPERIOD_CUSTOM)
				continue;

			end_minute=atoi(variables[x]);
			timeperiod_type=TIMEPERIOD_CUSTOM;
			compute_time_from_parts=TRUE;
		        }

		/* we found time argument */
		else if(!strcmp(variables[x],"esec")){
			x++;
			if(variables[x]==NULL){
				error=TRUE;
				break;
			        }

			if(timeperiod_type!=TIMEPERIOD_CUSTOM)
				continue;

			end_second=atoi(variables[x]);
			timeperiod_type=TIMEPERIOD_CUSTOM;
			compute_time_from_parts=TRUE;
		        }

		/* we found time argument */
		else if(!strcmp(variables[x],"ehour")){
			x++;
			if(variables[x]==NULL){
				error=TRUE;
				break;
			        }

			if(timeperiod_type!=TIMEPERIOD_CUSTOM)
				continue;

			end_hour=atoi(variables[x]);
			timeperiod_type=TIMEPERIOD_CUSTOM;
			compute_time_from_parts=TRUE;
		        }

		/* we found the embed option */
		else if(!strcmp(variables[x],"embedded"))
			embedded=TRUE;

		/* we found the noheader option */
		else if(!strcmp(variables[x],"noheader"))
			display_header=FALSE;

		/* we found the input option */
		else if(!strcmp(variables[x],"input")){
			x++;
			if(variables[x]==NULL){
				error=TRUE;
				break;
			        }

			if(!strcmp(variables[x],"gethost"))
				input_type=GET_INPUT_HOST_TARGET;
			else if(!strcmp(variables[x],"getservice"))
				input_type=GET_INPUT_SERVICE_TARGET;
			else if(!strcmp(variables[x],"getoptions"))
				input_type=GET_INPUT_OPTIONS;
			else
				input_type=GET_INPUT_TARGET_TYPE;
		        }

		/* we found the graph states option */
		else if(!strcmp(variables[x],"graphevents")){
			x++;
			if(variables[x]==NULL){
				error=TRUE;
				break;
			        }

			graph_events=atoi(variables[x]);
		        }

		/* we found the graph state types option */
		else if(!strcmp(variables[x],"graphstatetypes")){
			x++;
			if(variables[x]==NULL){
				error=TRUE;
				break;
			        }

			graph_statetypes=atoi(variables[x]);
		        }

		/* we found the breakdown option */
		else if(!strcmp(variables[x],"breakdown")){
			x++;
			if(variables[x]==NULL){
				error=TRUE;
				break;
			        }

			if(!strcmp(variables[x],"monthly"))
				breakdown_type=BREAKDOWN_MONTHLY;
			else if(!strcmp(variables[x],"dayofmonth"))
				breakdown_type=BREAKDOWN_DAY_OF_MONTH;
			else if(!strcmp(variables[x],"dayofweek"))
				breakdown_type=BREAKDOWN_DAY_OF_WEEK;
			else
				breakdown_type=BREAKDOWN_HOURLY;
		        }

		/* we found the assume state retention option */
		else if(!strcmp(variables[x],"assumestateretention")){
			x++;
			if(variables[x]==NULL){
				error=TRUE;
				break;
			        }

			if(!strcmp(variables[x],"yes"))
				assume_state_retention=TRUE;
			else
				assume_state_retention=FALSE;
		        }

		/* we found the initial states logges option */
		else if(!strcmp(variables[x],"initialstateslogged")){
			x++;
			if(variables[x]==NULL){
				error=TRUE;
				break;
			        }

			if(!strcmp(variables[x],"yes"))
				initial_states_logged=TRUE;
			else
				initial_states_logged=FALSE;

		        }

		/* we found the new states only option */
		else if(!strcmp(variables[x],"newstatesonly")){
			x++;
			if(variables[x]==NULL){
				error=TRUE;
				break;
			        }

			if(!strcmp(variables[x],"yes"))
				new_states_only=TRUE;
			else
				new_states_only=FALSE;

		        }
	        }

	/* free memory allocated to the CGI variables */
	free_cgivars(variables);

	return error;
        }



/* graphs histogram data */
void graph_all_histogram_data(void){
	int pixel_x;
	int pixel_y;
	int last_pixel_y;
	int current_bucket;
	int actual_bucket;
	unsigned long max_value;
	double x_scaling_factor;
	double y_scaling_factor;
	double x_units;
	double y_units;
	int current_unit;
	int actual_unit;
	char temp_buffer[MAX_INPUT_BUFFER];
	int string_width;
	int string_height;
	char *days[7]={"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"};
	char *months[12]={"January","February","March","April","May","June","July","August","September","October","November","December"};
	char start_time[MAX_INPUT_BUFFER];
	char end_time[MAX_INPUT_BUFFER];

	unsigned long state1_max=0L;
	unsigned long state1_min=0L;
	int have_state1_min=FALSE;
	unsigned long state1_sum=0L;
	double state1_avg=0.0;
	unsigned long state2_max=0L;
	unsigned long state2_min=0L;
	int have_state2_min=FALSE;
	unsigned long state2_sum=0L;
	double state2_avg=0.0;
	unsigned long state3_max=0L;
	unsigned long state3_min=0L;
	int have_state3_min=FALSE;
	unsigned long state3_sum=0L;
	double state3_avg=0.0;
	unsigned long state4_max=0L;
	unsigned long state4_min=0L;
	int have_state4_min=FALSE;
	unsigned long state4_sum=0L;
	double state4_avg=0.0;


#ifdef DEBUG
	printf("Total Buckets: %d\n",total_buckets);
#endif

	/* determine max value in the buckets (for scaling) */
	max_value=0L;
	for(current_bucket=0;current_bucket<total_buckets;current_bucket++){
		if(tsdata[current_bucket].service_ok>max_value)
			max_value=tsdata[current_bucket].service_ok;
		if(tsdata[current_bucket].service_warning>max_value)
			max_value=tsdata[current_bucket].service_warning;
		if(tsdata[current_bucket].service_unknown>max_value)
			max_value=tsdata[current_bucket].service_unknown;
		if(tsdata[current_bucket].service_critical>max_value)
			max_value=tsdata[current_bucket].service_critical;
		if(tsdata[current_bucket].host_up>max_value)
			max_value=tsdata[current_bucket].host_up;
		if(tsdata[current_bucket].host_down>max_value)
			max_value=tsdata[current_bucket].host_down;
		if(tsdata[current_bucket].host_unreachable>max_value)
			max_value=tsdata[current_bucket].host_unreachable;
	        }

#ifdef DEBUG
	printf("Done determining max bucket values\n");
	printf("MAX_VALUE=%lu\n",max_value);
	printf("DRAWING_HEIGHT=%lu\n",DRAWING_HEIGHT);
#endif

	/* min number of values to graph */
	if(max_value<10)
		max_value=10;
#ifdef DEBUG
	printf("ADJUSTED MAX_VALUE=%lu\n",max_value);
#endif

	/* determine y scaling factor */
	/*y_scaling_factor=floor((double)DRAWING_HEIGHT/(double)max_value);*/
	y_scaling_factor=(double)((double)DRAWING_HEIGHT/(double)max_value);

	/* determine x scaling factor */
	x_scaling_factor=(double)((double)DRAWING_WIDTH/(double)total_buckets);

	/* determine y units resolution - we want a max of about 10 y grid lines */
	/*
	y_units=(double)((double)DRAWING_HEIGHT/19.0);
	y_units=ceil(y_units/y_scaling_factor)*y_scaling_factor;
	*/
	y_units=ceil(19.0/y_scaling_factor);

	/* determine x units resolution */
	if(breakdown_type==BREAKDOWN_HOURLY)
		x_units=(double)((double)DRAWING_WIDTH/(double)(total_buckets/4.0));
	else
		x_units=x_scaling_factor;

#ifdef DEBUG
	printf("DRAWING_WIDTH: %d\n",DRAWING_WIDTH);
	printf("DRAWING_HEIGHT: %d\n",DRAWING_HEIGHT);
	printf("max_value: %lu\n",max_value);
	printf("x_scaling_factor: %.3f\n",x_scaling_factor);
	printf("y_scaling_factor: %.3f\n",y_scaling_factor);
	printf("x_units: %.3f\n",x_units);
	printf("y_units: %.3f\n",y_units);
	printf("y units to draw: %.3f\n",((double)max_value/y_units));
#endif

	string_height=gdFontSmall->h;

#ifdef DEBUG
	printf("Starting to draw Y grid lines...\n");
#endif

	/* draw y grid lines */
	if(max_value>0){
		for(current_unit=1;(current_unit*y_units*y_scaling_factor)<=DRAWING_HEIGHT;current_unit++){
			draw_dashed_line(DRAWING_X_OFFSET,DRAWING_Y_OFFSET-(current_unit*y_units*y_scaling_factor),DRAWING_X_OFFSET+DRAWING_WIDTH,DRAWING_Y_OFFSET-(current_unit*y_units*y_scaling_factor),color_lightgray);
#ifdef DEBUG
			printf("  Drawing Y unit #%d @ %d\n",current_unit,(int)(current_unit*y_units*y_scaling_factor));
#endif
		        }
	        }

#ifdef DEBUG
	printf("Starting to draw X grid lines...\n");
#endif

	/* draw x grid lines */
	for(current_unit=1;(int)(current_unit*x_units)<=DRAWING_WIDTH;current_unit++)
		draw_dashed_line(DRAWING_X_OFFSET+(int)(current_unit*x_units),DRAWING_Y_OFFSET,DRAWING_X_OFFSET+(int)(current_unit*x_units),DRAWING_Y_OFFSET-DRAWING_HEIGHT,color_lightgray);

#ifdef DEBUG
	printf("Starting to draw grid units...\n");
#endif

	/* draw y units */
	if(max_value>0){
		for(current_unit=0;(current_unit*y_units*y_scaling_factor)<=DRAWING_HEIGHT;current_unit++){
			snprintf(temp_buffer,sizeof(temp_buffer)-1,"%d",(int)(current_unit*y_units));
			temp_buffer[sizeof(temp_buffer)-1]='\x0';
			string_width=gdFontSmall->w*strlen(temp_buffer);
			gdImageString(histogram_image,gdFontSmall,DRAWING_X_OFFSET-string_width-5,DRAWING_Y_OFFSET-(current_unit*y_units*y_scaling_factor)-(string_height/2),temp_buffer,color_black);
	                }
	        }

	/* draw x units */
	for(current_unit=0,actual_unit=0;(int)(current_unit*x_units)<=DRAWING_WIDTH;current_unit++,actual_unit++){

		if(actual_unit>=total_buckets)
			actual_unit=0;

		if(breakdown_type==BREAKDOWN_MONTHLY)
			snprintf(temp_buffer,sizeof(temp_buffer)-1,"%s",months[actual_unit]);
		else if(breakdown_type==BREAKDOWN_DAY_OF_MONTH)
			snprintf(temp_buffer,sizeof(temp_buffer)-1,"%d",actual_unit+1);
		else if(breakdown_type==BREAKDOWN_DAY_OF_WEEK)
			snprintf(temp_buffer,sizeof(temp_buffer)-1,"%s",days[actual_unit]);
		else
			snprintf(temp_buffer,sizeof(temp_buffer)-1,"%02d:00",(actual_unit==24)?0:actual_unit);

		temp_buffer[sizeof(temp_buffer)-1]='\x0';
		string_width=gdFontSmall->w*strlen(temp_buffer);

		gdImageStringUp(histogram_image,gdFontSmall,DRAWING_X_OFFSET+(current_unit*x_units)-(string_height/2),DRAWING_Y_OFFSET+5+string_width,temp_buffer,color_black);
	        }

	/* draw y unit measure */
	snprintf(temp_buffer,sizeof(temp_buffer)-1,"Number of Events");
	temp_buffer[sizeof(temp_buffer)-1]='\x0';
	string_width=gdFontSmall->w*strlen(temp_buffer);
	gdImageStringUp(histogram_image,gdFontSmall,0,DRAWING_Y_OFFSET-(DRAWING_HEIGHT/2)+(string_width/2),temp_buffer,color_black);

	/* draw x unit measure */
	if(breakdown_type==BREAKDOWN_MONTHLY)
		snprintf(temp_buffer,sizeof(temp_buffer)-1,"Month");
	else if(breakdown_type==BREAKDOWN_DAY_OF_MONTH)
		snprintf(temp_buffer,sizeof(temp_buffer)-1,"Day of the Month");
	else if(breakdown_type==BREAKDOWN_DAY_OF_WEEK)
		snprintf(temp_buffer,sizeof(temp_buffer)-1,"Day of the Week");
	else
		snprintf(temp_buffer,sizeof(temp_buffer)-1,"Hour of the Day (15 minute increments)");
	temp_buffer[sizeof(temp_buffer)-1]='\x0';
	string_width=gdFontSmall->w*strlen(temp_buffer);
	gdImageString(histogram_image,gdFontSmall,DRAWING_X_OFFSET+(DRAWING_WIDTH/2)-(string_width/2),DRAWING_Y_OFFSET+70,temp_buffer,color_black);

	/* draw title */
	snprintf(start_time,sizeof(start_time)-1,"%s",ctime(&t1));
	start_time[sizeof(start_time)-1]='\x0';
	start_time[strlen(start_time)-1]='\x0';
	snprintf(end_time,sizeof(end_time)-1,"%s",ctime(&t2));
	end_time[sizeof(end_time)-1]='\x0';
	end_time[strlen(end_time)-1]='\x0';

	if(display_type==DISPLAY_HOST_HISTOGRAM)
		snprintf(temp_buffer,sizeof(temp_buffer)-1,"Event History For Host '%s'",host_name);
	else
		snprintf(temp_buffer,sizeof(temp_buffer)-1,"Event History For Service '%s' On Host '%s'",svc_description,host_name);
	temp_buffer[sizeof(temp_buffer)-1]='\x0';
	string_width=gdFontSmall->w*strlen(temp_buffer);
	gdImageString(histogram_image,gdFontSmall,DRAWING_X_OFFSET+(DRAWING_WIDTH/2)-(string_width/2),0,(unsigned char *)temp_buffer,color_black);

	snprintf(temp_buffer,sizeof(temp_buffer)-1,"%s to %s",start_time,end_time);
	temp_buffer[sizeof(temp_buffer)-1]='\x0';
	string_width=gdFontSmall->w*strlen(temp_buffer);
	gdImageString(histogram_image,gdFontSmall,DRAWING_X_OFFSET+(DRAWING_WIDTH/2)-(string_width/2),string_height+5,(unsigned char *)temp_buffer,color_black);


#ifdef DEBUG
	printf("About to starting graphing (total_buckets=%d)...\n",total_buckets);
#endif
	

	/* graph service states */
	if(display_type==DISPLAY_HOST_HISTOGRAM){

		/* graph host recoveries */
		if(graph_events & GRAPH_HOST_UP){

			last_pixel_y=0;
			for(current_bucket=0,actual_bucket=0;current_bucket<=total_buckets;current_bucket++,actual_bucket++){

				if(actual_bucket>=total_buckets)
					actual_bucket=0;

				pixel_x=(int)(current_bucket*x_scaling_factor);
			
				pixel_y=(int)(tsdata[actual_bucket].host_up*y_scaling_factor);

				if(current_bucket>0 && !(last_pixel_y==0 && pixel_y==0))
					draw_line(DRAWING_X_OFFSET+pixel_x-(int)x_scaling_factor,DRAWING_Y_OFFSET-last_pixel_y,DRAWING_X_OFFSET+pixel_x,DRAWING_Y_OFFSET-pixel_y,color_green);

				last_pixel_y=pixel_y;

				if(current_bucket<total_buckets){
					if(have_state1_min==FALSE || tsdata[actual_bucket].host_up<state1_min){
						state1_min=tsdata[actual_bucket].host_up;
						have_state1_min=TRUE;
				                }
					if(state1_max==0 || tsdata[actual_bucket].host_up>state1_max)
						state1_max=tsdata[actual_bucket].host_up;
					state1_sum+=tsdata[actual_bucket].host_up;
				        }
			        }
	                }

#ifdef DEBUG
		printf("Done graphing HOST UP states...\n");
#endif

		/* graph host down states */
		if(graph_events & GRAPH_HOST_DOWN){

			last_pixel_y=0;
			for(current_bucket=0,actual_bucket=0;current_bucket<=total_buckets;current_bucket++,actual_bucket++){

				if(actual_bucket>=total_buckets)
					actual_bucket=0;

				pixel_x=(int)(current_bucket*x_scaling_factor);
			
				pixel_y=(int)(tsdata[actual_bucket].host_down*y_scaling_factor);

				if(current_bucket>0 && !(last_pixel_y==0 && pixel_y==0))
					draw_line(DRAWING_X_OFFSET+pixel_x-(int)x_scaling_factor,DRAWING_Y_OFFSET-last_pixel_y,DRAWING_X_OFFSET+pixel_x,DRAWING_Y_OFFSET-pixel_y,color_red);

				last_pixel_y=pixel_y;

				if(current_bucket<total_buckets){
					if(have_state2_min==FALSE || tsdata[actual_bucket].host_down<state2_min){
						state2_min=tsdata[actual_bucket].host_down;
						have_state2_min=TRUE;
				                }
					if(state2_max==0 || tsdata[actual_bucket].host_down>state2_max)
						state2_max=tsdata[actual_bucket].host_down;
					state2_sum+=tsdata[actual_bucket].host_down;
				        }
			        }
	                }

#ifdef DEBUG
		printf("Done graphing HOST DOWN states...\n");
#endif

		/* graph host unreachable states */
		if(graph_events & GRAPH_HOST_UNREACHABLE){

			last_pixel_y=0;
			for(current_bucket=0,actual_bucket=0;current_bucket<=total_buckets;current_bucket++,actual_bucket++){

				if(actual_bucket>=total_buckets)
					actual_bucket=0;

				pixel_x=(int)(current_bucket*x_scaling_factor);
			
				pixel_y=(int)(tsdata[actual_bucket].host_unreachable*y_scaling_factor);

				if(current_bucket>0 && !(last_pixel_y==0 && pixel_y==0))
					draw_line(DRAWING_X_OFFSET+pixel_x-(int)x_scaling_factor,DRAWING_Y_OFFSET-last_pixel_y,DRAWING_X_OFFSET+pixel_x,DRAWING_Y_OFFSET-pixel_y,color_darkred);

				last_pixel_y=pixel_y;

				if(current_bucket<total_buckets){
					if(have_state3_min==FALSE || tsdata[actual_bucket].host_unreachable<state3_min){
						state3_min=tsdata[actual_bucket].host_unreachable;
						have_state3_min=TRUE;
				                }
					if(state3_max==0 || tsdata[actual_bucket].host_unreachable>state3_max)
						state3_max=tsdata[actual_bucket].host_unreachable;
					state3_sum+=tsdata[actual_bucket].host_unreachable;
				        }
			        }
	                }

#ifdef DEBUG
		printf("Done graphing HOST UNREACHABLE states...\n");
#endif

	        }

	/* graph service states */
	else{

		/* graph service recoveries */
		if(graph_events & GRAPH_SERVICE_OK){

			last_pixel_y=0;
			for(current_bucket=0,actual_bucket=0;current_bucket<=total_buckets;current_bucket++,actual_bucket++){

				if(actual_bucket>=total_buckets)
					actual_bucket=0;

				pixel_x=(int)(current_bucket*x_scaling_factor);
			
				pixel_y=(int)(tsdata[actual_bucket].service_ok*y_scaling_factor);

				if(current_bucket>0 && !(last_pixel_y==0 && pixel_y==0))
					draw_line(DRAWING_X_OFFSET+pixel_x-(int)x_scaling_factor,DRAWING_Y_OFFSET-last_pixel_y,DRAWING_X_OFFSET+pixel_x,DRAWING_Y_OFFSET-pixel_y,color_green);

				last_pixel_y=pixel_y;

				if(current_bucket<total_buckets){
					if(have_state1_min==FALSE || tsdata[actual_bucket].service_ok<state1_min){
						state1_min=tsdata[actual_bucket].service_ok;
						have_state1_min=TRUE;
				                }
					if(state1_max==0 || tsdata[actual_bucket].service_ok>state1_max)
						state1_max=tsdata[actual_bucket].service_ok;
					state1_sum+=tsdata[actual_bucket].service_ok;
				        }
			        }
	                }

		/* graph service warning states */
		if(graph_events & GRAPH_SERVICE_WARNING){

			last_pixel_y=0;
			for(current_bucket=0,actual_bucket=0;current_bucket<=total_buckets;current_bucket++,actual_bucket++){

				if(actual_bucket>=total_buckets)
					actual_bucket=0;

				pixel_x=(int)(current_bucket*x_scaling_factor);
				
				pixel_y=(int)(tsdata[actual_bucket].service_warning*y_scaling_factor);

				if(current_bucket>0 && !(last_pixel_y==0 && pixel_y==0))
					draw_line(DRAWING_X_OFFSET+pixel_x-(int)x_scaling_factor,DRAWING_Y_OFFSET-last_pixel_y,DRAWING_X_OFFSET+pixel_x,DRAWING_Y_OFFSET-pixel_y,color_yellow);

				last_pixel_y=pixel_y;

				if(current_bucket<total_buckets){
					if(have_state2_min==FALSE || tsdata[actual_bucket].service_warning<state2_min){
						state2_min=tsdata[actual_bucket].service_warning;
						have_state2_min=TRUE;
				                }
					if(state2_max==0 || tsdata[actual_bucket].service_warning>state2_max)
						state2_max=tsdata[actual_bucket].service_warning;
					state2_sum+=tsdata[actual_bucket].service_warning;
				        }
			        }
	                }

		/* graph service unknown states */
		if(graph_events & GRAPH_SERVICE_UNKNOWN){

			last_pixel_y=0;
			for(current_bucket=0,actual_bucket=0;current_bucket<=total_buckets;current_bucket++,actual_bucket++){
				
				if(actual_bucket>=total_buckets)
					actual_bucket=0;

				pixel_x=(int)(current_bucket*x_scaling_factor);
			
				pixel_y=(int)(tsdata[actual_bucket].service_unknown*y_scaling_factor);

				if(current_bucket>0 && !(last_pixel_y==0 && pixel_y==0))
					draw_line(DRAWING_X_OFFSET+pixel_x-(int)x_scaling_factor,DRAWING_Y_OFFSET-last_pixel_y,DRAWING_X_OFFSET+pixel_x,DRAWING_Y_OFFSET-pixel_y,color_orange);

				last_pixel_y=pixel_y;

				if(current_bucket<total_buckets){
					if(have_state3_min==FALSE || tsdata[actual_bucket].service_unknown<state3_min){
						state3_min=tsdata[actual_bucket].service_unknown;
						have_state3_min=TRUE;
				                }
					if(state3_max==0 || tsdata[actual_bucket].service_unknown>state3_max)
						state3_max=tsdata[actual_bucket].service_unknown;
					state3_sum+=tsdata[actual_bucket].service_unknown;
				        }
			        }
	                }

		/* graph service critical states */
		if(graph_events & GRAPH_SERVICE_CRITICAL){

			last_pixel_y=0;
			for(current_bucket=0,actual_bucket=0;current_bucket<=total_buckets;current_bucket++,actual_bucket++){

				if(actual_bucket>=total_buckets)
					actual_bucket=0;

				pixel_x=(int)(current_bucket*x_scaling_factor);
			
				pixel_y=(int)(tsdata[actual_bucket].service_critical*y_scaling_factor);

				if(current_bucket>0 && !(last_pixel_y==0 && pixel_y==0))
					draw_line(DRAWING_X_OFFSET+pixel_x-(int)x_scaling_factor,DRAWING_Y_OFFSET-last_pixel_y,DRAWING_X_OFFSET+pixel_x,DRAWING_Y_OFFSET-pixel_y,color_red);

				last_pixel_y=pixel_y;

				if(current_bucket<total_buckets){
					if(have_state4_min==FALSE || tsdata[actual_bucket].service_critical<state4_min){
						state4_min=tsdata[actual_bucket].service_critical;
						have_state4_min=TRUE;
				                }
					if(state4_max==0 || tsdata[actual_bucket].service_critical>state4_max)
						state4_max=tsdata[actual_bucket].service_critical;
					state4_sum+=tsdata[actual_bucket].service_critical;
				        }
			        }
	                }
	        }

#ifdef DEBUG
	printf("Done graphing states...\n");
#endif

	/* draw graph boundaries */
	draw_line(DRAWING_X_OFFSET,DRAWING_Y_OFFSET,DRAWING_X_OFFSET,DRAWING_Y_OFFSET-DRAWING_HEIGHT,color_black);
	draw_line(DRAWING_X_OFFSET+DRAWING_WIDTH,DRAWING_Y_OFFSET,DRAWING_X_OFFSET+DRAWING_WIDTH,DRAWING_Y_OFFSET-DRAWING_HEIGHT,color_black);
	draw_line(DRAWING_X_OFFSET,DRAWING_Y_OFFSET,DRAWING_X_OFFSET+DRAWING_WIDTH,DRAWING_Y_OFFSET,color_black);


	/* graph stats */
	snprintf(temp_buffer,sizeof(temp_buffer)-1,"EVENT TYPE");
	temp_buffer[sizeof(temp_buffer)-1]='\x0';
	string_width=gdFontSmall->w*strlen(temp_buffer);
	gdImageString(histogram_image,gdFontSmall,DRAWING_X_OFFSET+DRAWING_WIDTH+15,DRAWING_Y_OFFSET-DRAWING_HEIGHT,temp_buffer,color_black);

	snprintf(temp_buffer,sizeof(temp_buffer)-1,"  MIN   MAX   SUM   AVG");
	temp_buffer[sizeof(temp_buffer)-1]='\x0';
	string_width=gdFontSmall->w*strlen(temp_buffer);
	gdImageString(histogram_image,gdFontSmall,DRAWING_X_OFFSET+DRAWING_WIDTH+115,DRAWING_Y_OFFSET-DRAWING_HEIGHT,temp_buffer,color_black);

	draw_line(DRAWING_X_OFFSET+DRAWING_WIDTH+15,DRAWING_Y_OFFSET-DRAWING_HEIGHT+string_height+2,DRAWING_X_OFFSET+DRAWING_WIDTH+275,DRAWING_Y_OFFSET-DRAWING_HEIGHT+string_height+2,color_black);

	snprintf(temp_buffer,sizeof(temp_buffer)-1,"Recovery (%s):",(display_type==DISPLAY_SERVICE_HISTOGRAM)?"Ok":"Up");
	temp_buffer[sizeof(temp_buffer)-1]='\x0';
	string_width=gdFontSmall->w*strlen(temp_buffer);
	gdImageString(histogram_image,gdFontSmall,DRAWING_X_OFFSET+DRAWING_WIDTH+15,DRAWING_Y_OFFSET-DRAWING_HEIGHT+((string_height+5)*1),temp_buffer,color_green);

	state1_avg=(double)((double)state1_sum/(double)total_buckets);
	snprintf(temp_buffer,sizeof(temp_buffer)-1,"%5lu %5lu %5lu   %.2f",state1_min,state1_max,state1_sum,state1_avg);
	temp_buffer[sizeof(temp_buffer)-1]='\x0';
	string_width=gdFontSmall->w*strlen(temp_buffer);
	gdImageString(histogram_image,gdFontSmall,DRAWING_X_OFFSET+DRAWING_WIDTH+115,DRAWING_Y_OFFSET-DRAWING_HEIGHT+((string_height+5)*1),temp_buffer,color_black);

	snprintf(temp_buffer,sizeof(temp_buffer)-1,"%s:",(display_type==DISPLAY_SERVICE_HISTOGRAM)?"Warning":"Down");
	temp_buffer[sizeof(temp_buffer)-1]='\x0';
	string_width=gdFontSmall->w*strlen(temp_buffer);
	gdImageString(histogram_image,gdFontSmall,DRAWING_X_OFFSET+DRAWING_WIDTH+15,DRAWING_Y_OFFSET-DRAWING_HEIGHT+((string_height+5)*2),temp_buffer,(display_type==DISPLAY_SERVICE_HISTOGRAM)?color_yellow:color_red);

	state2_avg=(double)((double)state2_sum/(double)total_buckets);
	snprintf(temp_buffer,sizeof(temp_buffer)-1,"%5lu %5lu %5lu   %.2f",state2_min,state2_max,state2_sum,state2_avg);
	temp_buffer[sizeof(temp_buffer)-1]='\x0';
	string_width=gdFontSmall->w*strlen(temp_buffer);
	gdImageString(histogram_image,gdFontSmall,DRAWING_X_OFFSET+DRAWING_WIDTH+115,DRAWING_Y_OFFSET-DRAWING_HEIGHT+((string_height+5)*2),temp_buffer,color_black);

	snprintf(temp_buffer,sizeof(temp_buffer)-1,"%s:",(display_type==DISPLAY_SERVICE_HISTOGRAM)?"Unknown":"Unreachable");
	temp_buffer[sizeof(temp_buffer)-1]='\x0';
	string_width=gdFontSmall->w*strlen(temp_buffer);
	gdImageString(histogram_image,gdFontSmall,DRAWING_X_OFFSET+DRAWING_WIDTH+15,DRAWING_Y_OFFSET-DRAWING_HEIGHT+((string_height+5)*3),temp_buffer,(display_type==DISPLAY_SERVICE_HISTOGRAM)?color_orange:color_darkred);

	state3_avg=(double)((double)state3_sum/(double)total_buckets);
	snprintf(temp_buffer,sizeof(temp_buffer)-1,"%5lu %5lu %5lu   %.2f",state3_min,state3_max,state3_sum,state3_avg);
	temp_buffer[sizeof(temp_buffer)-1]='\x0';
	string_width=gdFontSmall->w*strlen(temp_buffer);
	gdImageString(histogram_image,gdFontSmall,DRAWING_X_OFFSET+DRAWING_WIDTH+115,DRAWING_Y_OFFSET-DRAWING_HEIGHT+((string_height+5)*3),temp_buffer,color_black);

	if(display_type==DISPLAY_SERVICE_HISTOGRAM){

		snprintf(temp_buffer,sizeof(temp_buffer)-1,"Critical:");
		temp_buffer[sizeof(temp_buffer)-1]='\x0';
		string_width=gdFontSmall->w*strlen(temp_buffer);
		gdImageString(histogram_image,gdFontSmall,DRAWING_X_OFFSET+DRAWING_WIDTH+15,DRAWING_Y_OFFSET-DRAWING_HEIGHT+((string_height+5)*4),temp_buffer,color_red);

		state4_avg=(double)((double)state4_sum/(double)total_buckets);
		snprintf(temp_buffer,sizeof(temp_buffer)-1,"%5lu %5lu %5lu   %.2f",state4_min,state4_max,state4_sum,state4_avg);
		temp_buffer[sizeof(temp_buffer)-1]='\x0';
		string_width=gdFontSmall->w*strlen(temp_buffer);
		gdImageString(histogram_image,gdFontSmall,DRAWING_X_OFFSET+DRAWING_WIDTH+115,DRAWING_Y_OFFSET-DRAWING_HEIGHT+((string_height+5)*4),temp_buffer,color_black);
	        }

	return;
        }


/* adds an archived state entry */
void add_archived_state(int state_type, time_t time_stamp){
	struct tm *our_time;
	int bucket;
	int skip_state=FALSE;

#ifdef DEBUG2
	printf("NEW ENTRY: last=%d this=%d\n",last_state,state_type);
#endif

	/* don't record program starts/stops, just make a note that one occurred */
	if(state_type==AS_PROGRAM_START || state_type==AS_PROGRAM_END){
#ifdef DEBUG2
		printf("Recording a program start: %d\n",state_type);
#endif
		program_restart_has_occurred=TRUE;
		return;
	        }

	/* see if we should even take into account this event */
	if(program_restart_has_occurred==TRUE){

#ifdef DEBUG2
		printf("program_restart_has_occurred: last=%d this=%d\n",last_state,state_type);
#endif
		
		if(initial_states_logged==TRUE){
			if(state_type==AS_SVC_OK && last_state==AS_SVC_OK)
				skip_state=TRUE;
			if(state_type==AS_HOST_UP && last_state==AS_HOST_UP)
				skip_state=TRUE;
		        }
			
		if(assume_state_retention==TRUE && initial_states_logged==TRUE){
			if(state_type==AS_SVC_WARNING && last_state==AS_SVC_WARNING)
				skip_state=TRUE;
			if(state_type==AS_SVC_UNKNOWN && last_state==AS_SVC_UNKNOWN)
				skip_state=TRUE;
			if(state_type==AS_SVC_CRITICAL && last_state==AS_SVC_CRITICAL)
				skip_state=TRUE;
			if(state_type==AS_HOST_DOWN && last_state==AS_HOST_DOWN)
				skip_state=TRUE;
			if(state_type==AS_HOST_UNREACHABLE && last_state==AS_HOST_UNREACHABLE)
				skip_state=TRUE;
		        }

		if(skip_state==TRUE){
			program_restart_has_occurred=FALSE;
#ifdef DEBUG2
			printf("Skipping state...\n");
#endif
			return;
		        }
	        }

	/* reset program restart variable */
	program_restart_has_occurred=FALSE;

	/* are we only processing new states */
	if(new_states_only==TRUE && state_type==last_state){
#ifdef DEBUG2
		printf("Skipping state (not a new state)...\n");
#endif
		return;
	        }

#ifdef DEBUG2
	printf("GOODSTATE: %d @ %lu\n",state_type,(unsigned long)time_stamp);
#endif
		


	our_time=localtime(&time_stamp);

	/* calculate the correct bucket to dump the data into */
	if(breakdown_type==BREAKDOWN_MONTHLY)
		bucket=our_time->tm_mon;

	else if(breakdown_type==BREAKDOWN_DAY_OF_MONTH)
		bucket=our_time->tm_mday-1;

	else if(breakdown_type==BREAKDOWN_DAY_OF_WEEK)
		bucket=our_time->tm_wday;

	else
		bucket=(our_time->tm_hour*4)+(our_time->tm_min/15);

#ifdef DEBUG2
	printf("\tBucket=%d\n",bucket);
#endif	

	/* save the data in the correct bucket */
	if(state_type==AS_SVC_OK)
		tsdata[bucket].service_ok++;
	else if(state_type==AS_SVC_UNKNOWN)
		tsdata[bucket].service_unknown++;
	else if(state_type==AS_SVC_WARNING)
		tsdata[bucket].service_warning++;
	else if(state_type==AS_SVC_CRITICAL)
		tsdata[bucket].service_critical++;
	else if(state_type==AS_HOST_UP)
		tsdata[bucket].host_up++;
	else if(state_type==AS_HOST_DOWN)
		tsdata[bucket].host_down++;
	else if(state_type==AS_HOST_UNREACHABLE)
		tsdata[bucket].host_unreachable++;

	/* record last state type */
	last_state=state_type;

	return;
        }



/* reads log files for archived state data */
void read_archived_state_data(void){
	char filename[MAX_FILENAME_LENGTH];
	int newest_archive=0;
	int oldest_archive=0;
	int current_archive;

#ifdef DEBUG2
	printf("Determining archives to use...\n");
#endif

	/* determine earliest archive to use */
	oldest_archive=determine_archive_to_use_from_time(t1);
	if(log_rotation_method!=LOG_ROTATION_NONE)
		oldest_archive+=backtrack_archives;

	/* determine most recent archive to use */
	newest_archive=determine_archive_to_use_from_time(t2);

	if(oldest_archive<newest_archive)
		oldest_archive=newest_archive;

#ifdef DEBUG2
	printf("Oldest archive: %d\n",oldest_archive);
	printf("Newest archive: %d\n",newest_archive);
#endif

	/* read in all the necessary archived logs */
	for(current_archive=newest_archive;current_archive<=oldest_archive;current_archive++){

		/* get the name of the log file that contains this archive */
		get_log_archive_to_use(current_archive,filename,sizeof(filename)-1);

#ifdef DEBUG2
		printf("\tCurrent archive: %d (%s)\n",current_archive,filename);
#endif

		/* scan the log file for archived state data */
		scan_log_file_for_archived_state_data(filename);
	        }

	return;
        }



/* grabs archives state data from a log file */
void scan_log_file_for_archived_state_data(char *filename){
	char input_buffer[MAX_INPUT_BUFFER];
	char input_buffer2[MAX_INPUT_BUFFER];
	char entry_host_name[MAX_INPUT_BUFFER];
	char entry_svc_description[MAX_INPUT_BUFFER];
	char *temp_buffer;
	time_t time_stamp;
	FILE *fp;

	/* print something so browser doesn't time out */
	if(mode==CREATE_HTML){
		printf(" ");
		fflush(NULL);
	        }

	fp=fopen(filename,"r");
	if(fp==NULL){
#ifdef DEBUG2
		printf("Could not open file '%s' for reading.\n",filename);
#endif
		return;
	        }

#ifdef DEBUG2
	printf("Scanning log file '%s' for archived state data...\n",filename);
#endif

	while(read_line(input_buffer,MAX_INPUT_BUFFER,fp)){

	        if(feof(fp))
		        break;

		if(input_buffer==NULL)
		        continue;

		strcpy(input_buffer2,input_buffer);
		temp_buffer=strtok(input_buffer2,"]");
		time_stamp=(temp_buffer==NULL)?(time_t)0:(time_t)strtoul(temp_buffer+1,NULL,10);

		/* program starts/restarts */
		if(strstr(input_buffer," starting..."))
			add_archived_state(AS_PROGRAM_START,time_stamp);
		if(strstr(input_buffer," restarting..."))
			add_archived_state(AS_PROGRAM_START,time_stamp);

		/* program stops */
		if(strstr(input_buffer," shutting down..."))
			add_archived_state(AS_PROGRAM_END,time_stamp);
		if(strstr(input_buffer,"Bailing out"))
			add_archived_state(AS_PROGRAM_END,time_stamp);

		if(display_type==DISPLAY_HOST_HISTOGRAM){
			if(strstr(input_buffer,"HOST ALERT:")){

				strcpy(input_buffer2,input_buffer);

				/* get host name */
				temp_buffer=my_strtok(input_buffer2,"]");
				temp_buffer=my_strtok(NULL,":");
				temp_buffer=my_strtok(NULL,";");
				strncpy(entry_host_name,(temp_buffer==NULL)?"":temp_buffer+1,sizeof(entry_host_name));
				entry_host_name[sizeof(entry_host_name)-1]='\x0';

				if(strcmp(host_name,entry_host_name))
					continue;

				/* skip soft states if necessary */
				if(!(graph_statetypes & GRAPH_SOFT_STATETYPES) && strstr(input_buffer,";SOFT;"))
					continue;

				/* skip hard states if necessary */
				if(!(graph_statetypes & GRAPH_HARD_STATETYPES) && strstr(input_buffer,";HARD;"))
					continue;

				if(strstr(input_buffer,";DOWN;"))
					add_archived_state(AS_HOST_DOWN,time_stamp);
				else if(strstr(input_buffer,";UNREACHABLE;"))
					add_archived_state(AS_HOST_UNREACHABLE,time_stamp);
				else if(strstr(input_buffer,";RECOVERY") || strstr(input_buffer,";UP;"))
					add_archived_state(AS_HOST_UP,time_stamp);
			        }
		        }
		if(display_type==DISPLAY_SERVICE_HISTOGRAM){
			if(strstr(input_buffer,"SERVICE ALERT:")){

				strcpy(input_buffer2,input_buffer);

				/* get host name */
				temp_buffer=my_strtok(input_buffer2,"]");
				temp_buffer=my_strtok(NULL,":");
				temp_buffer=my_strtok(NULL,";");
				strncpy(entry_host_name,(temp_buffer==NULL)?"":temp_buffer+1,sizeof(entry_host_name));
				entry_host_name[sizeof(entry_host_name)-1]='\x0';

				if(strcmp(host_name,entry_host_name))
					continue;
				
				/* get service description */
				temp_buffer=my_strtok(NULL,";");
				strncpy(entry_svc_description,(temp_buffer==NULL)?"":temp_buffer,sizeof(entry_svc_description));
				entry_svc_description[sizeof(entry_svc_description)-1]='\x0';

				if(strcmp(svc_description,entry_svc_description))
					continue;

				/* skip soft states if necessary */
				if(!(graph_statetypes & GRAPH_SOFT_STATETYPES) && strstr(input_buffer,";SOFT;"))
					continue;

				/* skip hard states if necessary */
				if(!(graph_statetypes & GRAPH_HARD_STATETYPES) && strstr(input_buffer,";HARD;"))
					continue;

				if(strstr(input_buffer,";CRITICAL;"))
					add_archived_state(AS_SVC_CRITICAL,time_stamp);
				else if(strstr(input_buffer,";WARNING;"))
					add_archived_state(AS_SVC_WARNING,time_stamp);
				else if(strstr(input_buffer,";UNKNOWN;"))
					add_archived_state(AS_SVC_UNKNOWN,time_stamp);
				else if(strstr(input_buffer,";RECOVERY;") || strstr(input_buffer,";OK;"))
					add_archived_state(AS_SVC_OK,time_stamp);
			        }
		        }
		
	        }

	fclose(fp);
	
	return;
        }
	



void convert_timeperiod_to_times(int type){
	time_t current_time;
	struct tm *t;

	/* get the current time */
	time(&current_time);

	t=localtime(&current_time);

	t->tm_sec=0;
	t->tm_min=0;
	t->tm_hour=0;

	switch(type){
	case TIMEPERIOD_LAST24HOURS:
		t1=current_time-(60*60*24);
		t2=current_time;
		break;
	case TIMEPERIOD_TODAY:
		t1=mktime(t);
		t2=current_time;
		break;
	case TIMEPERIOD_YESTERDAY:
		t1=(time_t)(mktime(t)-(60*60*24));
		t2=(time_t)mktime(t);
		break;
	case TIMEPERIOD_THISWEEK:
		t1=(time_t)(mktime(t)-(60*60*24*t->tm_wday));
		t2=current_time;
		break;
	case TIMEPERIOD_LASTWEEK:
		t1=(time_t)(mktime(t)-(60*60*24*t->tm_wday)-(60*60*24*7));
		t2=(time_t)(mktime(t)-(60*60*24*t->tm_wday));
		break;
	case TIMEPERIOD_THISMONTH:
		t->tm_mday=1;
		t1=mktime(t);
		t2=current_time;
		break;
	case TIMEPERIOD_LASTMONTH:
		t->tm_mday=1;
		t2=mktime(t);
		if(t->tm_mon==0){
			t->tm_mon=11;
			t->tm_year--;
		        }
		else
			t->tm_mon--;
		t1=mktime(t);
		break;
	case TIMEPERIOD_THISQUARTER:
		break;
	case TIMEPERIOD_LASTQUARTER:
		break;
	case TIMEPERIOD_THISYEAR:
		t->tm_mon=0;
		t->tm_mday=1;
		t1=mktime(t);
		t2=current_time;
		break;
	case TIMEPERIOD_LASTYEAR:
		t->tm_mon=0;
		t->tm_mday=1;
		t2=mktime(t);
		t->tm_year--;
		t1=mktime(t);
		break;
	case TIMEPERIOD_LAST7DAYS:
		t2=current_time;
		t1=current_time-(7*24*60*60);
		break;
	default:
		break;
	        }

	return;
        }



void compute_report_times(void){
	time_t current_time;
	struct tm *st;
	struct tm *et;

	/* get the current time */
	time(&current_time);

	st=localtime(&current_time);

	st->tm_sec=start_second;
	st->tm_min=start_minute;
	st->tm_hour=start_hour;
	st->tm_mday=start_day;
	st->tm_mon=start_month-1;
	st->tm_year=start_year-1900;

	t1=mktime(st);

	et=localtime(&current_time);

	et->tm_sec=end_second;
	et->tm_min=end_minute;
	et->tm_hour=end_hour;
	et->tm_mday=end_day;
	et->tm_mon=end_month-1;
	et->tm_year=end_year-1900;

	t2=mktime(et);
        }



/* draws a solid line */
void draw_line(int x1,int y1,int x2,int y2,int color){
	int styleSolid[1];

	styleSolid[0]=color;

	/* sets current style to a solid line */
	gdImageSetStyle(histogram_image,styleSolid,1);

	/* draws a line (dashed) */
	gdImageLine(histogram_image,x1,y1,x2,y2,gdStyled);

	return;
	}


/* draws a dashed line */
void draw_dashed_line(int x1,int y1,int x2,int y2,int color){
	int styleDashed[6];

	styleDashed[0]=color;
	styleDashed[1]=color;
	styleDashed[2]=gdTransparent;
	styleDashed[3]=gdTransparent;
	styleDashed[4]=gdTransparent;
	styleDashed[5]=gdTransparent;

	/* sets current style to a solid line */
	gdImageSetStyle(histogram_image,styleDashed,6);

	/* draws a line (dashed) */
	gdImageLine(histogram_image,x1,y1,x2,y2,gdStyled);

	return;
	}

