
/*  Timestamp.c: the timestamp widget 
 *
 *  This file is part of Aileron, a WINGs email client. 
 *
 *  Copyright (c) 1999 Michael J. Mitchell (mitch@gw2.redback.com.au)
 *  Modified for Aileron.
 *
 *  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 "Aileron.h"

/* yes... but this is a widget, and it's only included here */
#include <WINGs/WINGsP.h>


typedef	struct	_XpmIcon
{
    Pixmap pixmap;
    Pixmap mask;
    XpmAttributes attributes;
} XpmIcon;

// Define the widget class. These two fields are mandatory.
typedef	struct	W_TimeStamp
{
    W_Class			widgetClass;
    WMView			*view;
 
    // Painting.
	W_Pixmap		*image;
	XpmIcon			*result;

	XpmIcon			asclock;
	XpmIcon			led;
	XpmIcon			month;
	XpmIcon			date;
	XpmIcon			weekday;
	XpmIcon			asvisible;					// For ASClock.

	GC				gc;
	time_t			time;

	unsigned short	redraw;
} TimeStamp;

// XPMs from ASClock.
#include "images/timestamp/clk.xpm"
#include "images/timestamp/led.xpm"
#include "images/timestamp/month.xpm"
#include "images/timestamp/date.xpm"
#include "images/timestamp/weekday.xpm"

// LED positions.
static	int		twfour[5]  = { 4,  8, 17, 22, 31 };

// no shape
static	int		ns_posx[11] = { 5, 5, 5, 5, 5, 45, 21, 21, 26, 31, 19 };
static	int		ns_posy[4]  = { 7, 25, 34, 49 };

static	int		posx[11];
static	int		posy[4];

char		*LedColor = "LightSeaGreen";


// Widget class ID.
static	W_Class	timeStampWidgetClass = 0;

// Class initializer. Must be called before creating any instances of the
// widget.
W_Class InitTimeStamp(WMScreen *scr)
{
    // Register the widget with WINGs and get the widget class ID.
    if (!(timeStampWidgetClass))
	{
		timeStampWidgetClass =
			W_RegisterUserWidget(); 
	}
    return timeStampWidgetClass;
}

static int getXPM(TimeStamp *timestamp)
{
	Display			*dpy = timestamp->view->screen->display;
	Colormap		cmap;
	XColor			col;
	char			led1[36];
	char			led2[36];
	int				ret;

	// ASClock...
	cmap = DefaultColormap(dpy, DefaultScreen(dpy));

	if (!(XParseColor(dpy, cmap, LedColor, &col))) { return -1; }

	sprintf(led1, ".      c #%4X%4X%4X", col.red, col.green, col.blue);
	for(ret = 10; ret < 22; ret++)
    	{ if ((led1[ret] == ' ')) { led1[ret] = '0'; } }
	led_xpm[2] = led1;

	col.red   = (col.red / 10) * 3;
	col.green = (col.green / 10) * 3;
	col.blue  = (col.blue / 10) * 3;
	sprintf(led2, "X      c #%4X%4X%4X", col.red, col.green, col.blue);

	for(ret = 10; ret < 22; ret++)
    	{ if ((led2[ret] == ' ')) { led2[ret] = '0'; } }
	led_xpm[3] = led2;

	timestamp->asclock.attributes.valuemask =
		(XpmReturnPixels | XpmReturnExtensions | XpmSize);
	if (XpmCreatePixmapFromData(dpy,
			DefaultRootWindow(dpy),
			clk_xpm,
			&timestamp->asclock.pixmap, &timestamp->asclock.mask,
			&timestamp->asclock.attributes) != XpmSuccess)
    	{ return -1; }

	timestamp->asvisible.attributes.valuemask =
		(XpmReturnPixels | XpmReturnExtensions | XpmSize);
	if (XpmCreatePixmapFromData(dpy,
			DefaultRootWindow(dpy),
			clk_xpm,
			&timestamp->asvisible.pixmap, &timestamp->asvisible.mask,
			&timestamp->asvisible.attributes) != XpmSuccess)
		{ return -1; }

	timestamp->led.attributes.valuemask =
		(XpmReturnPixels | XpmReturnExtensions | XpmSize);
	if (XpmCreatePixmapFromData(dpy,
			DefaultRootWindow(dpy),
			led_xpm,
			&timestamp->led.pixmap, &timestamp->led.mask,
			&timestamp->led.attributes) != XpmSuccess)
		{ return -1; }

	timestamp->month.attributes.valuemask =
		(XpmReturnPixels | XpmReturnExtensions | XpmSize);
	if (XpmCreatePixmapFromData(dpy,
			DefaultRootWindow(dpy),
			month_xpm,
			&timestamp->month.pixmap, &timestamp->month.mask,
			&timestamp->month.attributes) != XpmSuccess)
		{ return -1; }

	timestamp->date.attributes.valuemask =
		(XpmReturnPixels | XpmReturnExtensions | XpmSize);
	if (XpmCreatePixmapFromData(dpy,
			DefaultRootWindow(dpy),
			date_xpm,
			&timestamp->date.pixmap, &timestamp->date.mask,
			&timestamp->date.attributes) != XpmSuccess)
		{ return -1; }

	timestamp->weekday.attributes.valuemask =
		(XpmReturnPixels | XpmReturnExtensions | XpmSize);
	if (XpmCreatePixmapFromData(dpy,
			DefaultRootWindow(dpy),
			weekday_xpm,
			&timestamp->weekday.pixmap, &timestamp->weekday.mask,
			&timestamp->weekday.attributes) != XpmSuccess)
		{ return -1; }

	return 0;
}


static void render(TimeStamp *timestamp)
{
	Display		*dpy = timestamp->view->screen->display;
	struct tm 	*clk;
	int			thishour;

	timestamp->result = &timestamp->asvisible;

	clk = localtime(&timestamp->time);

	XCopyArea(dpy,
		timestamp->asclock.pixmap,
		timestamp->asvisible.pixmap,
		timestamp->gc,
	    0, 0, 64, 64, 0, 0);

	thishour = clk->tm_hour % 12;
	if (!thishour)
		thishour = 12; 

	if (clk->tm_hour >= 12) { // PM
		XCopyArea(dpy,
			timestamp->led.pixmap,			// src
			timestamp->asvisible.pixmap,	// dest
			timestamp->gc,					// use GC
			107, 5, 						// src_x, src_y
			11, 6,							// width, height
			posx[5], posy[0] + 5);			// dest_x, dest_y
    } else { // AM
		XCopyArea(dpy,
			timestamp->led.pixmap,
			timestamp->asvisible.pixmap,
			timestamp->gc,
			94, 5, 12, 6, posx[5], posy[0] + 5);
	}
  
	if (thishour > 9) {
		XCopyArea(dpy,
			timestamp->led.pixmap,
			timestamp->asvisible.pixmap,
			timestamp->gc,
			13, 0, 5, 11, posx[0], posy[0]);
	}

	XCopyArea(dpy,
		timestamp->led.pixmap,
		timestamp->asvisible.pixmap,
		timestamp->gc,
	    9 * (thishour % 10), 0, 9, 11, posx[1], posy[0]);
  
	// Minute, drawn first, so am/pm won't be overwritten.
	XCopyArea(dpy,
		timestamp->led.pixmap,
		timestamp->asvisible.pixmap,
		timestamp->gc,
	    9 * (clk->tm_min / 10), 0, 9, 11, posx[3], posy[0]);

	XCopyArea(dpy,
		timestamp->led.pixmap,
		timestamp->asvisible.pixmap,
		timestamp->gc,
	    9 * (clk->tm_min % 10), 0, 9, 11, posx[4], posy[0]);

	// Month.
	XCopyArea(dpy,
		timestamp->month.pixmap,
		timestamp->asvisible.pixmap,
		timestamp->gc,
		0, 6 * (clk->tm_mon), 22, 6, posx[10], posy[3]);

	// Date.
	if ((clk->tm_mday > 9))
	{
		XCopyArea(dpy,
			timestamp->date.pixmap,
			timestamp->asvisible.pixmap,
			timestamp->gc,
			9 * ((clk->tm_mday / 10 + 9) % 10), 0, 9, 13, posx[7], posy[2]);

		XCopyArea(dpy,
			timestamp->date.pixmap,
			timestamp->asvisible.pixmap,
			timestamp->gc,
			9 * ((clk->tm_mday % 10 + 9) % 10), 0, 9, 13,
			posx[9], posy[2]);      
	}
	else
	{
		XCopyArea(dpy,
			timestamp->date.pixmap,
			timestamp->asvisible.pixmap,
			timestamp->gc,
			9 * (clk->tm_mday - 1), 0, 9, 13, posx[8], posy[2]);
	}
    
	// WeekDays.
	XCopyArea(dpy,
		timestamp->weekday.pixmap,
		timestamp->asvisible.pixmap,
		timestamp->gc,
		0, 6 * ((clk->tm_wday + 6) % 7), 21, 7, posx[6], posy[1]); 

	XCopyArea(dpy,
		timestamp->led.pixmap,
		timestamp->asvisible.pixmap,
		timestamp->gc,
		90, 0, 3, 11, posx[2], posy[0]);
}


static void paintTimeStamp(TimeStamp *timestamp)
{
	Display		*dpy = timestamp->view->screen->display;
    W_Screen	*scr = timestamp->view->screen;

    if (!timestamp->view->flags.realized)
		return; 

	if (timestamp->redraw) {
		render(timestamp);

		if (!(timestamp->image = WMCreatePixmapFromXPixmaps(scr,
				timestamp->result->pixmap, timestamp->result->mask,
				64, 64,
				DefaultDepth(dpy, DefaultScreen(dpy)))))
			{ wfatal("Unable to Create Clock Image"); }
	}

    if (timestamp->image) {
		W_PaintTextAndImage(timestamp->view,
			False,
			timestamp->gc,
			scr->normalFont,
			WRFlat,
			NULL, WACenter,
			timestamp->image, WIPImageOnly,
			timestamp->gc,
			0);
    }
	timestamp->redraw = 0;

}


// this breaks!
static void destroyTimeStamp(TimeStamp *timestamp)
{
    return;
	if ((timestamp->asclock.pixmap))
		{ XpmFree((void *) timestamp->asclock.pixmap); }
	if ((timestamp->asclock.mask)) 
		{ XpmFree((void *) timestamp->asclock.mask); }
	if ((timestamp->led.pixmap))
		{ XpmFree((void *) timestamp->led.pixmap); }
	if ((timestamp->led.mask))
		{ XpmFree((void *) timestamp->led.mask); }
	if ((timestamp->month.pixmap))
		{ XpmFree((void *) timestamp->month.pixmap); }
	if ((timestamp->month.mask))
		{ XpmFree((void *) timestamp->month.mask); }
	if ((timestamp->date.pixmap))
		{ XpmFree((void *) timestamp->date.pixmap); }
	if ((timestamp->date.mask))
		{ XpmFree((void *) timestamp->date.mask); }
	if ((timestamp->weekday.pixmap))
		{ XpmFree((void *) timestamp->weekday.pixmap); }
	if ((timestamp->weekday.mask))
		{ XpmFree((void *) timestamp->weekday.mask); }
	if ((timestamp->asvisible.pixmap))
		{ XpmFree((void *) timestamp->asvisible.pixmap); }
	if ((timestamp->asvisible.mask))
		{ XpmFree((void *) timestamp->asvisible.mask); }

	if ((timestamp->image))
		{ WMReleasePixmap(timestamp->image); }
    free((void *) timestamp);
}

static void handleEvents(XEvent *event, void *data)
{
    TimeStamp	*timestamp = (TimeStamp *) data;

    switch (event->type) {	

		case Expose:
			if (event->xexpose.count)
				break; 
			if (timestamp->view->flags.realized)
				paintTimeStamp(timestamp); 
			break;
		
        case ButtonPress:
            RunPrefsPanel();
            break;

		case DestroyNotify:
			destroyTimeStamp(timestamp);
			break;
    }
}


// Create.
void *CreateTimeStamp(WMWidget *parent)
{
    W_Screen	*scr;
    TimeStamp	*timestamp;
	int i;

    timestamp = wmalloc(sizeof(TimeStamp));
    memset(timestamp, 0, sizeof(TimeStamp));
    timestamp->widgetClass = timeStampWidgetClass;
    
    if (!(timestamp->view = W_CreateView(W_VIEW(parent)))) {
		free((void *) timestamp);
		return NULL;
    }
    timestamp->view->self = timestamp;

    scr = (W_VIEW(parent))->screen;
    //scr = timestamp->view->screen;

    // Create event handler.
    WMCreateEventHandler(timestamp->view,
		ExposureMask | StructureNotifyMask | ButtonPressMask|
		ButtonReleaseMask| EnterWindowMask|LeaveWindowMask,
		handleEvents,
		timestamp);

	// Default GC for paint.
	timestamp->gc = WMColorGC(scr->gray);


	W_ResizeView(timestamp->view, 64, 64);

	for (i = 0; i < 11; i++) { 
		if(i<4) 
			posy[i] = ns_posy[i]; 
		
		posx[i] = ns_posx[i] + (i<5 ? twfour[i] : 0); 

	}

	// Create XPMs.
	if ((getXPM(timestamp) == -1))
		{ wfatal("Unable to initialize Clock Pixmaps"); }

	timestamp->redraw = 1;
	timestamp->result = &timestamp->asvisible;
    return (void *)timestamp;
}

// Handle exposures.


void SetTimeStampWithTimeT(void *vtimestamp, time_t time)
{
	TimeStamp *timestamp = (TimeStamp *)vtimestamp;
    CHECK_CLASS(timestamp, timeStampWidgetClass);

	timestamp->time = time;
	timestamp->redraw = 1;

    if (timestamp->view->flags.realized)
		paintTimeStamp(timestamp); 
}

void SetTimeStampWithTimeTM(void *vtimestamp, struct tm *time)
{
	TimeStamp *timestamp = (TimeStamp *)vtimestamp;
    CHECK_CLASS(timestamp, timeStampWidgetClass);

	timestamp->time = mktime(time);
	timestamp->redraw = 1;

    if (timestamp->view->flags.realized)
		paintTimeStamp(timestamp); 
}




