/* common.h -- Common header file for Redshift source files
   This file is part of Redshift.

   Redshift 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.

   Redshift 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 Redshift.  If not, see <http://www.gnu.org/licenses/>.

   Copyright (c) 2009-2017               Jon Lund Steffensen <jonlst@gmail.com>
   Copyright (c) 2014, 2015, 2016, 2025  Mattias Andrée <m@maandree.se>
*/
#ifndef REDSHIFT_COMMON_H
#define REDSHIFT_COMMON_H

#ifndef WINDOWS
# if defined(__WIN32__) || defined(_WIN32)
#  define WINDOWS
# endif
#endif

#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <locale.h>
#include <math.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#ifdef _POSIX_TIMERS
# include <sys/time.h>
#endif
#ifdef WINDOWS
# include <windows.h>
#else
# include <pwd.h>
# include <signal.h>
# include <time.h>
#endif

#include <libred.h>

#ifdef ENABLE_NLS
# include <libintl.h>
#else
# define gettext(s) (s)
#endif
# define _(s) gettext(s)
# define N_(s) (s)


/* The color temperature when no adjustment is applied. */
#define NEUTRAL_TEMP  6500


enum period {
	PERIOD_NONE = 0,
	PERIOD_DAYTIME,
	PERIOD_NIGHT,
	PERIOD_TRANSITION
} ;

enum program_mode {
	PROGRAM_MODE_CONTINUAL,
	PROGRAM_MODE_ONE_SHOT,
	PROGRAM_MODE_PRINT,
	PROGRAM_MODE_RESET,
	PROGRAM_MODE_MANUAL
};

struct location {
	float lat, lon;
};

struct color_setting {
	int temperature;
	float gamma[3];
	float brightness;
};

/* Time range.
   Fields are offsets from midnight in seconds. */
struct time_range {
	int start;
	int end;
};

/* Transition scheme.
   The solar elevations at which the transition begins/ends,
   and the association color settings. */
struct transition_scheme {
	double high;
	double low;
	int use_time; /* When enabled, ignore elevation and use time ranges. */
	struct time_range dawn;
	struct time_range dusk;
	struct color_setting day;
	struct color_setting night;
};

struct config_ini_setting {
	struct config_ini_setting *next;
	char *name;
	char *value;
};

struct config_ini_section {
	struct config_ini_section *next;
	char *name;
	struct config_ini_setting *settings;
};

struct config_ini_state {
	struct config_ini_section *sections;
};


struct options {
	/* Path to config file */
	char *config_filepath;

	struct transition_scheme scheme;
	enum program_mode mode;
	int verbose;

	/* Temperature to set in manual mode. */
	int temp_set;
	/* Whether to fade between large skips in color temperature. */
	int use_fade;
	/* Whether to preserve gamma ramps if supported by gamma method. */
	int preserve_gamma;

	/* Selected gamma method. */
	const struct gamma_method *method;
	/* Arguments for gamma method. */
	char *method_args;

	/* Selected location provider. */
	const struct location_provider *provider;
	/* Arguments for location provider. */
	char *provider_args;
};


/* Gamma adjustment method */
typedef struct gamma_state GAMMA_STATE;

struct gamma_method {
	char *name;

	/* If true, this method will be tried if none is explicitly chosen. */
	int autostart;

	/* Initialize state. Options can be set between init and start. */
	int (*init)(GAMMA_STATE **state);
	/* Allocate storage and make connections that depend on options. */
	int (*start)(GAMMA_STATE *state, enum program_mode mode);
	/* Free all allocated storage and close connections. */
	void (*free)(GAMMA_STATE *state);

	/* Print help on options for this adjustment method. */
	void (*print_help)(FILE *f);
	/* Set an option key, value-pair */
	int (*set_option)(GAMMA_STATE *state, const char *key, const char *value);

	/* Restore the adjustment to the state before start was called. */
	void (*restore)(GAMMA_STATE *state);
	/* Set a specific color temperature. */
	int (*set_temperature)(GAMMA_STATE *state, const struct color_setting *setting, int preserve);
};


/* Location provider */
typedef struct location_state LOCATION_STATE;

struct location_provider {
	char *name;

	/* Initialize state. Options can be set between init and start. */
	int (*init)(LOCATION_STATE **state);
	/* Allocate storage and make connections that depend on options. */
	int (*start)(LOCATION_STATE *state);
	/* Free all allocated storage and close connections. */
	void (*free)(LOCATION_STATE *state);

	/* Print help on options for this location provider. */
	void (*print_help)(FILE *f);
	/* Set an option key, value-pair. */
	int (*set_option)(LOCATION_STATE *state, const char *key, const char *value);

	/* Listen and handle location updates. */
	int (*get_fd)(LOCATION_STATE *state);
	int (*handle)(LOCATION_STATE *state, struct location *location, int *available);
};


#define LIST_RAMPS_STOP_VALUE_TYPES(X, D)\
	X(u8, uint8_t, UINT8_MAX + 1ULL, UINT8_MAX, 8) D\
	X(u16, uint16_t, UINT16_MAX + 1ULL, UINT16_MAX, 16) D\
	X(u32, uint32_t, UINT32_MAX + 1ULL, UINT32_MAX, 32) D\
	X(u64, uint64_t, UINT64_MAX, UINT64_MAX, 64) D\
	X(float, float, 1, 1, -1) D\
	X(double, double, 1, 1, -2)

#define X(SUFFIX, TYPE, MAX, TRUE_MAX, DEPTH)\
	void colorramp_fill_##SUFFIX(TYPE *gamma_r, TYPE *gamma_g, TYPE *gamma_b,\
	                             size_t size_r, size_t size_g, size_t size_b,\
	                             const struct color_setting *setting)
LIST_RAMPS_STOP_VALUE_TYPES(X, ;);
#undef X


int config_ini_init(struct config_ini_state *state, const char *filepath);
void config_ini_free(struct config_ini_state *state);
struct config_ini_section *config_ini_get_section(struct config_ini_state *state, const char *name);


void options_init(struct options *options);
void options_parse_args(
	struct options *options, int argc, char *argv[],
	const struct gamma_method *gamma_methods,
	const struct location_provider *location_providers);
void options_parse_config_file(
	struct options *options, struct config_ini_state *config_state,
	const struct gamma_method *gamma_methods,
	const struct location_provider *location_providers);
void options_set_defaults(struct options *options);


void hooks_signal_period_change(enum period prev_period, enum period period);


int pipeutils_create_nonblocking(int pipefds[2]);

void pipeutils_signal(int write_fd);
void pipeutils_handle_signal(int read_fd);


#ifdef WINDOWS
extern int exiting;
extern int disable;
#else
extern volatile sig_atomic_t exiting;
extern volatile sig_atomic_t disable;
#endif

int signals_install_handlers(void);


int systemtime_get_time(double *now);
void systemtime_msleep(unsigned int msecs);


extern const struct gamma_method dummy_gamma_method;

#ifdef ENABLE_COOPGAMMA
extern const struct gamma_method coopgamma_gamma_method;
#endif

#ifdef ENABLE_RANDR
extern const struct gamma_method randr_gamma_method;
#endif

#ifdef ENABLE_VIDMODE
extern const struct gamma_method vidmode_gamma_method;
#endif

#ifdef ENABLE_DRM
extern const struct gamma_method drm_gamma_method;
#endif

#ifdef ENABLE_QUARTZ
extern const struct gamma_method quartz_gamma_method;
#endif

#ifdef ENABLE_W32GDI
extern const struct gamma_method w32gdi_gamma_method;
#endif


extern const struct location_provider manual_location_provider;

#ifdef ENABLE_GEOCLUE2
extern const struct location_provider geoclue2_location_provider;
#endif

#ifdef ENABLE_CORELOCATION
extern const struct location_provider corelocation_location_provider;
#endif


#endif