#ifndef __COMMON_H
#define __COMMON_H

/******************************************************************************
 * Constants                                                                  *
 ******************************************************************************/

/* #define MAX_LINE_LENGTH 65536 */
#define MAX_LINE_LENGTH 1000

#define INVALID_TAG (-1)
#define CONN        2*1024

/******************************************************************************
 * Data Structures                                                            *
 ******************************************************************************/

   /***************************************************************************
    * 1) The number of the requests should not exceed the range of this type, *
    *    otherwise, it is needed to change to "long" or "long long";          *
    * 2) Do not use "unsigned" because some negative values are used for tags *
    *    or something, for example: INVALID_TAG = -1                          *
    ***************************************************************************/
typedef long long INT;

   /***************************************************************************
    * An object is identified by a URL which is in the format of "server+path"*
    ***************************************************************************/
typedef struct object_id {
    INT server;
    INT path;
} OBJECT_ID;

   /***************************************************************************
    * This type is used to define the array of requests. This array holds all *
    * the requests read from the trace file. Later on, fgets can be avoid.    *
    ***************************************************************************/
typedef struct request { /* array of requests; used to avoid fgets */
    OBJECT_ID object;
    INT size;
    INT cost;
    INT last_modify;

    /* Used in the Italian algorithm */
    INT time;  /* time of access */
    INT count; /* this is the count'th access to the object */

} REQUEST;

   /***************************************************************************
    * record for every object *in cache*                                      *
    ***************************************************************************/
typedef struct object_in_cache {
    OBJECT_ID object;
    INT size;
    INT hash_index; /* the index of the all-object array where it is in */

    INT frequency; /* used mainly in Hybrid */
    INT time;      /* time of last access; used in Italian */

    /* Fields used for linking up the objects in a sorted list */
    /* LRU, LFU, SIZE, Italian etc will use this kind of sorted list as cache */
    INT primary_key;
    INT secondary_key;
    struct object_in_cache *previous;
    struct object_in_cache *next;

} OBJECT_IN_CACHE;

   /****************************************************************************
    * This is the type of the node that the hash table used. The node must have*
    * at least these fields:  primary_key, secondary_key, *previous, *next     *
    ***************************************************************************/
#define NODE_TYPE  OBJECT_IN_CACHE

   /****************************************************************************
    * Each request fetchs one object. All the unique requests seen in the trace*
    * will be kept in a hash table. This is the type of the hash table elements*
    ***************************************************************************/
typedef struct object_in_hash_table {
    OBJECT_ID object;
    INT size;           /* last seen size of this object */
    INT last_modify;    /* last modified time of this object */
    INT clashed_next;   /* the hash index of the next clashed element */
    INT in_which_cache; /* used in the partition-cache */
    OBJECT_IN_CACHE *position_in_cache; /* if not NULL, means this object is */
                                        /* currently in cache, and it points */
                                        /* to the object in the cache */
} OBJECT_IN_HASH_TABLE;

   /****************************************************************************
    * Algorithms will use this structure to record the statistic of the misses *
    ***************************************************************************/
typedef struct miss_info {
    INT miss_count;
    double missed_bytes;
    double missed_packets;
    double missed_cost;
    double missed_hops;
    double missed_weightedhops;
} MISS_INFO;


/******************************************************************************
 * Global Variables                                                           *
 ******************************************************************************/
extern FILE *fpout;

extern INT Echo, From, To, Step;
extern INT AveConnect;

extern INT    TotalRequests; /* the actual total number of requests */
extern INT    UniqueRequests;
extern double TotalCost, TotalBytes, TotalPackets;
extern double UniqueCost, UniqueBytes, UniquePackets;

double InfCacheHitRate, InfCacheByteHitRate, InfCacheReducedLatency,
       InfCacheReducedPackets;

extern REQUEST *RequestsTable; /* An array holding all the requests read from */
                               /* the trace file. Avoid fgets later on */

extern OBJECT_IN_HASH_TABLE *ObjectsHashTable; /* An array indicating the */
                                               /* state of all objects */


/******************************************************************************
 * Global Functions                                                           *
 ******************************************************************************/

extern void print_hash_table();
extern void init_objects_hash_table(INT size);
extern INT find_object_in_hash_table(OBJECT_ID object);
extern INT add_object_into_hash_table(OBJECT_ID obj, INT size, INT last_modify);
extern INT reset_the_field_of_position_in_cache();

extern NODE_TYPE *create_a_new_node();
extern void init_sorted_list(NODE_TYPE **head);
extern void add_node_into_sorted_list(NODE_TYPE *head, NODE_TYPE *new_node);
extern void remove_node_from_sorted_list(NODE_TYPE *head, NODE_TYPE *node);
extern NODE_TYPE *remove_last_node_from_sorted_list(NODE_TYPE *head);
extern INT  release_sorted_list(NODE_TYPE **head);
extern void print_sorted_list(NODE_TYPE *head);

extern void cache_LRU(INT size, INT threshold);
extern void cache_LFU(INT size, INT threshold);
extern void cache_SIZE(INT size, INT threshold);
extern void cache_PARTITIONING(INT size, float partition_ratio, INT threshold,
                      INT upgrading_threshold, INT window_size, INT throw_away);

extern void do_other_cache_simulation_according_to_the_script_file(FILE *fp);


/*** Macros ******************************************************************/

#define PR_REQUEST(request) \
        /* fprintf(stderr, "%9lld %9lld %9lld %9lld %9lld %9lld\n", \
                request.object.server, request.object.path, request.size, \
                request.cost, request.last_modify,   request.time  );
         */ \
        printf("%20lld %9lld %9lld\n", \
                request.object.server, request.size, request.last_modify );

#define ERROR_LOG(string)  fprintf(stderr, string)

#define IF_OUT_OF_MEM(Pointer, Pointer_name) \
{ \
    if (Pointer==NULL) { \
        fprintf(stderr, \
                "\nError: out of memory when allocating memory for '%s'!\n\n", \
                Pointer_name); \
        exit(-1); \
    } \
}

#define SAME_OBJECT(OBJ1,OBJ2)  (OBJ1.server==OBJ2.server&&OBJ1.path==OBJ2.path)
#define SET_OBJECT(OBJ1,OBJ2)   {OBJ1.server=OBJ2.server; OBJ1.path=OBJ2.path;}

#define IF_OBJECT_CHANGED(obj1, obj2)                     \
        if ( (obj1.size != obj2.size)                     \
             ||                                           \
             (obj1.last_modify!=0 && obj2.last_modify!=0  \
              && obj1.last_modify!=obj2.last_modify)      \
           )

#define GET_PACKET(size)  (2 + ((INT)(size/536)) )

#endif

