/*

Copyright (C) 2000 - 2006 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_tp_h
#define __libnd_tp_h

#include <libnd_types.h>

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

/* Trace parts define contain the packets of a contiguous area in a
 * trace file. They are managed by Trace Part Managers (TPMs, libnd_tpm.h)
 * and may contain up to a configurable maximum number of packets 
 * loaded into memory. The TPMs manage the stacking of the trace parts
 * when areas in a trace file get modified.
 */ 


/* Trace locations combine the notion of a trace part and an offset
 * into the part in one structure.
 */
struct lnd_trace_loc
{
  LND_TracePart *tp;
  off_t          offset;
};


struct lnd_trace_part
{
  /* Manager this part belongs to */
  LND_TPM             *tpm;

  /* The file this part is reading its packets from: */
  char                *in_filename;
  /* The name of this part when swapped out to disk: */
  char                *out_filename;

  /* All trace parts can be navigated -- this is the pcapnav handle for it. */
  pcapnav_t           *pcn;
  LND_TracePart       *next_part;

  pcap_dumper_t       *pd;

  /* First and last packet timestamps of the trace part. */
  struct bpf_timeval   start_ts;
  struct bpf_timeval   end_ts;

  /* GList<LND_TracePart*> of swapped out trace parts sitting
   * on top of this trace part (possibly extending past its end).
   */
  GList               *parts;

  /* GList<LND_TracePart*> of swapped out trace parts sitting
   * on top of this trace part, for BACKWARD iteration.
   */
  GList               *bw_parts;

  int                  op_queue_index;

  LND_Packet          *pl;               /* Packet list */
  LND_Packet          *pl_end;           /* Last in packet list */
  
  struct {
    LND_Packet        *pl;               /* Selected packets */
    int                size;
    LND_Packet        *last;
    int                last_index;
    gboolean           last_valid;
  } sel;

  /* The number of packets in this trace part. This value
   * will be correct except for the part representing the
   * base file.
   */
  guint                num_packets;

  /* The location (trace part and offset) that this part starts at. */
  LND_TraceLoc         start;
  /* The location (trace part and offset) that this part ends at. */
  LND_TraceLoc         end;

  /* The real size of this trace part. When a trace part is first
   * created this will just be the real size, but then the user
   * can perform manipulations, including insertions and deletions
   * of packets. This change the real size of the trace part,
   * which is recorded here.
   */
  off_t                size;

  gboolean             dirty;

  /* Whether this part currently belongs to some TPM */
  gboolean             anchored;
};



/* Different events that trace part observers can get reports on.
 * See libnd_tp_observer_XXX() below.
 */
typedef enum {  
  LND_TP_PACKET_SEL        = (1 << 0), /* Packet at certain index got selected */
  LND_TP_PACKET_UNSEL      = (1 << 1), /* Packet at certain index got deselected */
  LND_TP_SEL_CLR           = (1 << 2), /* All packets got deselected */
  LND_TP_SEL_ALL           = (1 << 3), /* All in-mem packets of trace part got selected */
  LND_TP_SEL_DEL           = (1 << 4), /* Selected in-mem packets got deleted */
  LND_TP_DIRTY_STATE       = (1 << 5), /* Trace part's dirty state got changed */
} LND_TracePartObserverOp;

typedef struct lnd_trace_part_observer
{
  void  (*tp_packet_sel) (LND_TracePart *tp, int index);
  void  (*tp_packet_unsel) (LND_TracePart *tp, int index);
  void  (*tp_sel_clr) (LND_TracePart *tp);
  void  (*tp_sel_all) (LND_TracePart *tp);
  void  (*tp_sel_del) (LND_TracePart *tp);
  void  (*tp_dirty_state) (LND_TracePart *tp);

} LND_TracePartObserver;




/**
 * libnd_tp_new - creates a new trace part.
 * @tpm: TPM for this part.
 * @parent: trace part that this new part starts upon.
 * @start_offset: offset into @parent where new part starts.
 *
 * The function creates and returns a new trace part, sitting on
 * top of @parent, starting at @start_offset. For the base part,
 * the parent is %NULL.
 *
 * Returns: new trace part, or %NULL on error.
 */
LND_TracePart     *libnd_tp_new(LND_TPM *tpm, LND_TracePart *parent, off_t start_offset);


/**
 * libnd_tp_free - releases a trace part's memory.
 * @tp: trace part to free.
 *
 * The function releases the memory occupied by the trace part
 * pointed to by @tp.
 */
void               libnd_tp_free(LND_TracePart *tp);


/**
 * libnd_tp_set_input_file - sets a trace part's input file.
 * @tp: trace part to set input for.
 * @filename: filename of the input trace part.
 *
 * This function specifies the input trace file for @tp.
 * For a TPM's base trace, this is the original input trace.
 *
 * Returns: %TRUE when successful, %FALSE otherwise.
 */
gboolean           libnd_tp_set_input_file(LND_TracePart *tp, const char *filename);


/**
 * libnd_tp_set_output_file - sets a trace part's output file.
 * @tp: trace part to set output for.
 * @filename: name of output trace file.
 *
 * The function sets the output trace file name for @tp to
 * @filename. This means that when @tp's packets are written
 * out to disk, @filename will be used.
 */
gboolean           libnd_tp_set_output_file(LND_TracePart *tp, const char *filename);


/**
 * libnd_tp_find_part_after_offset - tries to find the next part starting after a given offset.
 * @tp: trace part to query.
 * @offset: offset after which to look.
 * @tp_dontuse: last trace part, must not be used. Can be %NULL.
 *
 * In a scenario of multiple trace parts piled onto each other, the function
 * finds the first trace part that sits upon the given one, starting at or
 * after the offset given. If you want to make sure that a certain trace part
 * is not selected (like the most recent one used), pass it as @tp_last.
 *
 * Returns: found trace part, or %NULL if no such part exists.
 */
LND_TracePart     *libnd_tp_find_part_after_offset(const LND_TracePart *tp,
						   off_t offset,
						   const LND_TracePart *tp_dontuse);


/**
 * libnd_tp_write_packet - writes a single packet to the output trace associated with a trace part.
 * @tp: trace part whose output trace to use.
 * @packet: packet to dump.
 *
 * The function dumps the single given @packet to the output trace file
 * currently associated with @tp.
 */
void               libnd_tp_write_packet(LND_TracePart *tp, const LND_Packet *packet);


/**
 * libnd_tp_set_dirty - marks/clears a trace part as being dirty.
 * @tp: trace part to mark.
 * @dirty: modification status to set to.
 *
 * The function sets the modification status of @tp to @dirty.
 */
void               libnd_tp_set_dirty(LND_TracePart *tp, gboolean dirty);


/**
 *libnd_tp_init_packets - initializes loaded packets.
 * @tp: part whose loaded packets to initialize.
 * 
 * The function initializes all packets belonging to @tp and
 * loaded into memory (using libnd_tpm_load_packets()).
 */
void               libnd_tp_init_packets(LND_TracePart *tp);

/**
 * libnd_tp_insert_packets - insert one or more packets into a trace part.
 * @tp: part to add packet to.
 * @packet: first of a chain of packets to add.
 * @index: where to insert @packet.
 *
 * The function adds the chain of packets starting at @packet to
 * @tp at @index. The chain of packets is followed until a packet's
 * next pointer is %NULL, so make sure that last next pointer is
 * correct. If @index is < 0 or larger than the number of
 * packets currently in the trace part, the packet is added at the
 * end. Counting starts at zero, and the index is the index the packet
 * will have when it is inserted. No limit checking is
 * done; a trace part can grow arbitrarily large this way.
 */
void               libnd_tp_insert_packets(LND_TracePart *tp,
					   LND_Packet *packet,
					   int index);

/**
 * libnd_tp_remove_packet - removes a packet at a given index.
 * @tp: trace part.
 * @index: index of the packet in the trace part.
 *
 * The function removes the packet at @index in @tp from @tp
 * and returns the packet.
 *
 * Returns: removed packet, or %NULL on error.
 */
LND_Packet        *libnd_tp_remove_packet(LND_TracePart *tp, int index);


/**
 * libnd_tp_sync - writes all in-memory packets out to disk.
 * @tp: trace part to sync.
 *
 * The function writes all packets the trace part has currently
 * loaded into memory out to disk, using the currently existing
 * output trace. After that, the input trace file is adjusted
 * so that when packets are read from @tp, the trace part that
 * this function wrote packets into is used.
 */
void               libnd_tp_sync(LND_TracePart *tp);


/**
 * libnd_tp_clear_packetlists - resets in-memory packet data structures.
 * @tp: trace part to reset.
 * 
 * The function resets the internal loaded packet and selected
 * packet lists.
 *
 * Returns: first of the currently loaded packets (no longer
 * associated with @tp!).
 */
LND_Packet        *libnd_tp_clear_packetlists(LND_TracePart *tp);


/**
 * libnd_tp_move_packet - moves packet around in a trace part.
 * @tp: trace part.
 * @from_index: index of packet to move.
 * @to_index: index to move packet to.
 *
 * This function moves a single packet around in the trace part.
 */
void               libnd_tp_move_packet(LND_TracePart *tp,
					int from_index,
					int to_index);


/**
 * libnd_tp_packet_get_nth - returns nth packet in trace part.
 * @tp: trace part.
 * @n: index of packet to return.
 *
 * This function returns the nth packet of the trace part,
 * if possible, %NULL otherwise.
 *
 * Returns: packet.
 */
LND_Packet        *libnd_tp_packet_get_nth(const LND_TracePart *tp, int n);


/**
 * libnd_tp_clear_selection - clears the selection in a trace part.
 * @tp: trace part to clear selection of.
 * 
 * The function clears the selection of any in-memory packets of
 * the trace part pointed to by @tp.
 */
void               libnd_tp_clear_selection(LND_TracePart *tp);

/**
 * libnd_tp_full_selection - selectes all in-memory packets of a trace part.
 * @tp: trace part to select packets of.
 *
 * The function selectes all in-memory packets of the trace part
 * pointed to by @tp.
 */
void               libnd_tp_full_selection(LND_TracePart *tp);

/**
 * libnd_tp_select_packet - selects a packet in the tpm
 * @tp: trace part.
 * @index: index of packet to select.
 *
 * The function selects the indicated packet and marks it as the
 * currently selected one.
 *
 * Returns: selected packet.
 */
LND_Packet        *libnd_tp_select_packet(LND_TracePart *tp, int index);

/**
 * libnd_tp_unselect_packet - unselects a packet in the tpm.
 * @tp: trace part.
 * @index: index of packet to unselect.
 *
 * The function unselects the indicated packet in the trace part.
 *
 * Returns: unselected packet.
 */
LND_Packet        *libnd_tp_unselect_packet(LND_TracePart *tp, int index);


/**
 * libnd_tp_get_sel_size - returns number of selected packets.
 * @tp: trace part.
 *
 * The function returns the number of packets currently
 * selected in @tp.
 *
 * Returns: number of packets.
 */
guint              libnd_tp_get_sel_size(LND_TracePart *tp);


/**
 * libnd_tp_sel_delete - deletes currently selected packets.
 * @tp: trace part.
 *
 * The function deletes the selected packets from @tp.
 */
void               libnd_tp_sel_delete(LND_TracePart *tp);

/**
 * libnd_tp_sel_filter - filters currently selected packets.
 * @tp: trace part.
 *
 * The currently selected packets are filtered.
 */
void               libnd_tp_sel_filter(LND_TracePart *tp);

/**
 * libnd_tp_sel_unfilter - unfilter currently selected packets.
 * @tp: trace part.
 *
 * The function unfilters packets in the current selection.
 */
void               libnd_tp_sel_unfilter(LND_TracePart *tp);


/* ---------------------------- Trace Part Observers ----------------------------- */

/**
 * libnd_tp_observer_new - creates new trace observer.
 *
 * The function allocates a new, empty trace observer. You should
 * then fill in callbacks for the events you're interested in,
 * and register the thing using libnd_tp_add_observer().
 *
 * Returns: new observer.
 */
LND_TracePartObserver *libnd_tp_observer_new(void);

/**
 * libnd_tp_observer_free - deleted trace observer.
 * @ob: observer to delete.
 * 
 * The function releases all memory associated with @ob.
 */
void               libnd_tp_observer_free(LND_TracePartObserver *ob);


/**
 * libnd_tp_add_observer - registers a new trace observer.
 * @ob: new observer to register.
 *
 * The function registers the new observer for notifications about
 * future changes to traces.
 */
void               libnd_tp_add_observer(LND_TracePartObserver *ob);

/**
 * libnd_tp_del_observer - deletes a trace observer.
 * @ob: observer to drop.
 *
 * The function stops trace operations from being reported to
 * @ob. It does not release @ob's memory, use libnd_tp_observer_free()
 * for that. 
 */
void               libnd_tp_del_observer(LND_TracePartObserver *ob);

/**
 * libnd_tp_tell_observer - push operations to registered observers.
 * @trace: trace to report operation on.
 * @op: operation type.
 *
 * The function reports the given operation on the given trace to all
 * registered observers.
 */
void               libnd_tp_tell_observers(LND_TracePart *trace,
					   LND_TracePartObserverOp op,
					   void *data);



#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif

