#ifndef POWERSAVE_POWERLIB_H
#define POWERSAVE_POWERLIB_H

#ifdef __cplusplus
extern "C" {
#endif

#include <stdio.h>
#include <syslog.h>
#include <stdint.h>

#define MAX_FILE_PATH 512 /* XXX: HOpe this is only under /proc/acpi where this is correct. */
#define MAX_LINE_SIZE 1024

#define MAX_BATTERIES 4
  /* Max string length in ACPI Source Language: 200 bytes */
#define MAX_BAT_CHAR_LEN 200

#define MAX_THERMAL_ACTIVE 10

#define NO_ACPI_ERROR -20
#define NO_MODULE_ERROR -10
#define NO_DEVICE_ERROR -5

#define MAX_SUPPORTED_CPUS 32

	/****        BATTERY STATES AND STRUCTURES   ****/
	/* this is conform to the ACPI specification 2.0b (2002)*/

	/*be careful to test every variable on unknown*/
#define UNKNOWN -1

	enum BATTERY_PRESENT{PRESENT_YES = 0, PRESENT_NO};
	enum CAPACITY_UNIT{WATT_H = 0, AMP};
	enum BATTERY_TECH{TECH_NON_RECHARGEABLE = 0, TECH_RECHARGEABLE};
	
	/* because of kernel implementations separated in ACPI spec this is combined to battery_state*/
	/* be careful this is kernel definition of batteries states !*/
	enum CAPACITY_STATE{STATE_OK, STATE_CRIT, STATE_LOW, STATE_WARN};
#define CHARG_STATE_UNKNOWN	0
#define CHARG_STATE_CHARGING	1
#define CHARG_STATE_DISCHARGING	2
#define CHARG_STATE_CHARG_DISCHARG (CHARG_STATE_CHARGING | CHARG_STATE_DISCHARGING)
	enum AC_ADAPTER_STATE{AC_UNKNOWN, AC_ONLINE, AC_OFFLINE};
	enum DISK_MODE{DISK_FULL_ON, DISK_STANDBY, DISK_SLEEP};
	enum LID_STATE{LID_OPEN, LID_CLOSED};
	/* use for checkACPI function return value!*/

	enum ISACPI{NOT_SUPPORTED=-1, APM, ACPI};

	/* modes used for active/passive cooling mode
	 and for the devices' temperature state */
	enum THERM_MODE{OK, ACTIVE, PASSIVE, HOT, CRITICAL};

	enum _COOLING_POLICY{COOLING_MODE_ACTIVE=0, COOLING_MODE_PASSIVE};

typedef struct BatteryGeneral{
	int remPerc;
	int remMins;
	int charging_state; /* charging, discharging, charging/discharging, unknown*/
	int rem_charging_mins;
	/*	int capacity_state;*/
	/* ToDo: what about default battery warning low -> I think it is not needed here?!?*/
} BatteryGeneral;


	/* only available for ACPI through the getBatteryDetailedInfo function*/
typedef struct BatteryDetailed{
	int present;

	/* this is from info (ACPI)*/
	int design_capacity;
	int last_full_capacity;
	int battery_technology;
	int design_voltage;
	int design_capacity_warning;
	int design_capacity_low;
	int capacity_granularity_1;
	int capacity_granularity_2;
	char model_number[MAX_BAT_CHAR_LEN+1];
	char serial_number[MAX_BAT_CHAR_LEN+1];
	char battery_type[MAX_BAT_CHAR_LEN+1];
	char OEM_info[MAX_BAT_CHAR_LEN+1];

	/* this is from status (ACPI)*/
	int power_unit;
	int capacity_state;
	int charging_state;
	int present_rate;
	int remaining_capacity;
	int present_voltage;

	/* this is from alarm*/
	int alarm_limit;


} BatteryDetailed;


typedef struct ThermalDev{

	int present;
	int temperature;

	int cooling_mode;
	int polling_frequency;
	int critical;
	int hot;
	int passive;	
	int active[MAX_THERMAL_ACTIVE];

	int state;
	int tc1;
	int tc2;
	int tsp;
}ThermalDev;



	/***********   BATTERY STATES AND STRUCTURES  ********/

	/***********   REST OF DEFINITIONS   ****************/
	/***********   REST OF DEFINITIONS   ****************/
 


	/* **********************/
	/* */
	/* IMPORTANT !!!*/
	/**/
	/* Test all data for UNKNOWN*/
	/* You never know if the kernel or the hw supports specific features!*/
	/**/
	/* *********************/

	/**************************************************
	 *                                               
	 *  Function getBatteryInfo                      
	 *                                               
	 *  fills the given Battery struct with the current battery information
	 *  supports acpi and apm
	 *                                                
	 *************************************************/

	int getBatteriesInfo(BatteryGeneral *bat);

	/******   O N L Y   F O R   A C P I ! ! !  *****************/
	/**************************************************
	 *                                               
	 *  Functions: int getBatteriesNum();
	 *             int getBatteryDetailedInfo(const int no, BatteryDetailed &bd);
	 *             int setBatteryAlarm(const int percent);
	 *
	 * Only ACPI!
	 * These functions can be used to gain special information on batteries on 
	 * a ACPI system only!
	 * They are also used internally to determine the general battery information
	 * above                                              
	 *                                                
	 *************************************************/

	/* RETURN: */
	/*          x <  0 ERROR*/
	/*          x == 0 SUCCESS*/
	/*          x >  0 END OF BATTERIES REACHED*/
	/* use this method to get amount of batteries in the system:*/
	/* iterate until it's != 0 and check results for bd->present == PRESENT_YES*/
	int getBatteryDetailedInfo(const int no, BatteryDetailed *bd);

	/* sets the ACPI battery alarm for all batteries*/
	int setBatteryAlarm(const int percent);
	
	/* returns the current state of the lid: (enum LID_STATE{LID_OPEN, LID_CLOSED})*/
	int getLidState(void);

	/**************************************************
	 *                                               
	 *
	 * Functions: int getThrottlingInfo(int &states, int &current);
	 *            int setThrottlingState(const int state);
	 *            int setThrottlingPercent(const int percent);
	 *
	 * Only ACPI!
	 * get/set throttling states (0-8)
	 *
	 *************************************************/
	
	int getThrottlingInfo(int *states, int *current);
	/* not needed any more use setThrottlingPercent*/
	/*	int setThrottlingState(const int state);*/
	int setThrottlingPercent(const int percent);
	int getThrottlingInfoCPU(const int cpu, int *states, int *current);
	int setThrottlingStateCPU (const int cpu, const int state);
	int setThrottlingPercentCPU(const int cpu, const int percent);
	/**************************************************
	 *                                               
	 *
	 * Functions: int getThermalZonesNum();
	 *	      int getThermalZoneTemp(const int zone=0);
	 *
	 * Only ACPI!
	 * determines the thermal temperature for each themperautre zone
	 * 
	 *************************************************/
	/* returns greater than zero on success */
	/* less than zero on failure */
	int getThermalZonesNum(void);
	int getThermalZoneTemp(const int zone);
	int getThermalZoneState(int zone);
	/* returns: */
	/* zero or greater on success */
	/*  -1 if no ACPI */
	/*  -2 if no thermal directory (module probably not loaded) */
	/*  -3 if thermal device no. num does not exist */
	/*  -4 if td is not allocated */
	int getThermalZone(const int zone, ThermalDev *td);

	/* returns: */
	/*   NO_ACPI_ERROR */
	/*   NO_MODULE_ERROR */
	/*  -3 if thermal device no. num does not exist */
	int setThermalTrippoints(const int zone, const ThermalDev td);

	/* returns: */
	/*   NO_ACPI_ERROR */
	/*   NO_MODULE_ERROR */
	/*  -1 general error -> could not be set */
	/*  -2 if cooling_mode is not supported */
	/*  -3 if thermal device no. num does not exist */
	int setCoolingMode(const int num, const int mode);
	/**************************************************
	 *                                               
	 *
	 * Functions: int getFanNum();
	 *	      int getFanStatus(const int no);
	 *
	 * Only ACPI!
	 * determines the fan's status and no. of devices
	 * 
	 *************************************************/
	/* returns x < 0 on failure */
	/* or the number of fan devices on success */
	int getFanNum(void);
	
	/* returns: */
	/*  0 if fan is on */
	/*  1 if fan is off */
	/*  -1 if no ACPI */
	/*  -2 if no fan directory (module probably not loaded) */
	/*  -3 if fan device no. num does not exist */
	/*  -4 if state file does not exist */
	/*  -5 if state could not be figured out (probably changes in kernel syntax) */
	int getFanStatus(const int no);
	/******   O N L Y   F O R   A C P I ! ! !  *****************/


	/* returns if the machine is on ac power or not (enum AC_ADAPTER_STATE{AC_ONLINE, AC_OFFLINE});*/
	/* apm + acpi*/
	int getACAdapterStatus(void);
	

	/******************************************************************/
	/* CPU FREQUENCY SCALING*/
	/* */
	/* all relevant code is inside the daemon for now*/
	/* the reason is too different implementations for 2.4.x and 2.6.x*/
	/* and mainly to not let other applications use it, because*/
	/* cpufreq scaling should always be controlled by only one application!*/
	/* therefore only general methods are implemented here!*/

	/* be careful this method waits a second ...*/
	/* first commented out because it failed on ia64 machines!*/
	float getRealProcessorSpeed(void);	
	
	/* returns UNKNOWN if not supported, just reads out /proc file*/
	
	/* returns "Idleness" of the processor in percent*/
	/* since the last time this function has been called*/
	
	/* if you poll idleness of processor, ignore the result */
	/* of the first time you invoke this function, because*/
	/* it will be the total idleness of cpu since the machine*/
	/* has been powered on*/
	double getCPULoad(void);
	double getCPULoadConsiderNice(const int nice);
	double getCPULoadSMP(const int consider_nice, const int cpu);
	void freeCPULoadSMPCalls(void);
	int getCPUCount(void);
	/******************************************************************/

	/******************************************************************/
        /*
         *  Sleeping States
         *
	 *
	 */

#define ACPI_S1 1
#define ACPI_S2 2
#define ACPI_S3 4
#define ACPI_S3_BIOS 8
#define ACPI_S4 16
#define ACPI_S4_BIOS 32
#define APM_STANDBY 64
#define APM_SUSPEND 128
	/* mask out return value to evaluate supported states */
	int64_t getSupportedSleepStates(void);

	/******************************************************************/
	/* with this method you can determine whether there is apm, acpi or nothing on your Computer*/
	/* return values: NOT_SUPPORTED=-1, APM, ACPI  */
	int checkACPI(void);

	/* set debug level according to the macro below. Values: 0-31*/
	/* if library is compiled without -D DEBUG variable this method has no effect.*/
	/* 0 = nothing*/
	/* 1 = error*/
	/* 2 = warning*/
	/* 4 = diag*/
	/* 8 = info*/
	/* 16= debug*/
	/* sum up the levels you want to see: e.g.: 7 -> error + warning + diag*/
	void setDebugLevel(const int dbg);

	/***************** DEBUG DEFINITIONS ********************/
	/* define this variable through Makefile later to set debug possiblities on or of for the library*/
	/* additionally you can set -DSYSLOG in Makefile(see later) to let all debug be forwarded to */
	/* to the syslog daemon*/

#ifdef DEBUG
#define DBG_ERR 1
#define DBG_WARN 2
#define DBG_DIAG 4
#define DBG_INFO 8
#define DBG_DEBUG 16

	/* what about multiple threads ?!? -> I think it should be save ...*/
	extern int DEBUG_LEVEL;

#ifdef HAVE_SYSLOG_H
        static int syslog_open = 0; 
#define pDebug(level, string, args...) \
do{\
	if (!syslog_open){ \
		openlog("[powersave]", LOG_PID, LOG_DAEMON); \
	        syslog_open = 1; \
	} \
        if (level == DBG_ERR && (DEBUG_LEVEL & DBG_ERR)){ \
              syslog(LOG_ERR, "ERROR in Function %s; line %d: "string, __FUNCTION__, __LINE__, ## args); \
        }else if (level == DBG_WARN && (DEBUG_LEVEL & DBG_WARN)) { \
              syslog(LOG_WARNING, "WARNING in Function %s; line %d: "string, __FUNCTION__, __LINE__, ## args); \
        }else if (level == DBG_DIAG && (DEBUG_LEVEL & DBG_DIAG)) { \
              syslog(LOG_NOTICE, "DIAG in Function %s, line %d:  "string, __FUNCTION__, __LINE__, ## args); \
        }else if (level == DBG_INFO && (DEBUG_LEVEL & DBG_INFO)) {\
              syslog(LOG_INFO, "Info:  "string, ## args); \
        }else if (level == DBG_DEBUG && (DEBUG_LEVEL & DBG_DEBUG)) {\
              syslog(LOG_INFO, "Debug:  "string, ## args); \
        } \
}while(0);
#else
#define pDebug(level, string, args...) \
do{\
        if (level == DBG_ERR && (DEBUG_LEVEL & DBG_ERR)){ \
              fprintf(stderr, "[POWERSAVE] ERROR in Function %s; line %d: "string, __FUNCTION__, __LINE__, ## args); \
        }else if (level == DBG_WARN && (DEBUG_LEVEL & DBG_WARN)) { \
              fprintf(stderr, "[POWERSAVE] WARNING in Function %s; line %d: "string, __FUNCTION__, __LINE__, ## args); \
        }else if (level == DBG_DIAG && (DEBUG_LEVEL & DBG_DIAG)) { \
              printf("[POWERSAVE] DIAG in Function %s, line %d:  "string, __FUNCTION__, __LINE__, ## args); \
        }else if (level == DBG_INFO && (DEBUG_LEVEL & DBG_INFO)) {\
              printf(" "string, ## args); \
        }else {\
              printf( ""string, ## args); \
        } \
}while(0);
/*              printf("[POWERSAVE] INFO in Function %s, line %d: "string, __FUNCTION__, __LINE__, ## args); \*/
#endif

#else
#define pDebug(level, string, args...) do {} while (0);
#endif
	/***************** DEBUG DEFINITIONS ********************/

#ifdef __cplusplus
}
#endif

#endif
