#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <asm/ioctl.h>
//#include <linux/rtc.h>
#include <linux/android_alarm.h>

int alarm_main(int argc, char *argv[])
{
	int c;
    int res;
	struct tm tm;
	time_t t;
	struct timespec ts;
//	struct rtc_time rtc_time;
	char strbuf[26];
	int afd;
	int nfd;
//	struct timeval timeout = { 0, 0 };
    int wait = 0;
	fd_set rfds;
	const char wake_lock_id[] = "alarm_test"; 
	int waitalarmmask = 0;

    int useutc = 0;
	android_alarm_type_t alarmtype_low = ANDROID_ALARM_RTC_WAKEUP;
	android_alarm_type_t alarmtype_high = ANDROID_ALARM_RTC_WAKEUP;
	android_alarm_type_t alarmtype = 0;

    do {
        //c = getopt(argc, argv, "uw:");
        c = getopt(argc, argv, "uwat:");
        if (c == EOF)
            break;
        switch (c) {
        case 'u':
            useutc = 1;
            break;
		case 't':
			alarmtype_low = alarmtype_high = strtol(optarg, NULL, 0);
			break;
		case 'a':
			alarmtype_low = ANDROID_ALARM_RTC_WAKEUP;
			alarmtype_high = ANDROID_ALARM_TYPE_COUNT - 1;
			break;
        case 'w':
            //timeout.tv_sec = strtol(optarg, NULL, 0);
            wait = 1;
            break;
        case '?':
            fprintf(stderr, "%s: invalid option -%c\n",
                argv[0], optopt);
            exit(1);
        }
    } while (1);
    if(optind + 2 < argc) {
        fprintf(stderr,"%s [-uwa] [-t type] [seconds]\n", argv[0]);
        return 1;
    }

    afd = open("/dev/alarm", O_RDWR);
    if(afd < 0) {
        fprintf(stderr, "Unable to open rtc: %s\n", strerror(errno));
        return 1;
    }

    if(optind == argc) {
		for(alarmtype = alarmtype_low; alarmtype <= alarmtype_high; alarmtype++) {
			waitalarmmask |= 1U << alarmtype;
		}
#if 0
        res = ioctl(fd, RTC_ALM_READ, &tm);
        if(res < 0) {
            fprintf(stderr, "Unable to read alarm: %s\n", strerror(errno));
			return 1;
        }
#endif
#if 0
		t = timegm(&tm);
        if(useutc)
            gmtime_r(&t, &tm);
        else
            localtime_r(&t, &tm);
#endif
#if 0
        asctime_r(&tm, strbuf);
        printf("%s", strbuf);
#endif
    }
    else if(optind + 1 == argc) {
#if 0
        res = ioctl(fd, RTC_RD_TIME, &tm);
        if(res < 0) {
            fprintf(stderr, "Unable to set alarm: %s\n", strerror(errno));
			return 1;
        }
        asctime_r(&tm, strbuf);
        printf("Now: %s", strbuf);
        time(&tv.tv_sec);
#endif
#if 0
		time(&ts.tv_sec);
		ts.tv_nsec = 0;
		
        //strptime(argv[optind], NULL, &tm);
        //tv.tv_sec = mktime(&tm);
        //tv.tv_usec = 0;
#endif
		for(alarmtype = alarmtype_low; alarmtype <= alarmtype_high; alarmtype++) {
			waitalarmmask |= 1U << alarmtype;
		    res = ioctl(afd, ANDROID_ALARM_GET_TIME(alarmtype), &ts);
		    if(res < 0) {
		        fprintf(stderr, "Unable to get current time: %s\n", strerror(errno));
				return 1;
		    }
		    ts.tv_sec += strtol(argv[optind], NULL, 0);
		    //strtotimeval(argv[optind], &tv);
			gmtime_r(&ts.tv_sec, &tm);
		    printf("time %s -> %ld.%09ld\n", argv[optind], ts.tv_sec, ts.tv_nsec);
		    asctime_r(&tm, strbuf);
		    printf("Requested %s", strbuf);
			
		    res = ioctl(afd, ANDROID_ALARM_SET(alarmtype), &ts);
		    if(res < 0) {
		        fprintf(stderr, "Unable to set alarm: %s\n", strerror(errno));
				return 1;
		    }
		}
#if 0
        res = ioctl(fd, RTC_ALM_SET, &tm);
        if(res < 0) {
            fprintf(stderr, "Unable to set alarm: %s\n", strerror(errno));
			return 1;
        }
        res = ioctl(fd, RTC_AIE_ON);
        if(res < 0) {
            fprintf(stderr, "Unable to enable alarm: %s\n", strerror(errno));
			return 1;
        }
#endif
    }
    else {
        fprintf(stderr,"%s [-u] [date]\n", argv[0]);
        return 1;
    }

	if(wait) {
		while(waitalarmmask) {
			printf("wait for alarm %x\n", waitalarmmask);
			res = ioctl(afd, ANDROID_ALARM_WAIT);
			if(res < 0) {
				fprintf(stderr, "alarm wait failed\n");
			}
			printf("got alarm %x\n", res);
			waitalarmmask &= ~res;
			nfd = open("/sys/android_power/acquire_full_wake_lock", O_RDWR);
			write(nfd, wake_lock_id, sizeof(wake_lock_id) - 1);
			close(nfd);
			//sleep(5);
			nfd = open("/sys/android_power/release_wake_lock", O_RDWR);
			write(nfd, wake_lock_id, sizeof(wake_lock_id) - 1);
			close(nfd);
		}
		printf("done\n");
	}
#if 0	
	FD_ZERO(&rfds);
	FD_SET(fd, &rfds);
	res = select(fd + 1, &rfds, NULL, NULL, &timeout);
    if(res < 0) {
        fprintf(stderr, "select failed: %s\n", strerror(errno));
		return 1;
    }
	if(res > 0) {
		int event;
		read(fd, &event, sizeof(event));
		fprintf(stderr, "got %x\n", event);
	}
	else {
		fprintf(stderr, "timeout waiting for alarm\n");
	}
#endif

    close(afd);

    return 0;
}