/*
 * This file is part of the Owl Positioning System (OwlPS) project.
 * It is subject to the copyright notice and license terms in the
 * COPYRIGHT.t2t file found in the top-level directory of this
 * distribution and at
 *   https://code.lm7.fr/mcy/owlps/src/master/COPYRIGHT.t2t
 * No part of the OwlPS Project, including this file, may be copied,
 * modified, propagated, or distributed except according to the terms
 * contained in the COPYRIGHT.t2t file; the COPYRIGHT.t2t file must be
 * distributed along with this file, either separately or by replacing
 * this notice by the COPYRIGHT.t2t file's contents.
 */

/**
 * @file owlps-resultreader.h
 * @brief OwlPS Result Reader library
 *
 * libowlps-resultreader is the the library that provides functions to
 * read and display results sent on UDP by OwlPS Positioner.
 *
 * See also the source code of the example program
 * `owlps-resultreader-udp`.
 */


#ifndef _LIBOWLPS_RESULTREADER_CSV_
#define _LIBOWLPS_RESULTREADER_CSV_

#include <owlps.h>

#include <stdio.h>
#include <inttypes.h>


/* Maximum size of a result CSV string sent by OwlPS Positioner.
 * Request's information:
 *   MAC, request type (2 chars), timestamp, ';'
 * Plus, for each algorithm:
 *   Name, three coordinates, error (we assume the same size as the
 *   coordinates), area name, ';'
 * Let's define OWL_NB_ALGORITHMS as the number of implemented
 * algorithms (this is ugly).
 */
#define OWL_NB_ALGORITHMS 10
#define OWL_CSV_RESULT_REQUEST_STRLEN \
  (OWL_ETHER_ADDR_STRLEN + OWL_TIMESTAMP_STRLEN + 3)
#define OWL_CSV_ALGORITHM_RESULT_STRLEN \
  (OWL_ALGORITHM_STRLEN + 4 * OWL_COORDINATE_STRLEN + \
   OWL_AREA_STRLEN + 1)
/// Maximum size of a result CSV string sent by OwlPS Positioner
#define OWL_CSV_RESULT_STRLEN \
  (OWL_CSV_RESULT_REQUEST_STRLEN + \
   OWL_NB_ALGORITHMS * OWL_CSV_ALGORITHM_RESULT_STRLEN + 1)

/* Same thing, but for the simplified CSV strings created by
 * *_to_csv_simple().
 * Request's information is only the MAC address.
 * For the algorithm:
 *  = 12 characters per coordinate + OWL_AREA_STRLEN
 */
#define OWL_CSV_RESULT_REQUEST_SIMPLE_STRLEN OWL_ETHER_ADDR_STRLEN
#define OWL_CSV_ALGORITHM_RESULT_SIMPLE_STRLEN \
  (3 * OWL_COORDINATE_STRLEN + OWL_AREA_STRLEN + 1)
/// Maximum size of a simplified result CSV string as created by
/// *_to_csv_simple()
#define OWL_CSV_RESULT_SIMPLE_STRLEN \
  (OWL_CSV_RESULT_REQUEST_SIMPLE_STRLEN + \
   OWL_NB_ALGORITHMS * OWL_CSV_ALGORITHM_RESULT_SIMPLE_STRLEN + 1)


/// Structure of linked list of algorithm's results
/**
 * This structure represents the result of a single algorithm, and
 * includes a field `next` which points to the next algorithm's result,
 * if any, or `NULL` if it is the last algorithm.
 */
struct _owl_algorithm_result
{
  char *algorithm ; ///< Name of the algorithm used to compute the result
  float x ; ///< Computed X coordinate
  float y ; ///< Computed Y coordinate
  float z ; ///< Computed Z coordinate
  float error ; ///< Distance error (if available)
  char *area ; ///< Name of the area in which the result point is

  struct _owl_algorithm_result *next ; ///< Next result
} ;
/// Linked list of algorithms' results
typedef struct _owl_algorithm_result owl_algorithm_result ;


/// Structure of the generated results for a request
/**
 * This structure stores the information of a request along with a
 * pointer to the list of generated results.
 */
struct _owl_result
{
  char mobile_mac_addr[OWL_ETHER_ADDR_STRLEN] ; ///< Mobile's MAC address
  uint8_t request_type ; ///< Type of the request
  /// Local time on the mobile when sending the request
  owl_timestamp mobile_timestamp ;
  unsigned int nb_results ; ///< Number of results generated
  owl_algorithm_result *results ; ///< List of the generated results
} ;
/// Generated results for a request
typedef struct _owl_result owl_result ;


/// Receives a result from the socket `sockfd`
owl_result* owl_receive_position(const int sockfd) ;
/// Splits the `csv` string and stores it in a new `owl_result`
owl_result* owl_fill_result(char *csv) ;
/// Splits the `csv` string and stores it in a new `owl_algorithm_result`
owl_algorithm_result* owl_fill_algorithm_result(char **csv) ;
/// Reads an integer from the `csv` string
int owl_read_long_field(char **const csv, const char *const delim,
                        long *const ret) ;
int owl_read_float_field(char **const csv, float *const ret) ;

/// Converts an `owl_result back` to a CSV string
void owl_result_to_csv(char dst[OWL_CSV_RESULT_STRLEN],
                       const owl_result *const src) ;
/// Converts an `owl_algorithm_result` back to a CSV string
void
owl_algorithm_result_to_csv(char dst[OWL_CSV_ALGORITHM_RESULT_STRLEN],
                            const owl_algorithm_result *const src) ;
/// Converts an `owl_result` back to a CSV string (simplified format)
void owl_result_to_csv_simple(char dst[OWL_CSV_RESULT_SIMPLE_STRLEN],
                              const owl_result *const src) ;
/// Converts an `owl_algorithm_result` back to a CSV string (simplified
/// format)
void owl_algorithm_result_to_csv_simple
(char dst[OWL_CSV_ALGORITHM_RESULT_SIMPLE_STRLEN],
 const owl_algorithm_result *const src) ;

/// Prints an `owl_result` to the given stream
void owl_fprint_result(FILE *const stream, const owl_result *const src) ;
/// Prints an `owl_algorithm_result` to the given stream
void owl_fprint_algorithm_result(FILE *const stream,
                                 const owl_algorithm_result *const src) ;
/// Prints an `owl_result` to the standard output
#define owl_print_result(SRC) \
  (owl_fprint_result(stdout, (SRC)))
/// Prints an `owl_algorithm_result` to the standard output
#define owl_print_algorithm_result(SRC) \
  (owl_fprint_algorithm_result(stdout, (SRC)))

/// Frees an `owl_result`
void owl_free_result(owl_result *const result) ;
/// Frees a single `owl_algorithm_result`
void owl_free_algorithm_result(owl_algorithm_result *const algo) ;


#endif // _LIBOWLPS_RESULTREADER_CSV_
