/*
 * Copyright (C) 2013 Paul Kocialkowski
 *
 * 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 3 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, see <http://www.gnu.org/licenses/>.
 */

#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <linux/ioctl.h>
#include <linux/uinput.h>
#include <linux/input.h>

#include <hardware/sensors.h>
#include <hardware/hardware.h>

#define LOG_TAG "exynos_sensors"
#include <utils/Log.h>

#include "exynos_sensors.h"

struct lps331ap_data {
	char path_enable[PATH_MAX];
	char path_delay[PATH_MAX];
};

int lps331ap_init(struct exynos_sensors_handlers *handlers,
	struct exynos_sensors_device *device)
{
	struct lps331ap_data *data = NULL;
	char path[PATH_MAX] = { 0 };
	int input_fd = -1;
	int rc;

	LOGD("%s(%p, %p)", __func__, handlers, device);

	if (handlers == NULL)
		return -EINVAL;

	data = (struct lps331ap_data *) calloc(1, sizeof(struct lps331ap_data));

	input_fd = input_open("barometer_sensor");
	if (input_fd < 0) {
		LOGE("%s: Unable to open input", __func__);
		goto error;
	}

	rc = sysfs_path_prefix("barometer_sensor", (char *) &path);
	if (rc < 0 || path[0] == '\0') {
		LOGE("%s: Unable to open sysfs", __func__);
		goto error;
	}

	snprintf(data->path_enable, PATH_MAX, "%s/enable", path);
	snprintf(data->path_delay, PATH_MAX, "%s/poll_delay", path);

	handlers->poll_fd = input_fd;
	handlers->data = (void *) data;

	return 0;

error:
	if (data != NULL)
		free(data);

	if (input_fd >= 0)
		close(input_fd);

	handlers->poll_fd = -1;
	handlers->data = NULL;

	return -1;
}

int lps331ap_deinit(struct exynos_sensors_handlers *handlers)
{
	LOGD("%s(%p)", __func__, handlers);

	if (handlers == NULL)
		return -EINVAL;

	if (handlers->poll_fd >= 0)
		close(handlers->poll_fd);
	handlers->poll_fd = -1;

	if (handlers->data != NULL)
		free(handlers->data);
	handlers->data = NULL;

	return 0;
}


int lps331ap_activate(struct exynos_sensors_handlers *handlers)
{
	struct lps331ap_data *data;
	int rc;

	LOGD("%s(%p)", __func__, handlers);

	if (handlers == NULL || handlers->data == NULL)
		return -EINVAL;

	data = (struct lps331ap_data *) handlers->data;

	rc = sysfs_value_write(data->path_enable, 1);
	if (rc < 0) {
		LOGE("%s: Unable to write sysfs value", __func__);
		return -1;
	}

	handlers->activated = 1;

	return 0;
}

int lps331ap_deactivate(struct exynos_sensors_handlers *handlers)
{
	struct lps331ap_data *data;
	int rc;

	LOGD("%s(%p)", __func__, handlers);

	if (handlers == NULL || handlers->data == NULL)
		return -EINVAL;

	data = (struct lps331ap_data *) handlers->data;

	rc = sysfs_value_write(data->path_enable, 0);
	if (rc < 0) {
		LOGE("%s: Unable to write sysfs value", __func__);
		return -1;
	}

	handlers->activated = 1;

	return 0;
}

int lps331ap_set_delay(struct exynos_sensors_handlers *handlers, long int delay)
{
	struct lps331ap_data *data;
	int rc;

	LOGD("%s(%p, %ld)", __func__, handlers, delay);

	if (handlers == NULL || handlers->data == NULL)
		return -EINVAL;

	data = (struct lps331ap_data *) handlers->data;

	rc = sysfs_value_write(data->path_delay, (int) delay / 1000000);
	if (rc < 0) {
		LOGE("%s: Unable to write sysfs value", __func__);
		return -1;
	}

	return 0;
}

float lps331ap_convert(int value)
{
	return (float) value / 4096.0f;
}

int lps331ap_get_data(struct exynos_sensors_handlers *handlers,
	struct sensors_event_t *event)
{
	struct input_event input_event;
	int input_fd;
	int rc;

//	LOGD("%s(%p, %p)", __func__, handlers, event);

	if (handlers == NULL || event == NULL)
		return -EINVAL;

	input_fd = handlers->poll_fd;
	if (input_fd < 0)
		return -EINVAL;

	event->version = sizeof(struct sensors_event_t);
	event->sensor = handlers->handle;
	event->type = handlers->handle;

	do {
		rc = read(input_fd, &input_event, sizeof(input_event));
		if (rc < (int) sizeof(input_event))
			break;

		if (input_event.type == EV_REL) {
			if (input_event.code == REL_X)
				event->pressure = lps331ap_convert(input_event.value);
		} else if (input_event.type == EV_SYN) {
			if (input_event.code == SYN_REPORT)
				event->timestamp = input_timestamp(&input_event);
		}
	} while (input_event.type != EV_SYN);

	return 0;
}

struct exynos_sensors_handlers lps331ap = {
	.name = "LPS331AP",
	.handle = SENSOR_TYPE_PRESSURE,
	.init = lps331ap_init,
	.deinit = lps331ap_deinit,
	.activate = lps331ap_activate,
	.deactivate = lps331ap_deactivate,
	.set_delay = lps331ap_set_delay,
	.get_data = lps331ap_get_data,
	.activated = 0,
	.needed = 0,
	.poll_fd = -1,
	.data = NULL,
};