#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <getopt.h>
#include <string.h>
#include <time.h>
#include <math.h>
#include "sysfs.h"
#include "si.h"

struct si_wait_data {
	char		* d_object;
	char		* d_attr;

	double		d_secs;
	double		d_int;
};

static const double default_secs = 0.0;
static const double default_int = 1.0;

/**
 *	wait_init - Check arguments and allocate private data structures.
 *	@a:	Session data.
 */

static int wait_init(struct si_action * a)
{
	struct si_wait_data * data;
	double secs = default_secs;
	double interval = default_int;
	int error = 0;

	if (a->a_argc < 2 || a->a_argc > 4)
		return -EINVAL;

	data = calloc(1, sizeof(struct si_wait_data));
	if (!data)
		return -ENOMEM;

	switch (a->a_argc) {
	case 4:
		interval = strtod(a->a_argv[3], NULL);
	case 3:
		secs = strtod(a->a_argv[2], NULL);
	case 2:
		data->d_object = a->a_argv[0];
		data->d_attr = a->a_argv[1];
	}

	if (!error) {
		a->a_data = data;
		data->d_secs = secs;
		data->d_int = interval;
	} else
		free(data);
	return error;
}


static int wait_exec(struct si_action * a)
{
	struct si_wait_data * data = a->a_data;
	struct sysfs_object so;
	struct timespec req;
	char orig[PAGE_SIZE];
	char buffer[PAGE_SIZE];

	double interval = data->d_int;
	double nsecs;
	int error;

	error = sysfs_object_init(&so, data->d_object);
	if (error)
		return error;

	/* 
	 * Get Current Value
	 */
	error = sysfs_read_file(data->d_attr, orig);
	if (error < 0) {
		perror("read");
		goto Exit;
	} 
	error = 0;

	req.tv_sec = (time_t)floor(interval);
	nsecs = interval - floor(interval);
	req.tv_nsec = (unsigned long)(nsecs * 1000000000.0);

	if (data->d_secs > 0.0) {
		double remain;
		for (remain = data->d_secs; remain > 0.0; remain -= interval) {
			error = sysfs_read_file(data->d_attr, buffer);
			if (error < 0)
				goto Exit;
			error = 0;
			if (strcmp(orig, buffer))
				break;
			nanosleep(&req, NULL);
		}
	} else {
		do {
			error = sysfs_read_file(data->d_attr, buffer);
			if (error < 0)
				goto Exit;
			error = 0;
			if (strcmp(orig, buffer))
				break;
			nanosleep(&req, NULL);
		} while (1);
	}

 Exit:
	sysfs_object_exit(&so);
	return error;
}

static void wait_exit(struct si_action * a)
{
	struct si_wait_data * data = a->a_data;

	a->a_data = NULL;
	free(data);
}

static const char * wait_help = "Wait for attribute to change";
static const char * wait_usage = "<object> <attr> [ <seconds> [ <interval> ] ]";

decl_cmd(wait);

