// Copyright (C) 1997 Microsoft Corporation. All rights reserved.

#if _MSC_VER > 1000
#pragma once
#endif

#ifndef __SUBFILE_H__
#define __SUBFILE_H__

#include "hhtypes.h"

// we have three possible caching schemes:

// HH_FAST_CACHE - fast but its a hog!
//
// We store a small number of pages (2-3) for each unique
// title and subfile combination.  This results is quite of bit
// of memory being used per collection but oh boy is it fast!
//
//#define HH_FAST_CACHE

// HH_EFFICIENT_CACHE - slow but it saves memory!
//
// We store a small number of moderate pages (2-3) for each unique
// subfile regardless of the title it came from.  This results in an
// efficient use of memory since like subfiles, such as #TOCIDX, share
// the same group of cache pages instead of having their own uniqe group
// per title.  However, this method slows things down since multiple reads
// from the same named subfile accross several titles results in many
// cache misses.
//
//#define HH_EFFICIENT_CACHE

// HH_SHARED_CACHE - nice balance of speed and size!
//
// We store a large number of pages (16+) for the entire collection.
// This result is a fixed quantity of cache pages regardless of number
// and type of subfiles we have.  It utilizes memory well since we can
// access multiple subfiles of the same name accross several titles
// effectively yielding a larger pool of cache pages.
//
// [paulti] - We want to use this method exclusively.  Please see me
//            if you want to change this for any reason.
//
#define HH_SHARED_CACHE

#if defined ( HH_FAST_CACHE )
#define CACHE_PAGE_COUNT 3
#elif defined ( HH_EFFICIENT_CACHE )
#define CACHE_PAGE_COUNT 5
#else // HH_SHARED_CACHE
#define CACHE_PAGE_COUNT 32
#endif

class CSubFileSystem;
class CExTitle;

typedef struct page {
    CExTitle* pTitle;
    DWORD     dwPage;
    HASH      hashPathname;
    DWORD     dwLRU;
    BYTE      rgb[PAGE_SIZE];
} PAGE;

//////////////////////////////////////////////
//
//  CPagesList
//
//////////////////////////////////////////////

class CPagesList
{
    friend class CPagedSubfile;
    friend class CPages;

public:
    CPagesList() { m_pFirst = 0; }
    ~CPagesList();

private:
    CPages* m_pFirst;
    CPages* GetPages( HASH );

};

////////////////////////////////////////
//
//  CPages
//
////////////////////////////////////////

class CPages
{
public:
    void  Flush( CExTitle* pTitle );

private:
    CPages( HASH );

    void* Find( const CExTitle *, HASH, DWORD );
    void* Alloc( CExTitle *, HASH, DWORD );
    void  Flush( void );

    CPages* m_pNext;
    HASH           m_hash;
    DWORD          m_dwLRUPage;
    DWORD          m_dwLRUCount;
    PAGE           m_pages[CACHE_PAGE_COUNT];

    friend class CPagedSubfile;
    friend class CPagesList;
};

//////////////////////////////////////////////
//
//  CPagedSubfile
//
//////////////////////////////////////////////

class CPagedSubfile
{
public:
   CPagedSubfile();
   ~CPagedSubfile();

   HRESULT Open(CExTitle *, LPCSTR);

   void* Offset(DWORD dwOffs);
   void* Page(DWORD iPage);

private:
   CSubFileSystem* m_pCSubFileSystem;
   CExTitle*       m_pTitle;
   HASH            m_hashPathname;
   HASH            m_hash;
   DWORD           m_cbSize;
   CPages*  m_pPages;
};

#endif
