// cache.h

#ifndef CACHE_H
#define CACHE_H

#include <stdlib.h>
#include "Request.h"
#include "DecRequest.h"
#include "cacheEntry.h"

enum RequestType {unknown, hit, miss, refreshHit, refreshMiss, icpHit, clientRefresh, imsHit, imsMiss};

// hit means this should be credited with a hit - the proxy did not
//   consult the server at all.
// miss means the proxy was forced to consult the server
// unknown means the program could not figure out how to classify the request
// error means the cache knows for certain the request contains an HTTP error
enum SimulationResult {simUnknown, simError, simHit, simMiss};

/*
struct Request {
  RequestType type;
  int requestCode;
  long time; // ms since 1970
  char * url;
  int size;
};
*/

const float HIGH_WATER_RATIO = .95f;

class CacheIterator;

class Cache {
  // CacheIterator needs to step through cacheArray.
    friend class CacheIterator;

  private:
    long long maxSize; // how many bytes the cache can occupy
    long long currentSize; // how many bytes the cache currently occupies
    long long highWater; // clean when currentSize >= highWater
    long hashTableBits; // 2^hashTableBits = size of hash table
    CacheEntry ** cacheArray; // hashTable
    CacheEntry * findEntry(long hash); 
    void addEntry(unsigned long lastRefresh, unsigned long lastRequest, unsigned long hash, int size, unsigned long lastModified = 0);
    void deleteEntry(unsigned long hash);
    void clean(); 
    unsigned long hashBig(char * urlString); 
    unsigned int hashSmall(unsigned long hash); 

    // hash is the hash of req.url.  cacheEntry must be a ptr to the
    // entry for hash if one exists.  Positively or negatively
    // caches req, or ignores it according to the req.httpResult.
    int considerCaching(unsigned long hash, CacheEntry* cacheEntry, SquidRequest& req);

  public:
    // Create a cache that will hold up to maxSize worth of data, 
    // that will take up 1<<hashTableBits worth of memory
    Cache(long long maxSize, int hashTableBits);

    // Destrutor
    ~Cache();

    // The number of bytes stored in the cache.
    long long getCurrentSize();

    // Process Request req in the cache and return the result as a 
    // RequestType
    SimulationResult processRequest(SquidRequest req);

    // Process req in the cache and return the result as a RequestType
    SimulationResult processRequest(DecRequest req);
};

#endif
