/*
 *
 *  	wmGrabImage-1.00 (C) 1999 Mike Henderson (mghenderson@lanl.gov)
 *
 *  		- Monitors an image on the WWW in a WindowMaker DockApp
 *
 *
 *
 *
 * 	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, 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 (see the file COPYING); if not, write to the
 * 	Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 *      Boston, MA  02111-1307, USA
 *
 *
 *	Platforms tested on: Linux, Solaris 2.6, IRIX 6.5
 *
 *
 *	ToDo:	Add inicator to show if image is uptodate or not
 *		Get rid of GrabImage and put all that stuff in wmGrabImage.c
 *		Center image in icon - this info should be in the returned Attributes struct.
 *		etc...
 *
 *		I am still not sure we are handling color resources properly... Seems to work OK on my 24-bit displays...
 *
 *
 *
 *
 *      Changes:
 *	Version 0.72  - May 27, 2001
 *			Fixed resource leak (XFreeColors)
 *
 *	Version 0.71  - May 24, 2001
 *			Added support for "zooming" the icon display
 *			on a region
 *
 *	Version 0.70  - March 28, 1999.
 *			Added support for local images (e.g. file:///home/mgh/junk.gif.)
 *
 *	Version 0.66  - February 23, 1999.
 *			Added help line for -delay option. And added a man page.
 *
 *	Version 0.65  - February 11, 1999.
 *                      Now starts netscape if not already running...
 *
 *	Version 0.64  - February 9, 1999.
 *                      Added command-line option for "Time between updates"
 *
 *	Version 0.63  - February 9, 1999.
 *			Fixed (potential) memory leak in the ShapeMask Pixmap
 *                      (gets returned only if color None is used in xpm file)
 *			Added XFreeColors call.
 *
 *	Version 0.62  - February 4, 1999.
 *			buf fixes. Added -c option to center vertically.
 *
 *
 *	Version 0.61  - February 2, 1999.
 *			Added Attributes support for Xpm Creation.
 *        		Also, added a kludge to GrabImage to stream edit
 * 			any "Transparent" colors that may get generated. (Change them
 *			to black.)
 *
 *	Version 0.6   - February 2, 1999.
 * 			Some bug fixes. Added Double click support.
 *			Now, DoubleClick's do the following:
 *
 *				Button1: display original size image via xv.
 *
 *				Button2: send another URL (specified with the -http
 *			        	 command line option) to netscape.
 *
 *				Button3: Force Update.
 *
 *
 *	Version 0.5   - initial (very) beta release February 1, 1999.
 *
 *
 */





/*
 *   Includes
 */
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <X11/X.h>
#include <X11/xpm.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "../wmgeneral/wmgeneral.h"
#include "wmGrabImage_master.xpm"
#include "wmGrabImage_mask.xbm"



/*
 *  Delay between refreshes (in microseconds)
 */
#define DELAY 10000L
#define WMGRABIMAGE_VERSION "0.72"





void ParseCMDLine(int argc, char *argv[]);
void pressEvent(XButtonEvent *xev);
void print_usage();


char 		ImageURL[1024], XpmFileName[256], ImageFileName[1024];
char		HttpURL[1024];
char		*ConvertGeometry= NULL;
int		UpToDate = 0;
int		ForceUpdate = 1;
int		ForceUpdate2 = 1;
int		GotFirstClick1, GotDoubleClick1;
int		GotFirstClick2, GotDoubleClick2;
int		GotFirstClick3, GotDoubleClick3;
int		DblClkDelay;
int		CenterImage = 0;
long int	UpdateDELAY = 600;





/*
 *   main
 */
int main(int argc, char *argv[]) {

struct tm	*gTime, *gmt;
struct stat	fi;
XEvent		event;
Pixmap		NewPixmap, NewShapeMask;
XpmAttributes	Attributes;
Colormap	cmap;
int		n, s, m, dt1, dt2, dt3, len;
int 		Year, Month, Day;
int		Hours, Mins, Secs;
int		i, j, Width, Height, yoff, fd, Flag;
long		CurrentLocalTime;
double		UT, hour24(), jd(), CurrentJD, OldFileUT, FileUT;
char		command[1040], ImageName[256];
int           havePixmap= 0;










    /*
     *  Parse any command line arguments.
     */
    ParseCMDLine(argc, argv);


    /*
     *  Figure out what the name of the image xpm file should be...
     */
    len = strlen(ImageURL);
    for (j = 0, i=0; i<len; ++i){ if (ImageURL[i] == '/') j = i; }
    strcpy(ImageName, ImageURL+j+1);
    sprintf(XpmFileName, "%s/.wmGrabImage/%s.xpm", getenv("HOME"), ImageName);
    sprintf(ImageFileName, "%s/.wmGrabImage/%s", getenv("HOME"), ImageName);


    openXwindow(argc, argv, wmGrabImage_master, wmGrabImage_mask_bits, wmGrabImage_mask_width, wmGrabImage_mask_height);

    cmap = DefaultColormap(display, DefaultScreen(display));



    /*
     *  Loop until we die
     */
    n = 32000;
    s = 32000;
    m = 32000;
    dt1 = 32000;
    dt2 = 32000;
    dt3 = 32000;
    DblClkDelay = 32000;
    UpToDate = 0;
    FileUT = -999.0;
    Flag = 1;
    NewShapeMask = 0;
    Attributes.nalloc_pixels = 0;
    while(1) {




	/*
	 *  Keep track of # of seconds
	 */
	if (m > 100){

	    m = 0;
	    ++dt1;
	    ++dt2;
	    ++dt3;

	} else {

	    /*
	     *  Increment counter
	     */
	    ++m;

	}






	/*
	 *  Double Click Delays
	 *  Keep track of click events. If Delay too long, set GotFirstClick's to False.
	 */
	if (DblClkDelay > 15) {

	    DblClkDelay = 0;
	    GotFirstClick1 = 0; GotDoubleClick1 = 0;
	    GotFirstClick2 = 0; GotDoubleClick2 = 0;
	    GotFirstClick3 = 0; GotDoubleClick3 = 0;

	} else {

	    ++DblClkDelay;

	}














	/*
	 *   Process any pending X events.
	 */
        while(XPending(display)){
            XNextEvent(display, &event);
            switch(event.type){
                case Expose:
                        RedrawWindow();
                        break;
                case ButtonPress:
                        pressEvent(&event.xbutton);
                        break;
                case ButtonRelease:
                        break;
            }
        }












	/*
	 *  Draw window.
	 */
	if (ForceUpdate||Flag){



            /*
             *  Compute Current Julian Date
             */
            CurrentLocalTime = time(CurrentTime);
            gTime = gmtime(&CurrentLocalTime);
            Year  = gTime->tm_year+1900;
            Month = gTime->tm_mon+1;
            Day   = gTime->tm_mday;
            Hours = gTime->tm_hour;
            Mins  = gTime->tm_min;
            Secs  = gTime->tm_sec;
            UT = (double)Hours + (double)Mins/60.0 + (double)Secs/3600.0;
            CurrentJD = jd(Year, Month, Day, UT);


	    /*
	     * Clear window.
	     */
	    copyXPMArea(5, 69, 54, 54, 5, 5);



	    if (havePixmap) {
	      /*
	       * free up the colors, if we alloc'd some before
	       */
	      if (Attributes.nalloc_pixels > 0)
		XFreeColors(display, cmap,  Attributes.alloc_pixels,
			    Attributes.nalloc_pixels, 0);
		/*
		 *  Free last pixmap -- we dont need it anymore...
		 *  A ShapeMask is returned if the Pixmap had the color None used.
		 *  We could probably change Transparent to None to make use of this, but for now,
		 *  lets just ignore it...
		 */
		if ( NewShapeMask != 0 )
		  XFreePixmap(display, NewShapeMask);
		XFreePixmap(display, NewPixmap);

		XpmFreeAttributes(&Attributes);

		havePixmap= 0;
	    }
	    /*
	     *   Grab new pixmap. Accept a reasonable color match.
	     */
	    Attributes.valuemask   = XpmExactColors | XpmCloseness | XpmReturnAllocPixels;
	    Attributes.exactColors = 0;
	    Attributes.closeness   = 40000;
	    if (XpmReadFileToPixmap(display, Root, XpmFileName, &NewPixmap, &NewShapeMask, &Attributes) >= 0){



		Height = Attributes.height;
		Width  = Attributes.width;
		yoff   = (CenterImage) ? (54 - Height)/2 : 0;
	        XCopyArea(display, NewPixmap, wmgen.pixmap, NormalGC, 0, 0, Width, Height, 5, 5+yoff);


		Flag = 0;
		ForceUpdate = 0;
		havePixmap= 1;
	    }






	    /*
	     * Make changes visible
	     */
	    RedrawWindow();



	}





	/*
	 *  Check xpm file status
	 */
	if (dt2 > 1){

	    dt2 = 0;

	    if ( (fd = open(XpmFileName, O_RDONLY)) >= 0 ) {

		fstat(fd, &fi);
		close(fd);
		gmt = gmtime(&fi.st_mtime);
		OldFileUT = FileUT;
		FileUT = (double)gmt->tm_hour + (double)gmt->tm_min/60.0 + (double)gmt->tm_sec/3600.0;
		if (FileUT != OldFileUT) ForceUpdate = 1;

	    }


	}









	/*
	 *  Check every 5 min if the values are not up to date...
	 */

	if (ForceUpdate2||(dt3 > UpdateDELAY)){

	    dt3 = 0;

	    /*
	     *  Execute Perl script to grab the Latest METAR Report
	     */
	    if (ConvertGeometry != NULL)
	      sprintf(command, "GrabImage %s %s &", ImageURL, ConvertGeometry);
	    else
	      sprintf(command, "GrabImage %s &", ImageURL);
	    system(command);

	    ForceUpdate = 1;
	    ForceUpdate2 = 0;

	}





	/*
	 *  Wait for next update
	 */
	usleep(DELAY);


     }



}



/*
 *   ParseCMDLine()
 */
void ParseCMDLine(int argc, char *argv[]) {

    int  i;

    ImageURL[0] = '\0';
    for (i = 1; i < argc; i++) {

        if (!strcmp(argv[i], "-display")){

            ++i;

        } else if ((!strcmp(argv[i], "-url"))||(!strcmp(argv[i], "-u"))){

            strcpy(ImageURL, argv[++i]);

        } else if (!strcmp(argv[i], "-delay")){

            UpdateDELAY = atol(argv[++i]);
	    if (UpdateDELAY < 10){
		printf("Try a longer delay\n");
		exit(-1);
	    }

        } else if (!strcmp(argv[i], "-http")){

            strcpy(HttpURL, argv[++i]);

        } else if (!strcmp(argv[i], "-geom")){

            ConvertGeometry= argv[++i];

        } else if (!strcmp(argv[i], "-c")){

            CenterImage = 1;


        } else {
	    print_usage();
            exit(1);
        }
    }
    if (ImageURL[0] == '\0'){
	fprintf(stderr, "You must specify an Image URL\n");
	print_usage();
	exit(-1);
    }

}


void print_usage(){

    printf("\nwmGrabImage version: %s\n", WMGRABIMAGE_VERSION);
    printf("\nusage: wmGrabImage -u <ImageURL> -http <httpURL> -display <Display>] [-h]\n");
    printf("\t\t[-geom <CroppingGeometry>\n\n");
    printf("\t-display <Display>\tUse alternate X display.\n");
    printf("\t-h\t\t\tDisplay help screen.\n");
    printf("\t-url <ImageURL>\t\tThe URL of image to display.\n\n");
    printf("\t-delay <Time>\t\tSet time (in seconds) between updates.\n\n");
    printf("\t-http <httpURL>\t\tThe URL of the WWW page to send to\n\t\t\t\tnetscape with Button2 double click.\n\n");
    printf("\t-c          \tCenter the image vertically in the icon.\n\n");
    printf("\t-geom <CropGeometry>\tThe geometry to pass to convert\n");
    printf("\t\t\t\twhen scaling the image..\n\n");
}




/*
 *  Compute the Julian Day number for the given date.
 *  Julian Date is the number of days since noon of Jan 1 4713 B.C.
 */
double jd(ny, nm, nd, UT)
int ny, nm, nd;
double UT;
{
        double A, B, C, D, JD, day;

        day = nd + UT/24.0;


        if ((nm == 1) || (nm == 2)){
                ny = ny - 1;
                nm = nm + 12;
        }

        if (((double)ny+nm/12.0+day/365.25)>=(1582.0+10.0/12.0+15.0/365.25)){
                        A = ((int)(ny / 100.0));
                        B = 2.0 - A + (int)(A/4.0);
        }
        else{
                        B = 0.0;
        }
        if (ny < 0.0){
                C = (int)((365.25*(double)ny) - 0.75);
        }
        else{
                C = (int)(365.25*(double)ny);
        }

        D = (int)(30.6001*(double)(nm+1));


        JD = B + C + D + day + 1720994.5;
        return(JD);

}



/*
 *  This routine handles button presses.
 *
 *   Double click on
 *		Mouse Button 1: Display full size image with xv.
 *		Mouse Button 2: Send HttpURL to netscape.
 *		Mouse Button 3: Update image right away (i.e. grab a new one).
 *
 *
 */
void pressEvent(XButtonEvent *xev){

    char Command[512];

/*
   ForceUpdate = 1;
*/

    DblClkDelay = 0;
    if ((xev->button == Button1) && (xev->type == ButtonPress)){
	if (GotFirstClick1) GotDoubleClick1 = 1;
	else GotFirstClick1 = 1;
    } else if ((xev->button == Button2) && (xev->type == ButtonPress)){
	if (GotFirstClick2) GotDoubleClick2 = 1;
	else GotFirstClick2 = 1;
    } else if ((xev->button == Button3) && (xev->type == ButtonPress)){
	if (GotFirstClick3) GotDoubleClick3 = 1;
	else GotFirstClick3 = 1;
    }


    /*
     *  We got a double click on Mouse Button1 (i.e. the left one)
     */
    if (GotDoubleClick1) {
	GotFirstClick1 = 0;
	GotDoubleClick1 = 0;
	sprintf(Command, "xv %s &", ImageFileName);
	system(Command);
    }


    /*
     *  We got a double click on Mouse Button2 (i.e. the left one)
     */
    if (GotDoubleClick2) {
	GotFirstClick2 = 0;
	GotDoubleClick2 = 0;
	sprintf(Command, "netscape -remote 'openURL(%s)' || netscape '%s' &", HttpURL, HttpURL);
	system(Command);
    }


    /*
     *  We got a double click on Mouse Button3 (i.e. the left one)
     */
    if (GotDoubleClick3) {
	GotFirstClick3 = 0;
	GotDoubleClick3 = 0;
	ForceUpdate2 = 1;
    }



   return;

}