#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>
#include "Rk_wake_lock.h"

struct rk_wake_lock {
	char *id;
};

#define TAG "WAKE_LOCK"

#define debug(fmt, args...) \
    printf(TAG "[%s] " fmt "\n", __func__, ##args)

enum {
	ACQUIRE_PARTIAL_WAKE_LOCK = 0,
	RELEASE_WAKE_LOCK,
	OUR_FD_COUNT
};

const char * const WAKE_LOCK_PATHS[] = {
	"/sys/power/wake_lock",
	"/sys/power/wake_unlock",
};

static int g_initialized = 0;
static int g_fds[2];
static int g_error = -1;

static int open_file_descriptors(const char * const paths[])
{
	for (int i = 0 ; i < 2; i++) {
		int fd = open(paths[i], O_RDWR | O_CLOEXEC);
		if (fd < 0) {
			g_error = -errno;
			debug("fatal error opening \"%s\": %s", paths[i],
				  strerror(errno));
			return -1;
		}
		g_fds[i] = fd;
	}

	g_error = 0;
	return 0;
}

static inline void initialize_fds(void) {
	if (g_initialized == 0) {
		open_file_descriptors(WAKE_LOCK_PATHS);
		g_initialized = 1;
	}
}

struct rk_wake_lock* RK_wake_lock_new(const char *id) {
	struct rk_wake_lock* lock;
	if (!id)
		return NULL;
	initialize_fds();

	lock = (struct rk_wake_lock*)malloc(sizeof(struct rk_wake_lock));
	lock->id = strdup(id);
	return lock;
}

void RK_wake_lock_delete(struct rk_wake_lock* lock) {
	if (lock && lock->id)
		free(lock->id);
	if (lock)
		free(lock);
}

int RK_acquire_wake_lock(struct rk_wake_lock *wake_lock) {
	char *id = wake_lock->id;
	debug("id=%s", id);

	if (g_error)
		return g_error;

	int fd;
	size_t len;
	ssize_t ret;

	fd = g_fds[0];

	ret = write(fd, id, strlen(id));
	if (ret < 0) {
		return -errno;
	}

	return ret;
}

int RK_release_wake_lock(struct rk_wake_lock *wake_lock) {
	char *id = wake_lock->id;
	int fd;

	debug("id=%s", id);

	if (g_error)
		return g_error;

	fd = g_fds[1];

	ssize_t len = write(fd, id, strlen(id));
	if (len < 0) {
		return -errno;
	}
	return len;
}

static int exec(const char *cmd, char *buf, const size_t size) {
	FILE *stream = NULL;
	char tmp[1024];

	if ((stream = popen(cmd,"r")) == NULL) {
		return -1;
	}

	if (buf == NULL) {
		pclose(stream);
		return -2;
	}

	buf[0] = '\0';
	while (fgets(tmp, sizeof(tmp) -1, stream)) {
		if (strlen(buf) + strlen(tmp) >= size) {
			pclose(stream);
			return -3;
		}
		strcat(buf, tmp);
	}
	pclose(stream);

	return 0;
}

int RK_wait_all_wake_lock_release(int timeout_ms) {
    int cnt = timeout_ms / 10;
	char result[1024];

	while(cnt--) {
		memset(result, 0, 1024);
        exec("cat /sys/power/wake_lock", result, 1024);
		if (strlen(result) <= 1) //换行符
			break;
        usleep(10*1000);
        printf("## suspend waiting wake_lock: %s\n", result);
	}
	if (cnt == 0) {
        printf("wait suspend timeout, abort suspend\n");
        printf("unreleased wake_lock: %s\n", result);
		return -1;
	}
	return 0;
}

