/*

Copyright (C) 2000 - 2004 Christian Kreibich <christian@whoop.org>.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies of the Software and its documentation and acknowledgment shall be
given in the documentation and software packages that this Software was
used.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

*/
#ifndef __libnd_trace_pm_h
#define __libnd_trace_pm_h

#include <pcapnav.h>
#include <libnd_types.h>

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

/* An enumeration to specify iteration in time or space.
 */
typedef enum {
  LND_TPM_SPACE,
  LND_TPM_TIME,
  LND_TPM_ERROR
} LND_TPM_NavMode;


/* One TPM structure is part of each trace and provides
 * information about the trace part management. 
 */
struct lnd_tpm
{
  /* The trace this manager belongs to */
  LND_Trace      *trace;

  /* Size of the currently handled file, minus the pcap
   * file header.
   */
  off_t           size;

  LND_TracePart  *base;

  /* The trace part currently loaded into memory.
   * Two invariants here:
   *
   * - This is ALWAYS assumed to be a valid pointer!
   *   There may be no packets in the part for some reason,
   *   but there is still a current trace part.
   *
   * - tpm->current is always swapped in, thus never member
   *   of tpm->parts, which only contains swapped-out parts.
   */
  LND_TracePart  *current;
  
  /* The name of the base of the trace for saving the entire trace
   * to temporary storage */
  char           *output_name;
};


/**
 * libnd_tpm_new -- allocates and initializes a new trace part manager.
 * @trace: trace to manage.
 *
 * The function allocates a new trace part manager, sets up basic
 * stuff and returns it. It does not load any packets yet.
 *
 * Returns: new manager.
 */
LND_TPM          *libnd_tpm_new(LND_Trace *trace);


/**
 * libnd_tpm_free - cleans up trace part manager.
 * @tpm: trace part manager to free.
 *
 * The function shuts down @tpm properly and releases
 * any memory occupied. It also takes care of freeing
 * all related trace parts, removing temporary files etc.
 */
void             libnd_tpm_free(LND_TPM *tpm);


/**
 * libnd_tpm_read_packet - reads a single packet from current location.
 * @tpm: trace part manager.
 * @packet: result pointer.
 *
 * The function tries to read a single packet from the current location
 * in the trace. The resulting packet data is read into @packet. NOTE:
 * Upon return, @packet is not initialized, and its raw packet data
 * points to volatile storage. If you want to keep the packet around
 * after further calls to this function, you need to libnd_packet_duplicate()
 * the packet!
 *
 * Returns: %TRUE if successful, %FALSE otherwise.
 */
gboolean         libnd_tpm_read_packet(LND_TPM *tpm, LND_Packet *packet);


/**
 * libnd_tpm_load_packets - fills packets into current trace part.
 * @tpm: trace part manager.
 *
 * This function loads as many packets into memory as configured
 * by the user, and fires an LND_TRACE_RELOAD event after the
 * packets have been loaded.
 */
void             libnd_tpm_load_packets(LND_TPM *tpm);


/**
 * libnd_tpm_load_prev_part - loads packets located before the current part.
 * @tpm: trace part manager.
 *
 * The function is function loads as many packets into memory as the user
 * has configured, so that the last packet is located before the first
 * one of the current trace part. After the packets are loaded, an
 * LND_TRACE_RELOAD event is fired.
 */
void             libnd_tpm_load_prev_part(LND_TPM *tpm);


/**
 * libnd_tpm_next_prev_part - loads packets located after the current part.
 * @tpm: trace part manager.
 *
 * The function is function loads as many packets into memory as the user
 * has configured, so that the first packet is located after the last
 * one of the current trace part. After the packets are loaded, an
 * LND_TRACE_RELOAD event is fired.
 */
void             libnd_tpm_load_next_part(LND_TPM *tpm);


/**
 * libnd_tpm_set_output_file - sets output filename.
 * @tpm: trace part manager.
 * @filename: new base file name.
 *
 * The function sets @filename as the new base file name to write to.
 * Handle with care, you shouldn't really need this function. It's used
 * e.g. when a trace is saved to cause the packets to be written to the
 * original filename.
 */
void             libnd_tpm_set_output_file(LND_TPM *tpm, const char *filename);


/**
 * libnd_tpm_num_memory_packets - returns number of packets to keep in memory.
 *
 * This is a helper function returning the maximum number of
 * packets to keep in memory at any one point, as configured
 * by the user.
 *
 * Returns: maximum number of packets to be kept in memory at any time.
 */
guint            libnd_tpm_num_memory_packets();


/**
 * libnd_tpm_clear_current_part - cleans up a TPM's current trace part.
 * @tpm: trace part manager whose current trace part to clear.
 * @emit_signal: whether to emit a %LND_TRACE_CLEAR signal or not.
 *
 * The function releases @tpm's current trace part. If the part got modified,
 * it is added to the layers of trace parts on top of the base file, otherwise
 * it is simply freed. Depending on @emit_signal, a %LND_TRACE_CLEAR signal
 * is delivered to registered trace observers or not.
 */
void             libnd_tpm_clear_current_part(LND_TPM *tpm, gboolean emit_signal);


/**
 * libnd_tpm_add_part - adds a trace part to the manager.
 * @tpm: trace part manager.
 * @tp: trace part to add.
 *
 * The function adds @tp to @tpm's trace parts.
 */
void             libnd_tpm_add_part(LND_TPM *tpm, LND_TracePart *tp);


/**
 * libnd_tpm_remove_part - removes a trace part from the manager.
 * @tpm: trace part manager.
 * @tp: trace part to remove.
 *
 * The function removes @tp from @tpm's trace parts. This only
 * works when @tp is a plateau, that is, when there are no other
 * parts stacked on top of it.
 *
 * Returns: %TRUE if operation was successful, %FALSE otherwise.
 */
gboolean         libnd_tpm_remove_part(LND_TPM *tpm, LND_TracePart *tp);


/**
 * libnd_tpm_goto_ts - jump to a given timestamp in the file.
 * @tpm: trace part manager.
 * @timestamp: timestamp to jump to.
 *
 * The function jumps to the packet whose timestamp has a timestamp closest to
 * @timestamp. If the current trace part was previously modified, it is swapped
 * out to disk first. If the jump succeeded, an LND_TRACE_JUMPED event is
 * fired.
 *
 * Returns: result of jump, %PCAPNAV_DEFINITELY if it was successful. See
 * pcapnav.h for the other possible outcomes.
 */ 
pcapnav_result_t libnd_tpm_goto_ts(LND_TPM *tpm, struct bpf_timeval *timestamp);


/**
 * libnd_tpm_goto_fraction - jump to a given fraction in the file.
 * @tpm: trace part manager.
 * @fraction: fraction to jump to.
 *
 * The function jumps to the packet closest to the given size fraction of the
 * full trace. If the current trace part was previously modified, it is swapped
 * out to disk first. If the jump succeeded, an LND_TRACE_JUMPED event is
 * fired.
 *
 * Returns: result of jump, %PCAPNAV_DEFINITELY if it was successful. See
 * pcapnav.h for the other possible outcomes.
 */ 
pcapnav_result_t libnd_tpm_goto_fraction(LND_TPM *tpm, double fraction);


/**
 * libnd_tpm_goto_loc - jumps to a previously calculated location in the trace.
 * @tpm: trace part manager.
 * @loc: location to jump to.
 *
 * The function jumps to the location given by @loc. You can calculate a
 * location in three ways: using libnd_tpm_find_offset(),
 * libnd_tpm_find_fraction() and libnd_tpm_find_timestamp().
 * If the jump succeeded, an LND_TRACE_JUMPED event is fired.
 *
 * Returns: %TRUE if jump was successful, %FALSE otherwise.
 */
gboolean         libnd_tpm_goto_loc(LND_TPM *tpm, LND_TraceLoc *loc);


/**
 * libnd_tpm_is_tp_overlap - predicate that tests whether two trace parts overlap.
 * @tpm: trace part manager.
 * @tp1: first trace part.
 * @tp2: second trace part.
 *
 * The function tests two trace parts for overlap.
 *
 * Returns: %TRUE if @tp1 and @tp2 overlap, %FALSE otherwise.
 */
gboolean         libnd_tpm_is_tp_overlap(const LND_TPM *tpm,
					 const LND_TracePart *tp1,
					 const LND_TracePart *tp2);

/**
 * libnd_tpm_map_loc_to_offset - calculates the global offset of a trace location.
 * @tpm: trace part manager.
 * @loc: trace location.
 *
 * The function takes a trace location as input an calculates the
 * global offset in @tpm's trace that corresponds to this location.
 * Opposite to libnd_tpm_map_offset_to_loc().
 *
 * Returns: calculated offset.
 */
off_t            libnd_tpm_map_loc_to_offset(const LND_TPM *tpm,
					     const LND_TraceLoc *loc);

/**
 * libnd_tpm_map_offset_to_loc - calculates the trace location of a global offset.
 * @tpm: trace part manager.
 * @offset: offset to calculate with.
 * @loc: result pointer.
 *
 * The function takes @offset as input and calculates the trace location
 * for the packet closest to @offset in @tpm's current trace part
 * arrangement. Opposite of libnd_tpm_map_location_to_offset().
 * The resulting location is reported in @loc.
 *
 * Returns: success state of operation.
 */
pcapnav_result_t libnd_tpm_map_offset_to_loc(const LND_TPM *tpm,
					     off_t offset,
					     LND_TraceLoc *loc);

/**
 * libnd_tpm_map_loc_to_timestamp - calculates the timestamp of the packet at a trace location.
 * @tpm: trace part manager.
 * @loc: trace location to find timestamp of.
 * @tv: result pointer for calculated timestamp.
 *
 * The function takes trace location @loc as input and looks up the timestamp
 * of the packet that is closest to this location in @tpm's current trace
 * part scenario.
 *
 * Returns: %TRUE of the calculation was successful, %FALSE otherwise.
 */
gboolean         libnd_tpm_map_loc_to_timestamp(LND_TPM *tpm,
						LND_TraceLoc *loc,
						struct bpf_timeval *tv);


/**
 * libnd_tpm_map_fraction_to_loc - calculates the location of a fractional offset in a trace.
 * @tpm: trace part manager of trace.
 * @fraction: fraction to calculate.
 * @loc: result pointer, receives calculated location.
 *
 * This function calculates the location (i.e., trace part and offset
 * within that trace part) of a fractional offset in the trace (for example,
 * 0.5 is the middle of the trace). The resulting trace location is reported
 * in @loc upon return.
 *
 * Returns: the success status of the operation. This is a pcapnav
 * result type as the function relies on pcapnav to perform this operation.
 */
pcapnav_result_t libnd_tpm_map_fraction_to_loc(const LND_TPM *tpm,
					       double fraction,
					       LND_TraceLoc *loc);


/**
 * libnd_tpm_map_timestamp_to_loc - calculates the location of a timestamp in a trace.
 * @tpm: trace part manager of trace.
 * @timestamp: timestamp to calculate.
 * @loc: result pointer, receives calculated location.
 *
 * This function calculates the location (i.e., trace part and offset
 * within that trace part) of the packet with a timestamp closest to @timestamp.
 * The resulting trace location is reported in @loc upon return.
 *
 * Returns: the success status of the operation. This is a pcapnav
 * result type as the function relies on pcapnav to perform this operation.
 */
pcapnav_result_t libnd_tpm_map_timestamp_to_loc(const LND_TPM *tpm,
						struct bpf_timeval *timestamp,
						LND_TraceLoc *loc);



/**
 * libnd_tpm_get_offset - returns absolute offset from beginning of file.
 * @tpm: trace part manager.
 *
 * Returns: the absolute offset in bytes from the start of the
 * trace file, in the current trace parts configuration. Does
 * not include the size of the trace file header.
 */
off_t            libnd_tpm_get_offset(const LND_TPM *tpm);


/**
 * libnd_tpm_find_locs - calculates the start and end locations of a trace area.
 * @tpm: trace part manager.
 * @area: trace area to calculate locations of.
 * @start: result pointer for start location.
 * @end: result pointer for end location.
 *
 * The function takes the trace area pointed to by @area as
 * input and calculates the start and end trace locations that
 * the boundaries of this area correspond to in @tpm's current
 * trace part arrangement. The results are returned through
 * @start and @end, respectively.
 *
 * Returns: %TRUE of the calculation was successful, %FALSE otherwise.
 */
gboolean         libnd_tpm_find_locs(const LND_TPM *tpm,
				     LND_TraceArea *area,
				     LND_TraceLoc *start,
				     LND_TraceLoc *end);
/**
 * libnd_tpm_get_space_fraction - returns fraction in trace occupied by given offset.
 * @tpm: trace part manager.
 * @offset: offset to calculate with.
 *
 * The function returns the fraction in the trace where @offset is located.
 * 0.5 means that we're currently in the middle of the file, 1.0 that we're at the end.
 *
 * Returns: fraction in space.
 */
double           libnd_tpm_get_space_fraction(const LND_TPM *tpm, off_t offset);


/**
 * libnd_tpm_get_time_fraction - returns fraction in trace occupied by given timestamp.
 * @tpm: trace part manager.
 * @tv: timestamp to calculate with.
 *
 * The function returns the fraction in the trace where the packet with
 * timestamp @tv is located. 0.5 means that we're currently at the point
 * in trace whose packets are in the middle between the start- and end
 * times of the full trace.
 *
 * Returns: fraction in time currently visited.
 */
double           libnd_tpm_get_time_fraction(const LND_TPM *tpm,
					     const struct bpf_timeval *tv);


/**
 * libnd_tpm_get_rel_size - returns size of the currently loaded trace part, relative to entire trace.
 * @tpm: trace part manager.
 *
 * The function compares the size (in bytes) of the trace part that is currently loaded into memory
 * to the size of the entire trace, and returns that ration.
 *
 * Returns: size of trace part loaded / size of entire trace.
 */
double           libnd_tpm_get_rel_size(const LND_TPM *tpm);


/**
 * libnd_tpm_get_packets - accessor function for currently visited packets.
 * @tpm: trace part manager.
 *
 * Returns: first packet in list of currently loaded packets, if any. Otherwise
 * returned value is %NULL.
 */
LND_Packet      *libnd_tpm_get_packets(LND_TPM *tpm);


/**
 * libnd_tpm_get_sel - accessor function for currently selected packets.
 * @tpm: trace part manager.
 *
 * Returns: first packet in list of selected packets in current trace part,
 * if any. Otherwise the returned value is %NULL.
 */
LND_Packet      *libnd_tpm_get_sel(LND_TPM *tpm);


/**
 * libnd_tpm_pcap_read_handler - convenience pcap read handler
 * @data: an #LND_TPM pointer.
 * @h: pointer to a pcap packet header
 * @pdata: packet data
 *
 * This is a pcap read handler that expects the data ptr to be an
 * LND_TracePart *. It adds the passed packet to this trace part.
 */
void             libnd_tpm_pcap_read_handler(u_char *data,
					     const struct pcap_pkthdr *h,
					     const u_char *pdata);

/**
 * libnd_tpm_dump_parts - debugging function that dumps trace part
 * descriptions to the console.
 * @tpm: trace part manager whose trace parts to print.
 *
 * This debugging function prints a textual description of the
 * current trace part arrangement to the console.
 */
void             libnd_tpm_dump_parts(LND_TPM *tpm);

#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif

