/*
 * Copyright (c) 2019 Clementine Computing LLC.
 *
 * This file is part of PopuFare.
 * 
 * PopuFare is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * PopuFare 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 Affero General Public License for more details.
 * 
 * You should have received a copy of the GNU Affero General Public License
 * along with PopuFare.  If not, see <https://www.gnu.org/licenses/>.
 *
 */

#ifndef _CLIENT_UTILS_H
#define _CLIENT_UTILS_H

//-------------------------------------- Utility structures to hold the system status data and be updated by the default system callbacks
extern gps_status	gps_stat;
extern stop_status	stop_stat;
extern driver_status	driver_stat;
extern pass_status	pass_stat;
extern bill_status	bill_stat;

//---------------------------------------------------

//These functions return the effective latitude and longitude
//If there is a good GPS fix, we use this, otherwise we use the
//coordinates of the last stop we were at (even if the driver manually advanced there)
float effective_lat();
float effective_lon();

//---------------------------------------------------

//This enum specifies the values that can be returned by a message callback
typedef enum 
{
  MESSAGE_UNHANDLED	= -1,	//This message was unhandled (this is actually only returned by the main message processing function).

  MESSAGE_HANDLED_CONT	= 0,	//The message was handled, and we should attempt no further processing on this message
  MESSAGE_HANDLED_STOP,		//The message was handled, and we should see if it matches any other callbacks
  
} message_callback_return;

//These macros are default ident values for some common message handling semantics
#define CALLBACK_PREPROCESS	(-1)	//the ident value CALLBACK_PREPROCESS is essentially only for things to be marked ignore
#define CALLBACK_SYSTEM		(0)	//the ident value CALLBACK_SYSTEM is for the default status message handlers which update the global structures

//This macro will generate an ident value for a user-defined behavior
#define CALLBACK_USER(x)	(1000 + (x))

//This defines a function pointer type for message callback functions and allows the message handling structures and functions
//to have sane-looking prototypes...
typedef message_callback_return (*message_notify_func)(struct message_record *, void *);
//A function that fits this pointer type will be defined like this:
//
//  message_callback_return foo(struct message_record *msg, void *param)
//  {
//  	return MESSAGE_HANDLED_CONT;
//  }


//--------------------------------------------------------------------------------------------------------------------------
//						CALLBACK HANDLING FUNCTIONS
//--------------------------------------------------------------------------------------------------------------------------

//This function subscribes a client to all of the mailboxes with system callbacks
int subscribe_to_default_messages(int fd);

//----------------------------------------------- UTILITY CALLBACKS

message_callback_return ignore_message(struct message_record *msg, void *param);

//----------------------------------------------- CALLBACK REGISTRATION AND RELATED FUNCTIONS

//This function registers a callback to happen when a certain message is received.
//It takes four parameters:
//                              mailbox = string containing name of mailbox to trigger this callback
//                              ident   = a numeric identifier specifying both a unique identifier for this callback, and processing order
//                              func    = a message handling callback function
//                              param   = an untyped pointer used to pass any outside contect to the callback
//
int register_dispatch_callback(char *mailbox, int ident, message_notify_func func, void *param);

//This function unregisters a message callback function by its mailbox name and identifier
//this allows for easy selective removal of a specific callback while still keeping the rest of the chain intact
int unregister_dispatch_callback(char *mailbox, int ident);

//This function unregisters ALL callbacks in preparation for a clean exit
int unregister_all_callbacks();

//This function registers the default system status callbacks
int register_system_status_callbacks();


//This function unregisters the default system status callbacks
int unregister_system_status_callbacks();

//----------------------------------------------- CALLBACK PROCESSING FUNCTIONS

//This function actually processes a message through the dispatch list
//using the return values of the callbacks to determine whether to stop or continue
//the return value is the return value of the last handler to have read the message.
//a return value of MESSAGE_UNHANDLED means that no handler successfully handled the message.
message_callback_return process_message(struct message_record *msg);


//--------------------------------------------------------------------------------------------------------------------------
//					MESSAGE FORMATTING FUNCTIONS FOR SOME COMMON MESSAGES
//--------------------------------------------------------------------------------------------------------------------------

//This function is a printf-line interface to format user display messages:
//
//      target = blank IPC message to fill with this log entry
//      line = which line of the display to draw on (0 or 1)
//      priority = what message priority?
//      duration = how many seconds to display this (0 makes it the default message)
//      fmt = printf format
//      ... = printf args
int format_piu_message(struct message_record *target, int line, int priority, int duration, const char *fmt, ...);


#define LOGLEVEL_DEBUG	('#')
#define LOGLEVEL_WARN	('*')
#define LOGLEVEL_ERROR	('!')

#define LOGLEVEL_ACCEPT	('>')
#define LOGLEVEL_REJECT	('<')
#define LOGLEVEL_EVENT	('|')


//This function takes a buffer and a buffer size and puts a
//log prefix in that contains the equipment number and the local time
int make_log_prefix(char *prefix, int max);

//This function is a printf-line interface to format log messages for the server: (note, it already applies the above prefix, so you don't have to)
//
//      target = blank IPC message to fill with this log entry
//      loglevel = one of the following: LOGLEVEL_DEBUG, LOGLEVEL_WARN, LOGLEVEL_ERROR
//      fmt = printf format
//      ... = printf args
//
//      NOTE:  DO NOT UNDER ANY CIRCUMSTANCES TERMINATE A LOG MESSAGE WITH A '\n' CHARACTER!
//
int format_log_message(struct message_record *target, char loglevel, const char *fmt, ...);

//This function is a printf-line interface to format messages for the driver:
//
//      target = blank IPC message to fill with this log entry
//      loglevel = one of the following: LOGLEVEL_DEBUG, LOGLEVEL_WARN, LOGLEVEL_ERROR
//      fmt = printf format
//      ... = printf args
//
//      NOTE:  DO NOT UNDER ANY CIRCUMSTANCES TERMINATE A LOG MESSAGE WITH A '\n' CHARACTER!
//
int format_driver_message(struct message_record *target, char loglevel, const char *fmt, ...);

//This function printf-line interface to format messages for debug and trace purposes
//
int format_trace_message(struct message_record *target, const char *fmt, ...);



#define BILLING_ACTION_LEN	(16)
#define BILLING_RULE_LEN	(24)
#define BILLING_RULEPARAM_LEN	(24)
#define BILLING_REASON_LEN	(32)
#define BILLING_CREDENTIAL_LEN	(32)

//This function formats a billing log entry into a form ready to pass off to the billdb process:
//
//      target = blank IPC message to fill with this log entry
//      action = string specifying billing action (ACCEPT, REJECT, PASSBACK, etc...)
//      rule =   string specifying which rule (if any) generated this billing entry
//      ruleparam = string specifying the parameter passed to the above rule
//      reason = human readable reason for the reject or accept of this rider
//      credential = string containing the magnetic or RFID credential used to identify the rider
//      rider_id = rider ID from pass table
//      cash_value = number of cents paid for this fare if it is a cash fare
//
//      All other required values are supplied by the system status structures maintained by the default status callbacks:
//
//      equipment number, GPS locaction, driver, paddle, route, trip, stop, and stop name
//
int format_billing_message(struct message_record *target, char *action, char *rule, char *ruleparam, char *reason, char *credential, unsigned long long rider_id, int cash_value);


#endif
