/*******************************************************************
 *
 * TITLE:
 *      chart.c
 *
 * AUTHOR:
 *      Cassie Mulnix
 *
 * DESCRIPTION:
 *      This module is part of the OPPS editor: xopps.  It contains
 *      routines to draw chart onto background.
 *
 *                              CHANGE HISTORY
 *
 * $Log: chart.c,v $
 * Revision 1.74  1995/02/02  00:29:39  kevin
 * fixed memory bug
 *
 * Revision 1.73  1994/08/10  22:02:18  cassie
 * fixed DialogFlagSet calls
 *
 * Revision 1.72  1994/07/20  19:06:35  clm
 * updated TRUE, ERROR etc in cancel & ok_button functions
 * to DIALOG_ constants
 *
 * Revision 1.71  1994/06/16  21:55:48  clm
 * updated to new dialog routines - extra parameter to DialogTextCreate
 *
 * Revision 1.70  1994/06/16  16:56:35  clm
 * updated to new gr_ routines using GR_ for font names
 *
 * Revision 1.69  1994/06/08  18:47:59  clm
 * removed Xm library includes since they are in dialog
 *
 * Revision 1.68  1994/06/07  00:52:11  clm
 * fixed ok_button date values
 *
 * Revision 1.67  1994/06/02  19:43:27  clm
 * changed Event Symbols label
 *
 * Revision 1.66  1994/06/01  22:27:07  clm
 * rewrote init functions to use dialog oellib functions
 * also don't initialize popups until object called
 *
 * Revision 1.65  1994/05/20  23:31:43  clm
 * updated with HP, SGI changes
 *
 * Revision 1.64  1994/05/04  23:34:36  clm
 * ported to ANSI C
 *
 * Revision 1.63  1994/02/09  16:24:09  clm
 * added week_monday as resource to display weeks by Mondays
 *
 * Revision 1.62  1993/11/23  18:39:30  clm
 * changed displayfy so fy is displayed on top line if Y_CY set
 *
 * Revision 1.61  1993/11/22  17:36:39  clm
 * make FY always on top line
 *
 * Revision 1.60  1993/05/19  19:53:11  clm
 * add_status call incorrect parameters
 *
 * Revision 1.59  1993/05/18  22:39:41  clm
 * added meaningful error messages for check_num and check_day
 *
 * Revision 1.58  1993/05/18  20:58:30  clm
 * added new message.c function
 *
 * Revision 1.57  1993/04/13  22:23:51  clm
 * if FY flag then display Year on top line, else display Year in middle
 *
 * Revision 1.56  1993/03/29  15:58:08  clm
 * set snap_evt default to ON
 *
 * Revision 1.55  1993/03/25  18:34:06  clm
 * ok_button uses existing status date characteristics if the object
 * already exists
 *
 * Revision 1.54  1993/03/09  16:48:38  clm
 * error checking in xval if xs == xe
 *
 * Revision 1.53  1993/03/04  17:48:04  clm
 * added init_chart to load_chart if error in chart object line
 *
 * Revision 1.52  1993/02/08  15:53:39  clm
 * changed y_notes_top to y_lines_end
 *
 * Revision 1.51  1992/12/18  16:08:24  clm
 * fixed y for gr_text so text is always centered
 *
 * Revision 1.50  1992/12/15  16:38:24  clm
 * filled in rem_chart so memory is freed when new chart created
 * l.
 *
 * Revision 1.49  1992/12/11  21:26:51  clm
 * fixed init_chart so RSRC_FONT and RSRC_POINT are global resources
 *
 * Revision 1.48  1992/12/10  22:46:22  clm
 * added font and point as resources
 * set dates according to current computer date
 * guaranteed chart is always object 0
 * fixes as per code review
 * ;.
 *
 * Revision 1.47  1992/11/09  16:27:11  clm
 * added dsp_pline to dsp_chart
 *
 * Revision 1.46  1992/10/13  00:17:10  clm
 * fixed display month buffer size for dow display
 *
 * Revision 1.45  1992/10/02  19:48:49  clm
 * housekeeping
 *
 * Revision 1.44  1992/09/25  21:43:56  clm
 * fixed display of doy to fit in chart
 *
 * Revision 1.43  1992/09/25  21:11:28  clm
 * added vgrid to be saved
 *
 * Revision 1.42  1992/09/25  20:18:18  clm
 * fixed display of month for greater width
 *
 * Revision 1.41  1992/09/24  15:43:20  clm
 * added save of utc_bar to chart
 *
 * Revision 1.40  1992/09/22  22:36:20  clm
 * moved initialization of utc_bar toggle to init_char
 * to incorporate change of utc_bar addition to internals.c
 *
 * Revision 1.39  1992/09/16  14:54:39  clm
 * fixed load function so doesn't add object if error in load
 *
 * Revision 1.38  1992/09/16  14:06:15  clm
 * moved initialization of issue_disp to init_chart
 *
 * Revision 1.37  1992/09/14  19:19:54  clm
 * fixed flags to be chtptr->flags
 *
 * Revision 1.36  1992/09/11  22:59:11  clm
 * fixed add_status call for new drawing area size
 *
 * Revision 1.35  1992/09/10  17:11:30  clm
 * added pg_lines, num_pages and snap toggles default values
 * removing xopps_init
 *
 * Revision 1.34  1992/09/01  20:19:30  clm
 * fixed dsp_utc
 *
 * Revision 1.33  1992/08/31  17:01:19  clm
 * added OEL XOPPS Editor text along bottom of chart
 * changed default chart dates
 *
 * Revision 1.32  1992/08/27  16:22:43  clm
 * made all year division lines thick
 *
 * Revision 1.31  1992/08/27  16:13:33  clm
 * added vgrid option
 *
 * Revision 1.30  1992/08/26  17:55:35  clm
 * fixed the display of fy
 *
 * Revision 1.28  1992/08/26  15:03:46  clm
 * moved num_pages and pg_lines initial value to init file
 *
 * Revision 1.27  1992/08/25  15:33:19  clm
 * added xlnary and ylnary
 * changed dsp_chart to incorporate new arrays
 *
 * Revision 1.26  1992/08/20  18:05:39  clm
 * fixed load error checking for status date
 *
 * Revision 1.25  1992/08/13  18:07:47  clm
 * added error checking to load_chart
 *
 * Revision 1.23  1992/08/04  17:01:10  clm
 * changed malloc and free to XtMalloc and XtFree
 *
 * Revision 1.22  1992/08/03  21:29:07  clm
 * added flags for calendar year and fiscal year
 * added display toggles and auto_reset toggles
 * added display utc_bar
 *
 * Revision 1.21  1992/07/16  15:32:17  clm
 * better format to output
 *
 * Revision 1.19  1992/07/13  20:53:03  clm
 * added load_chart routine
 *
 * Revision 1.18  1992/07/08  19:38:56  clm
 * added color value to chtptr
 * fixed comment format
 *
 * Revision 1.17  1992/06/24  17:11:06  clm
 * added display week and dow routines
 *
 * Revision 1.15  1992/06/12  18:13:13  clm
 * formatted text output
 *
 * Revision 1.14  1992/06/12  17:54:54  clm
 * filled in displayweek routine
 *
 * Revision 1.13  1992/06/10  15:01:13  clm
 * combined chart.c and dates.c
 * filled in missing loc, lim ,edt, add routines
 *
 * Revision 1.9  1992/05/11  22:38:16  kevin
 * renamed project include file to xopps.h
 *
 ***********************************************************************
 *
 * WARNINGS:
 *
 * EXTERNAL CALLABLE COMPONENTS (PUBLIC):
 *
 * GLOBALS:
 *
 * WAIVERS:
 *
 * NOTES:
 *
 * MANPAGE:
 *
 ***********************************************************************/

#ifndef lint
static char rcsid[] =
   "$Id: chart.c,v 1.74 1995/02/02 00:29:39 kevin OEL $";
#endif

#include <sys/types.h>
#include <sys/time.h>
#include "xopps.h"

#include <unistd.h>

#define TEXT_FONT 20
#define TEXT_SIZE 12

static int font_values[] = {
    GR_COURIER, GR_COURIER_BOLD, GR_HELVETICA, GR_HELVETICA_BOLD, GR_TIMES, 
    GR_TIMES_BOLD
};

static int font_sizes[] = {
    8, 10, 12, 14, 18, 24
};

typedef enum flag {
    Y_NONE, Y_CY, Y_FY
} flag_vals;

static void create_dialog(void);
static void chart_ok_button(void);		/* Callback for ok button */
static void cancel_button(void); 		/* Callback for cancel button */
static void change_font(Widget, XtPointer, XtPointer);
static void change_point(Widget, XtPointer, XtPointer);
static void change_color(Widget, XtPointer, XtPointer);
static void change_resol(Widget, XtPointer, XtPointer);
static void change_date(Widget, XtPointer, XtPointer);
static void change_disp(Widget, XtPointer, XtPointer);
static void change_event(Widget, XtPointer, XtPointer);
static void change_flag(Widget, XtPointer, XtPointer);
static void edt_chart(int, int);		/* Edit module */
static void rem_chart(int, int);		/* Remove module */
static void lim_chart(int, int *, int *, int *, int *, int); /* Limit motion */
static void loc_chart(int, int);		/* Locates object */
static void mov_chart(int, int, int, int);	/* Moves object */
static void cpy_chart(struct obj *, struct obj *);	/* Copies object */
static void msg_chart(int, int);		/* Outputs object messages */
static void sav_chart(int, FILE *, int);        /* Saves objects */
static int load_chart(char *);                  /* loads objects */
static void dsp_doy(int, int);			/* displays doy value */
static void displayhalfmonth(struct cht *, int, int);	/* display routine */
static void displaymonth(struct cht *, utc_val, int, int);			/* display routine */
static void displayhalfyear(struct cht *, int, int);	/* display routine */
static void displayyear(struct cht *, int, int);	/* display routine */
static void displayquarter(struct cht *, int, int);	/* display routine */
static void displayweek(struct cht *, int, int);	/* display routine */
static void displaydow(struct cht *, int, int);
static void displayfy(struct cht *, int, int);		/* display routine */
static void verify_fun(Widget, XtPointer, XtPointer);

static struct ops cht_ops = {
    dsp_chart, edt_chart, rem_chart, lim_chart, loc_chart, mov_chart, cpy_chart,
    msg_chart, sav_chart
};

static Widget chart_dialog;			/* dialog shell for popup */
static Widget parent_shell;

static DialogOption *resolw; 
static DialogOption *fontw, *pointw;
static DialogOption *colorw;
static DialogOption *dispw;
static DialogOption *datew, *eventw;
static DialogOption *flagsw;
static DialogDate *sdate, *edate, *stdate;

static int new_font;				/* new font id */
static int new_point;				/* new point id */
static int new_color;				/* new color id */
static enum tim_res new_resltn;			/* new resolution id */
static int new_date;                            /* new toggle id */
static int new_disp;                            /* new toggle id */
static int new_event;                           /* new toggle id */
static int new_flag;				/* new toggle id */
static int doy = 0;				/* display doy value */

/***********************************************************************
 *
 * FUNCTION:
 *	init_chart()
 *
 * INPUTS:
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *	initializes the chart default values
 */

void 
init_chart(void)
{
    int linespace;				/* temp indices */
    utc_val start_date, end_date, status_date;	/* chart values */
    enum tim_res resltn;			/* chart values */
    long s;					/* seconds since 01/01/70 */
    struct tm *t;				/* local time structure */
    int mo, da, yr;

    /*  INITIALIZE the chart's start and end dates according to current date */
    s = time(NULL);
    t = localtime(&s);
    mo = t->tm_mon + 1;
    da = t->tm_mday;
    yr = t->tm_year;
    /* convert the year to a 4 digit year */
    if (yr <= 50) {
	yr = yr + 2000;
    } else {
	yr = yr + 1900;
    }
    start_date = set_mdy(1,1,yr);
    end_date = set_mdy(12,31,yr);
    status_date = set_mdy(mo,da,yr);
    linespace = (page_height - 2 * MARGIN) / 32;

    /* Default values */
    current_page = 1;
    pg_lines = 23;
    num_pages = 1;
    page_end = current_page * pg_lines;
    page_begin = page_end - pg_lines + 1;
    y_gap = (int)((y_lines_end - y_act_bottom) /pg_lines);
    
    resltn = MONTHLY; 
    snap_evt = TOG_ON;
    set_evt_tog();
    snap_txt = TOG_OFF;
    issue_disp = TOG_ON;
    utc_bar = TOG_OFF;
    add_chart(start_date, end_date, status_date, 0, RSRC_FONT, RSRC_POINT, 2, 
	2, resltn, 0);
}

/***********************************************************************
 *
 * FUNCTION:
 *	init_chart_object()
 *
 * INPUTS:
 *	parent  (Widget)
 *
 * OUTPUTS:
 *	none
 *
 * RETURNS:
 *	none
 *
 * EXTERNALLY READ:
 *	none
 *
 * EXTERNALLY MODIFIED:
 *	none
 *
 * DESCRIPTION:
 *	registers the chart object and sets the parent
 */

void 
init_chart_object(Widget parent)
{

    register_io_obj('C', load_chart);		/* register object */
    parent_shell = parent;
}

/***********************************************************************
 *
 * FUNCTION:
 *	create_dialog()
 *
 * INPUTS:
 *	none
 *
 * OUTPUTS:
 *	none
 *
 * RETURNS:
 *	none
 *
 * EXTERNALLY READ:
 *	none
 *
 * EXTERNALLY MODIFIED:
 *	none
 *
 * DESCRIPTION:
 *	sets the widgets for a chart object
 */

static void 
create_dialog(void)
{
    static char *fonts[] = {"Courier", "Courier Bold", "Helvetica",
	"Helvetica Bold", "Times", "Times Bold"};

    static char *points[] = { "8", "10", "12", "14", "18", "24" };

    static char *flags[] = { " ", "CY", "FY" };

    static char *resols[] = { "Yearly", "HalfYearly", "Quarterly",
	"Monthly", "HalfMonthly", "BiWeekly", "Weekly", "Daily", "Days of Week"     };

    static char *opts[] = { "No", "Yes" };

    chart_dialog = DialogInit(parent_shell, "Chart Object", "chart", verify_fun,
	(XtPointer)DIALOG_CANCEL);

    DialogAddRow(2);
    sdate = DialogDateCreate("Start Date ");
    edate = DialogDateCreate("End Date ");
    stdate = DialogDateCreate("Status Date");

    DialogAddRow(3);
    fontw = DialogOptionCreate("Font: ", 6, 5, change_font, DIALOG_OPT_STR_ARY,
	fonts, font_values);
    pointw = DialogOptionCreate("Point: ", 6, 10, change_point, 
	DIALOG_OPT_STR_ARY, points, font_sizes);
    colorw = DialogOptionCreate("Color: ", ncolor, 0, change_color, 
	DIALOG_OPT_STR_ARY, color_name, color_index);

    DialogAddRow(2);
    flagsw = DialogOptionCreate("Flags: ", 3, 2, change_flag, 
	DIALOG_OPT_STR_ARY, flags, NULL);
    resolw = DialogOptionCreate("Resolution: ", 9, 4, change_resol, 
	DIALOG_OPT_STR_ARY, resols, NULL);
    dispw = DialogOptionCreate("Display Status Date: ", 2, 1, change_disp,
	DIALOG_OPT_STR_ARY, opts, NULL);
    datew = DialogOptionCreate("Auto Reset of % Dates: ", 2, 0, change_date,
	DIALOG_OPT_STR_ARY, opts, NULL);
    eventw = DialogOptionCreate("Auto Reset of Event Symbols: ", 2, 0, 
	change_event, DIALOG_OPT_STR_ARY, opts, NULL);
    
    DialogStdButtons(verify_fun, (XtPointer)DIALOG_UPDATE, verify_fun,
	(XtPointer)DIALOG_CANCEL, (XtCallbackProc)ShowHelp, "date");

}

/***********************************************************************
 *
 * FUNCTION:
 *	add_chart()
 *
 * INPUTS:
 *	start_date, end_date, status_date	(utc_val)
 *	status_flag, font, point, color, flags 	(int)
 *	resltn					(enum tim_res)
 *	layer					(int)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *	adds new chart object when session is started or when new
 *	file is opened
 */

int 
add_chart(utc_val start_date, utc_val end_date, utc_val status_date, int status_flag, int font, int point, int color, int flags, enum tim_res resltn, int layer)
{
    int i;						/* temp index */

    i = new_index(TRUE);
    if (i != 0) {
	Warning("INTERNAL ERROR - PROGRAM ABORTED");
	sleep(1);
	exit(2);
    }
    objary[i].layer = 0;
    objary[i].z.chtptr = (struct cht *)XtMalloc(sizeof(struct cht));
    objary[i].z.chtptr->start_date = start_date;
    objary[i].z.chtptr->end_date = end_date;
    st_date = status_date;
    objary[i].z.chtptr->font = font;
    objary[i].z.chtptr->point = point;
    objary[i].z.chtptr->color = color;
    objary[i].z.chtptr->flags = flags;
    objary[i].z.chtptr->resltn = resltn;
    st_flag = (enum tog)status_flag;
    objary[i].type = OBJ_CHT;
    objary[i].opsptr = &cht_ops;
    return i;
}

/***********************************************************************
 *
 * FUNCTION:
 *	dsp_chart()
 *
 * INPUTS:
 *	i	(int)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *	draws the chart
 */

void 
dsp_chart(int i)
{
    struct cht *chtptr;				/* local pointer */
    int x, dy;					/* temp coordinates */
    int height;					/* text height */
    char buf[30];				/* temp text buffer */
    int days, val;				/* time differentials */
    int scale, xe, xs, width;			/* temp values */

    chtptr = objary[i].z.chtptr; 
    gr_set_color(color_name[chtptr->color], color_gscale[chtptr->color]);
    gr_move(x_num_offset + 3, y_lines_end);
    gr_draw(x_num_offset + 3, y_act_bottom);
    gr_move(x_right_margin, y_top_margin);
    gr_draw(x_right_margin, y_bottom_margin);
    gr_draw(x_left_margin, y_bottom_margin);
    gr_draw(x_left_margin, y_top_margin);
    gr_draw(x_right_margin, y_top_margin);

    gr_move(x_left_margin, y_hdr_bottom);
    gr_draw(x_right_margin, y_hdr_bottom);
    gr_move(x_left_hdr, y_top_margin);
    gr_draw(x_left_hdr, y_hdr_bottom);
    gr_move(x_rt_hdr, y_top_margin);
    gr_draw(x_rt_hdr, y_hdr_bottom);
    gr_move(x_left_margin, y_act_bottom);
    gr_draw(x_right_margin, y_act_bottom);
    gr_move(x_left_margin, y_lines_end);
    gr_draw(x_right_margin, y_lines_end);
    gr_move(x_time_offset, y_hdr_bottom);
    gr_draw(x_time_offset, y_lines_end);
    gr_move(x_time_offset + 1, y_hdr_bottom);
    gr_draw(x_time_offset + 1, y_lines_end);

    gr_text(x_right_margin - 112, y_bottom_margin + 13, "OEL XOPPS Editor", 0,
	0|10, 0);

    dy = y_act_bottom - y_hdr_bottom;
    if (chtptr->resltn == HALFYEARLY) {
        gr_move(x_time_offset, y_hdr_bottom + dy / 2); 
        gr_draw(x_right_margin, y_hdr_bottom + dy / 2);
    } else if (chtptr->resltn > HALFYEARLY) {
        gr_move(x_time_offset, y_hdr_bottom + dy / 3); 
        gr_draw(x_right_margin, y_hdr_bottom + dy / 3);
        gr_move(x_time_offset, y_act_bottom - dy / 3); 
        gr_draw(x_right_margin, y_act_bottom - dy / 3);
    }       /* if yearly graph nothing */  
    /*
     * if the display day of year toggle is selected,
     * the doy is only printed if the text fits in
     * the width of the columns depending on how much time
     * the chart covers
     * this sets the boolean doy to true if the width of the
     * columns is large enough for the text to fit
     */

    if (utc_bar == TOG_ON) {
	xs = xval(chtptr, chtptr->start_date, START_OF_DAY);
	xe = x_right_margin;
	days = (chtptr->end_date - chtptr->start_date)/UTC_ONE_DAY + 1;
	/*
	 * if resltn is YEARLY or HALFYEARLY days is the number of days
	 * in the chart, then calculate the number of chart separations
	 * for the doy display
	 */
	if ((chtptr->resltn == YEARLY) || (chtptr->resltn == HALFYEARLY)) {
	    val = days/365;
	} else if (chtptr->resltn == QUARTERLY) {
	    if (days < 365) {
	        val = days/4;
	    } else {
	        val = days/365 * 4;
	    }
	} else if (chtptr->resltn == MONTHLY) {
	    if (days < 28) {
	       val = 1;
	    } else {
	       val = days/28;
	    }
	} else if (chtptr->resltn == HALFMONTHLY) {
	    if (days < 14) {
	        val = 1;
	    } else {
	        val = days/14;
	    }
	} else if ((chtptr->resltn == BIWEEKLY) || (chtptr->resltn == WEEKLY)
	    || (chtptr->resltn == DAILY)) {
	    if (chtptr->resltn == BIWEEKLY) {
		scale = 14;
	    } else if (chtptr->resltn == WEEKLY) {
		scale = 7;
	    } else {
		scale = 1;
	    }
	    if (days < scale) {
	       val = scale;
	    } else {
	       val = days/scale;
	    }
	} else if (chtptr->resltn == DAYSOFWEEK) {
	    val = days;
	}
        (void)sprintf(buf, " %03d", get_doy(chtptr->start_date));
	width = gr_strwidth(buf, chtptr->font|chtptr->point);
	if ((xe - xs)/val + 2 > width) {
	    doy = 1;
	} else {
	    doy = 0;
   	}
        if (chtptr->resltn >= QUARTERLY) {
	    height = gr_txheight(chtptr->font|chtptr->point);
	    gr_line(x_time_offset, y_lines_end, x_time_offset, y_lines_end
	        + height + 1);
	    gr_line(x_time_offset + 1,y_lines_end,x_time_offset + 1,y_lines_end
	        + height + 1);
	    gr_line(x_left_margin, y_lines_end + height + 1, x_right_margin, 
	        y_lines_end + height + 1);
	    (void)sprintf(buf, "Day of Year");
	    gr_text(x_left_margin + 32, y_lines_end + height + 1, buf, GR_LEFT,
	        chtptr->font|chtptr->point, 0);
        }
    }

    /*
     * call the individual display routines for drawing the vertical lines
     * and filling in the text 
     * if FY flag then display Year on top line, else display Year in middle
     */

    switch (chtptr->resltn) {
    case YEARLY:
        displayyear(chtptr, y_hdr_bottom, dy);
        break;
    case HALFYEARLY:
	if (chtptr->flags == Y_FY) {
	    displayyear(chtptr, y_hdr_bottom, dy/2);
	    displayfy(chtptr, y_hdr_bottom + dy/2, dy/2);
	} else {
	    displayfy(chtptr, y_hdr_bottom, dy/2);
	    displayyear(chtptr, y_hdr_bottom + dy/2, dy/2);
	}
        displayhalfyear(chtptr, y_act_bottom, dy/2);
        break;
    case QUARTERLY:
	if (chtptr->flags == Y_FY) {
	    displayyear(chtptr, y_hdr_bottom, dy/3);
	    displayfy(chtptr, y_hdr_bottom + dy/3, dy/3);
	} else {
	    displayfy(chtptr, y_hdr_bottom, dy/3);
	    displayyear(chtptr, y_hdr_bottom + dy/3, dy/3);
	}
        displayquarter(chtptr, y_act_bottom - dy/3, dy/3);
        break;
    case MONTHLY:
	if (chtptr->flags == Y_FY) {
	    displayyear(chtptr, y_hdr_bottom, dy/3);
	    displayfy(chtptr, y_hdr_bottom + dy/3, dy/3);
	} else {
	    displayfy(chtptr, y_hdr_bottom, dy/3);
	    displayyear(chtptr, y_hdr_bottom + dy/3, dy/3);
	}
        displaymonth(chtptr, chtptr->start_date, y_act_bottom - dy/3, dy/3);
        break;
    case HALFMONTHLY:
	if (chtptr->flags == Y_FY) {
	    displayyear(chtptr, y_hdr_bottom, dy/3);
	    displayfy(chtptr, y_hdr_bottom + dy/3, dy/3);
	} else {
	    displayfy(chtptr, y_hdr_bottom, dy/3);
	    displayyear(chtptr, y_hdr_bottom + dy/3, dy/3);
	}
        displaymonth(chtptr, chtptr->start_date, y_act_bottom - dy/3, dy/3);
        displayhalfmonth(chtptr, y_act_bottom, dy/3);
        break;
    case BIWEEKLY:
	displayyear(chtptr, y_hdr_bottom, dy/3);
	displaymonth(chtptr, chtptr->start_date, y_hdr_bottom + dy/3, dy/3);
 	displayweek(chtptr, y_act_bottom - dy/3, dy/3);
	break;
    case WEEKLY:
	displayyear(chtptr, y_hdr_bottom, dy/3);
	displaymonth(chtptr, chtptr->start_date, y_hdr_bottom + dy/3, dy/3);
 	displayweek(chtptr, y_act_bottom - dy/3, dy/3);
	break;
    case DAILY:
	displayyear(chtptr, y_hdr_bottom, dy/3);
	displaymonth(chtptr, chtptr->start_date, y_hdr_bottom + dy/3, dy/3);
 	displayweek(chtptr, y_act_bottom - dy/3, dy/3);
	break;
    case DAYSOFWEEK:
	displaymonth(chtptr, chtptr->start_date, y_hdr_bottom, dy/3);
	displaydow(chtptr, y_hdr_bottom + dy/3, dy/3);
	break;
    default:
        break;
    }

    /* 
     * if the status date flag is on, find the status date object
     * and display the status date
     */

    if (st_flag == TOG_ON) {
   	x = find_object_type(OBJ_STT);
	if (x >= 0) {
	    (*(objary[x].opsptr->loc))(x, OBJECT);
	    (*(objary[x].opsptr->dsp))(x);
	}
    }

   for (i = 0; i < npln; i++) {
	dsp_pline(i);
   }
}

/***********************************************************************
 *
 * FUNCTION:
 *      rem_chart()
 *
 * INPUTS:
 *	i       (int)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *	This module removes chart i from the data base
 *
 */

static void 
rem_chart(int i, int dir)
{
    struct obj *objptr;				/* object pointer */

    objptr = &(objary[i]);
    freeRectList(objptr->rlist);
    XtFree((char *)objptr->z.evtptr);
    rem_object(objptr);

}

/***********************************************************************
 *
 * FUNCTION:
 *      mov_chart()
 *
 * INPUTS:      
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *	The chart cannot be moved at this time
 *
 */

static void mov_chart(int i, int j, int k, int dir)
{
/* THIS IS DISABLED */
}

/***********************************************************************
 *
 * FUNCTION:
 *      sav_chart()
 *
 * INPUTS:
 *	i               (int)
 *      fp              (FILE *)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *	This module saves chart i to file fp.
 */

static void 
sav_chart(int i, FILE *fp, int dir)
{
    struct cht *chtptr;				/* chart object pointer */
    char buf[128];				/* temp text buffer */

    chtptr = objary[i].z.chtptr;
    buf[0] = 'C';
    buf[1] = ' ';
    record_print(buf+2, "tttddddddddd", chtptr->start_date, chtptr->end_date, 
	st_date, st_flag, chtptr->font, chtptr->point,chtptr->color,
	chtptr->flags,chtptr->resltn, objary[i].layer, utc_bar, vgrid);
    fputs(buf, fp);
}

/***********************************************************************
 *
 * FUNCTION:
 *	msg_chart()
 *
 * INPUTS:
 *	i       (int)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *	displays the chart message for chart i
 */

static void 
msg_chart(int i, int dir)
{
    char buf[64];				/* temp text buffer */

    strcpy(buf, "Timeline Area ");
    Message(buf);
}

/***********************************************************************
 *
 * FUNCTION:
 *	cpy_chart()
 *
 * INPUTS:
 *	to, from        (obj *)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *	This module copies chart from to chart to
 */

static void 
cpy_chart(struct obj *to, struct obj *from)
{
    if (from->type == OBJ_NUL) {
	 return;
    }

    to->z.chtptr = (struct cht *)XtMalloc(sizeof(struct cht));
    to->z.chtptr->start_date = from->z.chtptr->start_date;
    to->z.chtptr->end_date = from->z.chtptr->end_date;
    to->z.chtptr->font = from->z.chtptr->font;
    to->z.chtptr->point = from->z.chtptr->point;
    to->z.chtptr->color = from->z.chtptr->color;
    to->z.chtptr->flags = from->z.chtptr->flags;
    to->z.chtptr->resltn = from->z.chtptr->resltn;
    to->type = OBJ_CHT;
    to->layer = from->layer;
    to->opsptr = &cht_ops;
    to->rlist = copyRectList(from->rlist);
}

/***********************************************************************
 *
 * FUNCTION:
 *	edt_chart()
 *
 * INPUTS:
 *	i, new  (int)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *	edits object i
 */

static void 
edt_chart(int i, int new)
{
    if (chart_dialog == NULL) {
	create_dialog();
    }

    (*(objary[i].opsptr->cpy))(&objtmp, &objary[i]);
    new_color = objtmp.z.chtptr->color;
    new_point = objtmp.z.chtptr->point;
    new_font = objtmp.z.chtptr->font;
    new_resltn = objtmp.z.chtptr->resltn;
    new_event = auto_ereset;
    new_disp = st_flag;
    new_date = auto_areset;
    new_flag = objtmp.z.chtptr->flags;
    if (new) {
	(*(objary[i].opsptr->rem))(i, OBJECT);
	i = -1;
    }
    DialogDateSet(sdate, objtmp.z.chtptr->start_date);
    DialogDateSet(edate, objtmp.z.chtptr->end_date);
    DialogDateSet(stdate, st_date);
    DialogOptionSet(fontw, (int)new_font);
    DialogOptionSet(pointw, (int)new_point);
    DialogOptionSet(colorw, (int)new_color);
    DialogOptionSet(resolw, (int)new_resltn);
    DialogOptionSet(datew, (int)auto_areset);
    DialogOptionSet(eventw, (int)auto_ereset);
    DialogOptionSet(dispw, (int)st_flag);
    DialogOptionSet(flagsw, objtmp.z.chtptr->flags);
    EditObject(i, chart_dialog);
}

/***********************************************************************
 *
 * FUNCTION:
 *      loc_chart()
 *
 * INPUTS:
 *	i       (int)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *	This module locates the position of chart object i
 *
 */

static void 
loc_chart(int i, int dir)
{
    XRectangle r1, r2;          /* rectangle */

    r1.x = 0;
    r1.y = 0;
    r1.width = page_width;
    r1.height = page_height;

    r2.x = x_time_offset;
    r2.y = y_hdr_bottom;
    r2.width = x_right_margin - x_time_offset;
    r2.height = y_act_bottom - y_hdr_bottom;
    setRectList(objary[i].rlist, 2, &r1, RL_EXPOSE, &r2, RL_PRIMARY);

}

/***********************************************************************
 *
 * FUNCTION:
 *      lim_chart()
 *
 * INPUTS:
 *	i               (int)
 *      x1, y1, x2, y2  (int *)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *	This module limits the range of motion of the chart object
 */

static void 
lim_chart(int i, int *x1, int *y1, int *x2, int *y2, int dir)
{
    /*
     * Chart cannot move at this time
     */

    *x1 = x_time_offset;
    *y1 = y_hdr_bottom;
    *x2 = x_right_margin;
    *y2 = y_act_bottom;
}

/***********************************************************************
 *
 * FUNCTION:
 *	chart_ok_button()
 *
 * INPUTS:
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *	checks the values when the ok button is selected
 */

static void 
chart_ok_button(void)
{
    int change = DIALOG_NO_CHANGE;
    int st_change = DIALOG_NO_CHANGE;		/* temp boolean value */
    int found = FALSE;				/* only position status if
						   one does not exist */
    int i;					/* loop counter */
    utc_val temp_date;

    temp_date = DialogDateGet(sdate);
    if (temp_date != UTC_INVALID) {
	if (temp_date != objtmp.z.chtptr->start_date) {
	    change |= DIALOG_UPDATE;
	}
    } else {
	Warning("Improper Start Date");
	change |= DIALOG_ERROR;
    }
    objtmp.z.chtptr->start_date = temp_date;
    temp_date = DialogDateGet(edate);
    if (temp_date != UTC_INVALID) {
	if (temp_date != objtmp.z.chtptr->end_date) {
	    change |= DIALOG_UPDATE;
	}
    } else {	
	Warning("Improper End Date");
	change |= DIALOG_ERROR;
    }
    objtmp.z.chtptr->end_date = temp_date;
    if (objtmp.z.chtptr->end_date < objtmp.z.chtptr->start_date) {
	Warning("End date must be later than Start date");
	change |= DIALOG_ERROR;
    }
    temp_date = DialogDateGet(stdate);
    if (temp_date != UTC_INVALID) {
	if (temp_date != st_date) {
	    st_change |= DIALOG_UPDATE;
	}
    } else {	
	Warning("Improper Status Date");
	st_change |= DIALOG_ERROR;
    }
    st_date = temp_date;
    if (new_disp != st_flag) {
	st_change |= DIALOG_UPDATE;
    }
    st_flag = DialogOptionGet(dispw);
    for (i = 1; i < nobj; i++) {
	if (objary[i].type == OBJ_STT) {
	    found = DIALOG_UPDATE;
	}
    }
    if ((st_change) && (!found)) {
	add_status(850, 55, 0, 10, 0, 0);
    } 
    change |= st_change;
    if (new_resltn != objtmp.z.chtptr->resltn) {
	change |= DIALOG_UPDATE;
    }
    objtmp.z.chtptr->resltn = DialogOptionGet(resolw);
    if (new_font != objtmp.z.chtptr->font) {
	change |= DIALOG_UPDATE;
    }
    objtmp.z.chtptr->font = DialogOptionGet(fontw);
    if (new_point != objtmp.z.chtptr->point) {
	change |= DIALOG_UPDATE;
    }
    objtmp.z.chtptr->point = DialogOptionGet(pointw);
    if (new_date != (int)auto_areset) {
	change |= DIALOG_UPDATE;
    }
    auto_areset = DialogOptionGet(datew);
    if (new_event != (int)auto_ereset) {
	change |= DIALOG_UPDATE;
    }
    auto_ereset = DialogOptionGet(eventw);
    if (new_flag != objtmp.z.chtptr->flags) {
	change |= DIALOG_UPDATE;
    }
    objtmp.z.chtptr->flags = DialogOptionGet(flagsw);

    if (new_color != objtmp.z.chtptr->color) {
	change |= DIALOG_UPDATE;
    }
    objtmp.z.chtptr->color = DialogOptionGet(colorw);

    object_change = change;
    DialogFlagSet(change);
}

/***********************************************************************
 *
 * FUNCTION:
 *	cancel_button()
 *
 * INPUTS:
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *	discards any edits and closed the window
 */

static void 
cancel_button(void)
{
    object_change = DIALOG_CANCEL;
    DialogFlagSet(DIALOG_CANCEL);
}

/**********************************************************************
 *
 * FUNCTION:
 *     load_chart() 
 *
 * INPUTS:
 *     buf		(char *) 
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *     loads chart object record 
 */

static int 
load_chart(char *buf)
{
    utc_val start_date, end_date, status_date;		/* dates of chart */
    int status_flag, font, point, color, flags;		/* pieces of object */
    enum tim_res resltn;				/* time resolution */
    int layer;						/* layer of object */
    int i;

    if (record_scan(buf+1, "tttddddddddd", &start_date, &end_date, &status_date,
	&status_flag, &font, &point, &color, &flags, &resltn, &layer, &utc_bar,
	&vgrid) == 12) {
	if ((utc_bar != TOG_ON) && (utc_bar != TOG_OFF)) {
            Warning("Illegal Doy Bar toggle value %d", utc_bar);
            return -1;
        } else {
            set_utc_tog();
	}
	if ((status_flag != TOG_ON) && (status_flag != TOG_OFF)) {
	    Warning("Illegal Chart status flag %d", status_flag);
	} else if ((font != GR_COURIER) && (font != GR_COURIER_BOLD) && 
	    (font != GR_HELVETICA) && (font != GR_HELVETICA_BOLD) && (font !=
	    GR_TIMES) && (font != GR_TIMES_BOLD)) {
            Warning("Illegal Chart font %d", font);
        } else if ((point != 8) && (point != 10) && (point != 12) &&
            (point != 14) && (point != 18) && (point != 24)) {
            Warning("Illegal Chart point %d", point);
        } else if ((color < 0) || (color >= ncolor)) {
	    Warning("Illegal Chart color %d", color);
	} else if ((flags < 0) || (flags > 2)) {
	    Warning("Illegal Chart flags %d", flags);
	} else if (((int)resltn < YEARLY) || ((int)resltn > DAYSOFWEEK)) {
	    Warning("Illegal Chart resltn %d", resltn);
	} else if ((layer < 0) || (layer > 3)) {
	    Warning("Illegal Chart layer %d", layer);
	} else if ((vgrid != 0) && (vgrid != 1)) {
	    Warning("Illegal Vertical Grid value %d", vgrid);
	} else {
	    i = add_chart(start_date, end_date, status_date, status_flag, font,
	        point, color, flags, resltn, layer);
	    (*(objary[i].opsptr->loc))(i, OBJECT);
	    return 0;
	}
	return -1;
    } else {
	Warning("Error in Chart Object - default being used");
	init_chart();
	return -1;
    }
}

/***********************************************************************
 *
 * FUNCTION:
 *	change_point()
 *
 * INPUTS:
 *	button  		(Widget)
 *      option, any_data        (int)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *	sets new font point size for chart object
 */

static void 
change_point(Widget button, XtPointer option, XtPointer any_data)
{
    new_point = (int)option;
}

/***********************************************************************
 *
 * FUNCTION:
 *	change_color()
 *
 * INPUTS:
 *	button  		(Widget)
 *      option, any_data        (int)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *	sets new color for chart object
 */

static void 
change_color(Widget button, XtPointer option, XtPointer any_data)
{
    new_color = (int)option; 
}

/***********************************************************************
 *
 * FUNCTION:
 *	change_font()
 *
 * INPUTS:
 *	button  		(Widget)
 *      option, any_data        (int)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *	sets new font for chart object
 */

static void 
change_font(Widget button, XtPointer option, XtPointer any_data)
{
    new_font = (int)option;
}

/***********************************************************************
 *
 * FUNCTION:
 *	change_resol()
 *
 * INPUTS:
 *	button  		(Widget)
 *      option, any_data        (int)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *	changes the chart resolution to the input date value
 */

static void 
change_resol(Widget button, XtPointer option, XtPointer any_data)
{
    new_resltn = (int)option;
}

/***********************************************************************
 *
 * FUNCTION:
 *      change_date()
 *
 * INPUTS:
 *      button          - (Widget)
 *      option          - (int)
 *      any_data        - (int)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *      This module sets the selected change % dates toggle
 */

static void 
change_date(Widget button, XtPointer option, XtPointer any_data)
{
    new_date = (int)option;
}

/***********************************************************************
 *
 * FUNCTION:
 *      change_disp()
 *
 * INPUTS:
 *      button          - (Widget)
 *      option          - (int)
 *      any_data        - (int)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *      This module sets the selected display status date toggle
 */

static void 
change_disp(Widget button, XtPointer option, XtPointer any_data)
{
    new_disp = (int)option;
}

/***********************************************************************
 *
 * FUNCTION:
 *      change_event()
 *
 * INPUTS:
 *      button          - (Widget)
 *      option          - (int)
 *      any_data        - (int)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *      This module sets the selected change event toggle
 */

static void 
change_event(Widget button, XtPointer option, XtPointer any_data)
{
    new_event = (int)option;
}

/***********************************************************************
 *
 * FUNCTION:
 *      change_flag()
 *
 * INPUTS:
 *      button          - (Widget)
 *      option          - (int)
 *      any_data        - (int)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *      This module sets the selected change flag toggle
 */

static void 
change_flag(Widget button, XtPointer option, XtPointer any_data)
{
    new_flag = (int)option;
}

/***********************************************************************
 *
 * FUNCTION:
 *	displayyear()
 *
 * INPUTS:
 *	chtptr		(struct cht *)
 *	y, dy		(int)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *	displays the year text and line on the chart
 */

static void 
displayyear(struct cht *chtptr, int y, int dy)
{
    utc_val sdate, edate;  	/* local time notes */
    char buf[40];           	/* temporary string buffer */
    int xs, xe;             	/* x start and end coordinates */
    int xm;                 	/* center position of a field */
    int y1, y2;             	/* y coordinates for vertical lines */
    int width, height;          /* width of a string in pixels */
    int done;               	/* TRUE when done */
    int mo, da, yr;		/* month, day, year for date */
    int whatbuf = 1;		/* for formatting text */
    int first = 1;	        /* format first time through only */
    int start_doy;		/* start date doy for 1st Quarter DOY */

    y1 = y;
    y2 = y + dy + 1;

    /* display year */
    sdate = chtptr->start_date;
    done = FALSE;
    while (!done) {
        get_mdy(&mo, &da, &yr, sdate);
        edate = set_mdy(1, 1, yr + 1);
        xs = xval(chtptr, sdate, START_OF_DAY);
        xe = xval(chtptr, edate, START_OF_DAY);
        if (xe == XVAL_LATE) {
            xe = x_right_margin;
  	    done = TRUE;
        }
        xm = (xs + xe) / 2;
	if (whatbuf) {
            (void)sprintf(buf, "%d", yr);
	} else {
	    (void)sprintf(buf, "  %02d", yr % 100);
	}
	while (first) {
	    if ((width  = gr_strwidth(buf, chtptr->font|chtptr->point)) 			+ 2 > (xe - xs)) {
	        (void)sprintf(buf, "  %02d", yr % 100);
	        whatbuf = 0;
	    }

	    /*
             * prints out first quarter doy value
	     */

	    if ((chtptr->resltn == QUARTERLY) && (utc_bar)) {
		start_doy = get_doy(chtptr->start_date);
                dsp_doy(start_doy, xs);
	    }
	    first = 0;
	}
	height = gr_txheight(chtptr->font|chtptr->point);
	if ((xe != XVAL_EARLY) && (xe-xs > gr_strwidth(buf,
	    (chtptr->font|chtptr->point)))) {
            gr_text(xm, y + dy/2 + height/2 + 2,buf,GR_CENTER,chtptr->font
	        |chtptr->point, 0);
	}
        if (!done) {        /* don't draw year line at end of chart */
	    gr_line(xe, y1, xe, y2);
	    if ((chtptr->flags != Y_FY) && (chtptr->resltn <= HALFMONTHLY)) {
               gr_line(xe+1, y1, xe+1, y2);
	    }
	    if (chtptr->resltn <= HALFYEARLY) {
                gr_line(xe, y_act_bottom, xe, y_lines_end);
		if (chtptr->flags != Y_FY) {
                    gr_line(xe+1, y_act_bottom, xe+1, y_lines_end);
		}
	    }
        }
        sdate = edate;
    }
}

/***********************************************************************
 *
 * FUNCTION:
 *	displaymonth()
 *
 * INPUTS:
 *	chtptr		(struct cht *)
 *	date		(utc_val)
 *	y, dy		(int)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *	displays the month text and line on the chart if monthly or bimonthly
 *	resolution are selected	
 */

static void 
displaymonth(struct cht *chtptr, utc_val date, int y, int dy)
{
    static char *mn[2][12] = { 
	"J", "F", "M", "A", "M", "J", "J", "A", "S", "O", "N", "D", "JAN", \
	"FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", \
	"DEC" 
    };

    utc_val sdate, mdate;          	    /* temp date variable */
    int xs, xe;                             /* start and end x coordinates */
    int mo,da,yr;		    	    /* month, day, year of date */
    int y1, y2;                             /* y coordinates */
    int width, height;                      /* width for text */
    int done;                               /* TRUE when done */
    char buf[8];			    /* temp text buffer */
    int first=1;			    /* format first time through only */
    int whatbuf;			    /* for formatting text */
    int doy;				    /* day of year text */

    y1 = y;
    sdate = date; 
    get_mdy(&mo,&da,&yr, sdate);
    /* 
     * set up initial buffers
     */
    if (chtptr->resltn < BIWEEKLY) {
	y2 = y_lines_end;
	whatbuf = 3;
	(void)sprintf(buf, "%s", mn[1][mo - 1]);
    } else if (chtptr->resltn < DAYSOFWEEK) {
	y2 = y_act_bottom - dy;
	whatbuf = 3;
	(void)sprintf(buf, "%s", mn[1][mo - 1]);
    } else {
	y2 = y_hdr_bottom + dy;
	whatbuf = 1;
	(void)sprintf(buf, "%s %d", mn[1][mo - 1], yr);
    }	
    done = FALSE;
    while (!done) {
        xs = xval(chtptr, sdate, START_OF_DAY);
        if (mo == 12) {
            mdate = set_mdy(1, 1, yr + 1);
        } else {
            mdate = set_mdy(mo + 1, 1, yr);
        }
	xe = xval(chtptr, mdate, END_OF_DAY);
        if (xe == XVAL_LATE) {
	    xe = x_right_margin;
 	    done = TRUE;
        }
	while (first) {
	    /*
             * the first time through find the buffer that is small
             * enough for the text to fit in the width of the column
	     * it is set the first time through only for consistency
             */
	    if (whatbuf == 1) {
		if ((width = gr_strwidth(buf, chtptr->font | chtptr->point)) + 2
		    > (xe - xs)) {
		    whatbuf = 2;
	    	    (void)sprintf(buf, "%s %d", mn[0][mo - 1], yr);
	        }
	   	if ((width = gr_strwidth(buf, chtptr->font|chtptr->point)) + 2 >
		    (xe - xs)) {
		    whatbuf = 3;
		    (void)sprintf(buf, "%s", mn[1][mo-1]);
		}
	    }
	    if ((width = gr_strwidth(buf, chtptr->font|chtptr->point)) + 2 >
		(xe - xs)) {
		whatbuf = 4;
	    }
	    first = 0; 
	}
	/* 
	 * after finding the right buffer, it sets the text
         */
	switch(whatbuf) {
	case 1:
	    (void)sprintf(buf, "%s %d", mn[1][mo - 1], yr);
	    break;
	case 2:
	    (void)sprintf(buf, "%s %d", mn[0][mo - 1], yr);
	    break;
	case 3:
	    (void)sprintf(buf, "%s", mn[1][mo - 1]);
	    break;
	case 4:
	    (void)sprintf(buf, "%s", mn[0][mo - 1]);
	    break;
	default:
	    break;
	}
	if (vgrid == G_SOLID) {
    	    if ((mo == 1) && (chtptr->flags != Y_FY)) {
                gr_line(xs, y1, xs, y2);
		if (chtptr->resltn <= HALFMONTHLY) {
	            gr_line(xs+1, y1, xs+1, y2);
		}
	    } else if ((mo == 10) && (chtptr->flags == Y_FY) && 
		(chtptr->resltn <= HALFMONTHLY)) {
                gr_line(xs, y1, xs, y_lines_end);
	        gr_line(xs+1, y1, xs+1, y_lines_end);
	    } else {
                gr_line(xs, y1, xs, y2);
	    }
	}
	height = gr_txheight(chtptr->font|chtptr->point);
	gr_text((xs + xe)/2, y + dy/2 + height/2 + 2, buf,
	    GR_CENTER, chtptr->font|chtptr->point, 0);
	if ((chtptr->resltn <= HALFMONTHLY) && (utc_bar)) {
	    doy = get_doy(sdate);
	    dsp_doy(doy, xs);
	}
        sdate = mdate;
        get_mdy(&mo,&da,&yr, sdate);
    } 
}

/***********************************************************************
 *
 * FUNCTION:
 *	displayhalfyear()
 *
 * INPUTS:
 *	chtptr		(struct cht *)
 *	y, dy		(int)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *	displays half year resolution lines on the chart
 */

static void 
displayhalfyear(struct cht *chtptr, int y, int dy)
{
    int x, y1, y2;                              /* temp x and y coordinates */
    utc_val mdate;                              /* middle of year date */
    int done, mo, da, yr;                       /* TRUE when done */
    int incr = 0;				/* temp increment index */	

    get_mdy(&mo, &da, &yr, chtptr->start_date);
    y1 = y;
    y2 = y_lines_end;
    done = FALSE;
    while (!done) {
        mdate = set_mdy(7, 1, yr + incr);
        x = xval(chtptr, mdate, END_OF_DAY);
        if (x == XVAL_LATE) {
            done = TRUE;
        } else if (x != XVAL_EARLY) {
	    if (vgrid == G_SOLID) {
                gr_line(x, y1, x, y2);
	    }
        }
        incr += 1;
    }

}


/***********************************************************************
 *
 * FUNCTION:
 *	displayhalfmonth()
 *
 * INPUTS:
 *	chtptr		(struct cht *)
 *	y, dy		(int)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *	displays bi-monthly lines on the chart
 */

static void 
displayhalfmonth(struct cht *chtptr, int y, int dy)
{
    int xs, y1, y2;                         /* temp x and y coordinates */
    utc_val sdate;                   	    /* start of year date */
    int done, mo, da, yr;                   /* TRUE when done */
    int incr = 0;			    /* temp increment index */
    int doy;			 	    /* day of year text */

    sdate = chtptr->start_date;
    xs = xval(chtptr, sdate, START_OF_DAY);
    y1 = y;
    y2 = y_lines_end;
    done = FALSE;
    while (!done) {
        get_mdy(&mo, &da, &yr, sdate);
        if (mo == 12) {
            sdate = set_mdy(1, 16, yr + 1);
        } else {
            sdate = set_mdy(mo + incr, 16, yr);
        }
        xs = xval(chtptr, sdate, END_OF_DAY);
        if (xs == XVAL_LATE) {
	    xs = x_right_margin;
            done = TRUE;
        } else  {
	    if (vgrid == G_SOLID) {
                gr_line(xs, y1, xs, y2);
	    }
	    doy = get_doy(sdate);
	    if (utc_bar) {
	        dsp_doy(doy, xs);
	    }
        }
        incr = 1;
    }
}

/***********************************************************************
 *
 * FUNCTION:
 *	displayquarter()
 *
 * INPUTS:
 *	chtptr		(struct cht *)
 *	y, dy		(int)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *	displays the quarters text and lines on the chart
 */

static void 
displayquarter(struct cht *chtptr, int y, int dy)
{
    int xs, xe, y1, y2;                       /* temp x and y coordinates */
    utc_val sdate, mdate;                     /* year dates */
    int done;                                 /* TRUE when done */
    int mo, da, yr;		 	      /* month, day, year of date */
    int q;                                    /* quarter counter */
    static char *c[] = {"1", "2", "3", "4"};  /* quarter text character */
    int doy;			      	      /* day of year */
    int height;				      /* height of text */

    q = 0;
    sdate = chtptr->start_date;
    xs = xval(chtptr, sdate, START_OF_DAY);
    get_mdy(&mo, &da, &yr, sdate);
    mdate = set_mdy(3 * q + 4, 1, yr);
    y1 = y;
    y2 = y_lines_end;
    done = FALSE;
    height = gr_txheight(chtptr->font|chtptr->point);
    while (!done) {
        xe = xval(chtptr, mdate, START_OF_DAY);
        if ((xe > 0) && (vgrid == G_SOLID)) {
            gr_line(xe, y1, xe, y2);
        }
	if ((((q == 3) && (chtptr->flags != Y_FY)) || ((q == 2) && 
	    (chtptr->flags == Y_FY))) && (xe != XVAL_EARLY)) {
            gr_line(xe, y1, xe, y2);
	    gr_line(xe+1, y1, xe+1, y2);
	}
        if (xe == XVAL_LATE) {
	    xe = x_right_margin;
            done = TRUE;
        }

	/*
	 * don't print last one if it is off screen or
	 * won't fit in remaining space
	 */
        if ((xe != XVAL_EARLY)  && (xe - xs > gr_strwidth(c[q], 
		(chtptr->font|chtptr->point)))) {
            gr_text((xs + xe)/2, y + dy/2 + height/2 + 2,c[q],
	        GR_CENTER, chtptr->font | chtptr->point, 0);
	    doy = get_doy(mdate);
	    if (utc_bar) {
	        dsp_doy(doy, xe);
	    }
            xs = xe;
        }
        get_mdy(&mo, &da, &yr, mdate);
        switch (++q) {
        case 4:
            q = 0;
        case 1:
        case 2:
            mdate = set_mdy(3 * q + 4, da, yr);
            break;
        case 3:
            mdate = set_mdy(1, da, yr + 1);
            break;
        }
    }
}

/***********************************************************************
 *
 * FUNCTION:
 *	displayweek()
 *
 * INPUTS:
 *	chtptr		(struct cht *)
 *	y, dy		(int)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *	displays the chart weekly, both lines and text
 */

static void 
displayweek(struct cht *chtptr, int y, int dy)
{
    utc_val sdate, edate;		/* temp date variable */
    int i, scale;			/* temp variables */
    int xs, xe;				/* start/end x coordinates */
    int mo, da, yr;			/* month, day, year of date */
    int y1, y2, y3;			/* temp indices */
    int done;				/* TRUE when done */
    int days;				/* number of days, day of week */
    char buf[20];			/* temp text buffer */
    int doy;				/* day of year text */
    int height;				/* height of text */

    y1 = y;
    y2 = y_lines_end;
    y3 = y_act_bottom;

    sdate = chtptr->start_date;
    xs = xval(chtptr, sdate, START_OF_DAY);
    done = FALSE;
    /*
     * set the scale for the number of days in a column
     */
    if (chtptr->resltn == BIWEEKLY) {
        scale = 14;
    } else {
	scale = 7;
    } 
    i = scale;
    height = gr_txheight(chtptr->font|chtptr->point);
    while (!done) {
        get_mdy(&mo, &da, &yr, sdate);
	/*
         * set the length of the month correctly
         */
	if ((mo == 4) || (mo == 6) || (mo == 9) || (mo == 11)) { 
	    days = 30;
	} else if (mo == 2) {
	    if ((yr % 4) == 0) {
		days = 29;
	    } else {
	        days = 28;
	    }
	} else {
	    days = 31;
	}
	if (da == days) {
	    if (mo == 12) {
		edate = set_mdy(1, 1, yr + 1);
	    } else {
	        edate = set_mdy(mo + 1, 1, yr);
	    }
	} else {
	    edate = set_mdy(mo, da + 1, yr);
	}
	xs = xval(chtptr, sdate, START_OF_DAY);
	xe = xval(chtptr, edate, START_OF_DAY);
	if (xe == XVAL_LATE) {
	    done = TRUE;	
 	    break;
	}
	if (((!week_monday) && (i == scale)) || ((week_monday) && 
	    (!strcmp(getx_wkday(sdate), "Monday")))) {
	    if (chtptr->resltn == DAILY) {	
	 	/* draw week separating line */
		if (vgrid == G_SOLID) {
	            gr_line(xs, y1, xs, y3);
	 	}
		if ((mo == 1) && (da == 1)) {
		    gr_line(xs+1, y1, xs + 1, y3);
		}
	    } else {
		if (vgrid == G_SOLID) {
	            gr_line(xs, y1, xs, y2);
	 	}
		if ((mo == 1) && (da == 1)) {
		    gr_line(xs+1, y1, xs+1, y2);
		}
	    }
	    (void)sprintf(buf, "%02d", da);
	    if ((xe != XVAL_EARLY) && (x_right_margin - xs > gr_strwidth(buf,
		chtptr->font|chtptr->point))) {
	        gr_text((xs + xe)/2, y + dy/2 + height/2 + 2, buf,
                    GR_LEFT, chtptr->font | chtptr->point, 0);
	    }
	    i = 0;
	    doy = get_doy(sdate);
	    if (utc_bar) {
	        dsp_doy(doy, xs);
	    }
	}
	if (chtptr->resltn == DAILY) {	
	   /* draw daily line */
	    if (vgrid == G_SOLID) {
	        gr_line(xs, y3, xs, y2);
	    }
	    doy = get_doy(sdate);
	    if (utc_bar) {
	        dsp_doy(doy, xs);
	    }
   	}
	sdate = edate;
	i++;
    }
}

/***********************************************************************
 *
 * FUNCTION:
 *      displaydow()
 *
 * INPUTS:
 *      chtptr          (struct cht *)
 *      y, dy     	(int)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *      displays the days of the week text and lines on the chart
 */

static void 
displaydow(struct cht *chtptr, int y, int dy)
{
    static char *wkday[7] = { "M", "T", "W", "T", "F", "S", "S" };
    utc_val sdate, edate;			/* start and end dates */
    int xs, xe;					/* x coordinates for dates */
    int mo, da, yr;				/* month, day, year */
    int y1, y2, y3;				/* y coordinates for dates */
    int done;					/* True if done */
    int month;					/* boolean value */
    int days, dow;				/* number days index */
    char buf[2];				/* temp text buffer */
    int doy;					/* day of year text */
    int height;					/* height of text */

    y1 = y;
    y2 = y_lines_end;
    y3 = y_act_bottom;

    sdate = chtptr->start_date;
    xs = xval(chtptr, sdate, START_OF_DAY);
    get_mdy(&mo, &da, &yr, sdate);
    done = FALSE;
    month = 0;
    height = gr_txheight(chtptr->font|chtptr->point);
    while(!done) {
	get_mdy(&mo, &da, &yr, sdate);
	dow = get_wkday(sdate);
	/*
         * set the correct number of days according to the month
         */
 	if ((mo == 4) || (mo == 6) || (mo == 9) || (mo == 11)) {
	    days = 30;
	} else if (mo == 2) {
	    if ((yr % 4) == 0) {	
		days = 29;
	    } else {
		days = 28;
	    }
	} else {
	    days = 31;
	}
	/*
         * if you have reached the end of a month, increment the month
         */
	if (da == days) {
	    if (mo == 12) {
		edate = set_mdy(1, 1, yr + 1);
	    } else {
		edate = set_mdy(mo + 1, 1, yr);
	    }
	    month = 1;
	} else {
	    edate = set_mdy(mo, da + 1, yr);
	}
	xs = xval(chtptr, sdate, START_OF_DAY);
	xe = xval(chtptr, edate, START_OF_DAY);
	if (xe == XVAL_LATE) {
	    done = TRUE;
	    break;
	}
	if ((month) && (!done)) {
	    if (xval(chtptr, edate, END_OF_DAY) != XVAL_LATE) {	
		/* dont want text to print at end of chart */
	        displaymonth(chtptr, edate, y_hdr_bottom, dy);
	    }
	    month = 0;
	}
	if (vgrid == G_SOLID) {
	    gr_line(xs, y1, xs, y2);
	}
	(void)sprintf(buf, "%02d", da);
	gr_text((xs+xe)/2, y + dy/2 + height/2 + 2, buf,
	    GR_CENTER, chtptr->font|chtptr->point, 0);
	gr_text((xs+xe)/2, y3 - dy/2 + height/2 + 2, wkday[dow],
	    GR_CENTER, chtptr->font|chtptr->point, 0);
	doy = get_doy(sdate);
	if (utc_bar) {
	    dsp_doy(doy, xs);
	}
	sdate = edate;
    }
}
/************************************************************************
 *
 * FUNCTION:
 *	displayfy
 *
 * INPUTS:
 *	chtptr		(struct cht *)
 *	y, dy	(int)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *	displays fiscal year lines and text on chart
 */

static void 
displayfy(struct cht *chtptr, int y, int dy)
{
    utc_val sdate, edate;   	/* local time notes */
    char buf[40];           	/* temporary string buffer */
    int xs, xe;             	/* x start and end coordinates */
    int y1, y2;             	/* y coordinates for vertical lines */
    int done;			/* TRUE when done */
    int mo, da, yr;		/* month, day, year of date */
    int mod;			/* for formatting text */
    int height;			/* height of text */

    y1 = y;
    y2 = y + dy;

    /* display fiscal year */
    sdate = chtptr->start_date;
    get_mdy(&mo, &da, &yr, sdate);
    edate = set_mdy(10, 1, yr);
    if (xval(chtptr, edate,  START_OF_DAY) == XVAL_EARLY) {
        edate = set_mdy(10, 1, yr + 1);
    }
    if (chtptr->flags == 0) {
	done = TRUE;
    } else {
    	done = FALSE;
    }
    height = gr_txheight(chtptr->font|chtptr->point);
    while (!done) {
        xs = xval(chtptr, sdate, START_OF_DAY);
        xe = xval(chtptr, edate, START_OF_DAY);
        if (xe == XVAL_LATE) {
            xe = x_right_margin;
            done = TRUE;
        }
	/* prints Fiscal Year */
        get_mdy(&mo, &da, &yr, edate);
	if (yr > 2000) {
	    mod = 200;
	} else {
	    mod = 100;
	}
        (void)sprintf(buf, "FY%02d", yr % mod);
	if (sdate != edate) {
	    /*
	     * if last entry doesn't fit on screen, don't print it
	     */
	    if ((xe != XVAL_EARLY) && (xe - xs) > gr_strwidth(buf, 
		(chtptr->font|chtptr->point))) {
                gr_text((xs + xe)/2,y2 - dy/2 + height/2 + 2,buf,GR_CENTER,
	            chtptr->font | chtptr->point, 0);
	    }
            if (!done) {
	    /* don't draw year line at end of chart */
                gr_line(xe, y1, xe, y2);
	        if (((chtptr->flags == 1) && (mo == 1)) || ((mo == 10) && 
		    (chtptr->flags == Y_FY))) {
	  	    gr_line(xe+1, y1, xe+1, y2);
	        }
            }
	}
        sdate = set_mdy(10, 1, yr);
        edate = set_mdy(10, 1, yr + 1);
    }
}

/***********************************************************************
 *
 * FUNCTION:
 *	xval()
 *
 * INPUTS:
 *	chtptr		(struct cht *)
 *	date		(utc_val)
 *	time_of_day 	(enum when)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *	sets the x value of the time_of_day
 */

int 
xval(struct cht *chtptr, utc_val date, enum when time_of_day)
{
    utc_val sx, ex, dx;			/* temp time values */

    sx = chtptr->start_date / (UTC_ONE_DAY / 2);
    ex = chtptr->end_date/ (UTC_ONE_DAY / 2);
    switch(time_of_day) {
    case START_OF_DAY:
	dx = date;
	break;
    case MIDDLE_OF_DAY:
	dx = date + UTC_ONE_DAY/2;
	break;
    case END_OF_DAY:
	dx = date + UTC_ONE_DAY;
	break;
    }
    dx /= (UTC_ONE_DAY / 2);
    if (dx < sx) return XVAL_EARLY;
    if (dx > ex) return XVAL_LATE;
    if (ex == sx) {
        return (((dx - sx) * (x_right_margin - x_time_offset)) / 1 + 
	    x_time_offset);
    } else {
        return (((dx - sx) * (x_right_margin - x_time_offset)) / (ex - sx)
            + x_time_offset); 
    }
}

/***********************************************************************
 *
 * FUNCTION:
 *	dsp_doy()
 *
 * INPUTS:
 *      doy          	(int)
 *	x		(int)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *     displays the doy value along the bottom of the chart 
 */

static void 
dsp_doy(int doy, int x)
{
    int txt_width, txt_height;		/* text width */
    char buf[8];			/* temp text buffer */
    int y, dy;				/* position of plot timeline */
    struct cht *chtptr;			/* temp object pointer */

    chtptr = objary[0].z.chtptr;
    txt_height = gr_txheight(chtptr->font|chtptr->point);
    dy = txt_height + 1;
    y = y_lines_end + dy;
    (void)sprintf(buf, "%03d", doy);
    gr_line(x, y, x, y - dy);
    txt_width = gr_txwidth(chtptr->font|chtptr->point);
    if ((x + txt_width <= x_right_margin) && (doy)) {
	gr_text(x + 1, y, buf, GR_LEFT, chtptr->font|chtptr->point, 0);
    }
}

/***********************************************************************
 *
 * FUNCTION:
 *      init_font()
 *
 * INPUTS:
 *      font_rsrc       (char *)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *      sets the font to its integer value from the character resource value
 */

void 
init_font(char *font_rsrc)
{
    int font;

    if (!strcmp(font_rsrc, "COURIER")) {
        font = GR_COURIER;
    } else if (!strcmp(font_rsrc, "COURIER_BOLD")) {
        font = GR_COURIER_BOLD;
    } else if (!strcmp(font_rsrc, "HELVETICA")) {
        font = GR_HELVETICA;
    } else if (!strcmp(font_rsrc, "HELVETICA_BOLD")) {
        font = GR_HELVETICA_BOLD;
    } else if (!strcmp(font_rsrc, "TIMES")) {
        font = GR_TIMES;
    } else if (!strcmp(font_rsrc, "TIMES_BOLD")) {
        font = GR_TIMES_BOLD;
    } else {
        Warning("Error in resource font - font set to TIMES");
        font = GR_TIMES;
    }
    RSRC_FONT = font;
}

/***********************************************************************
 *
 * FUNCTION:
 *      init_point()
 *
 * INPUTS:
 *      point_rsrc       (char *)
 *
 * OUTPUTS:
 *
 * RETURNS:
 *
 * EXTERNALLY READ:
 *
 * EXTERNALLY MODIFIED:
 *
 * DESCRIPTION:
 *      sets the point to its integer value from the character resource value
 */

void 
init_point(char *point_rsrc)
{
    int point;

    if (strcmp(point_rsrc, "8") == 0) {
        point = 8;
    } else if (strcmp(point_rsrc, "10") == 0) {
        point = 10;
    } else if (strcmp(point_rsrc, "12") == 0) {
        point = 12;
    } else if (strcmp(point_rsrc, "14") == 0) {
        point = 14;
    } else if (strcmp(point_rsrc, "18") == 0) {
        point = 18;
    } else if (strcmp(point_rsrc, "24") == 0) {
        point = 24;
    } else {
        Warning("Error in resource point = point set to 10");
        point = 10;
    }
    RSRC_POINT = point;
}

/***********************************************************************
 *
 * FUNCTION:
 *      verify_fun()
 *
 * INPUTS:
 *      w       (Widget)
 *      x, y    (XtPointer)
 *
 * OUTPUTS:
 *      none
 *
 * RETURNS:
 *      none
 *
 * EXTERNALLY READ:
 *      none
 *
 * EXTERNALLY MODIFIED:
 *      none
 *
 * DESCRIPTION:
 *      validates that the popup dialog can be closed
 */

static void
verify_fun(Widget w, XtPointer x, XtPointer y)
{

    if ((int)x == DIALOG_CANCEL) {
	if (!ShellValidateClose(w)) return;
	cancel_button();
    } else if ((int)x == DIALOG_UPDATE) {
	chart_ok_button();
    }
}

