/////////////////////////////////////////////////////////////////////////////
//
//  Copyright (C) 1997, Microsoft Corporation.  All Rights Reserved.
//
/////////////////////////////////////////////////////////////////////////////
//#include "stdafx.h"

#include "pch.cxx"

#include "BSDict.h"
#ifdef _INSTRUMENT
#include "clog.h"
#endif

#include "Hash.h"
static    CWordHash    wordHash;

BYTE CDoubleFileBSDict::lpBuffer[MAX_BUFFER_SIZE];
BYTE *CDoubleFileBSDict::lpCurIndex;

void CDoubleFileBSDict::LoadIndex(HANDLE hInput)
{
    DWORD    readBytes;
//    _ASSERT(hInput != NULL);

    // read index header
    LoadIndexHeader(hInput);

    // Alloc indexes
    hIndex = GlobalAlloc(GPTR, GetIndexSize() * GetNumOfBlocks());
    Assert( hIndex != NULL );
    lpIndex = (BYTE *)GlobalLock(hIndex);
    Assert( lpIndex != NULL);
    // read indexes
    ReadFile(hInput, lpIndex, GetIndexSize() * GetNumOfBlocks(), &readBytes, NULL);
}

void CDoubleFileBSDict::LoadIndexHeader(HANDLE hInput)
{
    DWORD readBytes;
    ReadFile(hInput, m_pIndexHeader, sizeof(_IndexHeader), &readBytes, NULL);
//    _ASSERT(readBytes == sizeof(_IndexHeader));
}

int CDoubleFileBSDict::FindWord(HANDLE hDict, DWORD fpBlock, LPCTSTR lpStr)
{
    int indexNum;
    BYTE pumsa = 0;
    DWORD readBytes;
    int  numWords, wordNum;
    static int      curBufferWordLen, curBufIndexNum;


//#ifdef _INSTRUMENT
//numOfComp =0;
//#endif

    indexNum =  FindIndex(lpStr, 0, GetNumOfBlocks()-1, &pumsa);

    if (pumsa) return pumsa;
    else {
        // Search Cache Block
    #ifdef _INSTRUMENT
        _Log.IncreaseTotalAccess(lpStr);
    #endif
        if (wordHash.Find(lpStr, &pumsa)==TRUE) {
        #ifdef _INSTRUMENT
            _Log.IncreaseHit();
        #endif
            if (pumsa)    // if word found in cache
                return pumsa;
            else return 0;
        } else {
            // Check if aleady in buffer
            if ( (curBufferWordLen == GetWordLen()) && (curBufIndexNum == indexNum) )
            #ifdef _INSTRUMENT
                _Log.IncreaseHit();
            #else
                ;
            #endif
            else {
                // read a candidate block 
                SetFilePointer(hDict, fpBlock + indexNum*GetBlockSize(), 0, FILE_BEGIN);
                ReadFile(hDict, lpBuffer, GetBlockSize(), &readBytes, 0);
                curBufferWordLen = GetWordLen(); curBufIndexNum = indexNum;
                #ifdef _INSTRUMENT
                    _Log.IncreaseFail();
                #endif
            }
        }
        numWords = *(WORD*)(lpCurIndex+GetIndexSize() - sizeof(WORD));
        if ( (wordNum = FindBlock(lpStr, 0, numWords-1))!=-1) {
            pumsa = *(lpBuffer+numWords*GetWordByteLen() + wordNum);
            //
            wordHash.Add(lpStr, pumsa);
            // 
            return pumsa;
        }
        else {
            wordHash.Add(lpStr, pumsa);
            return 0;
        }
    }
    return 0;
}

int CDoubleFileBSDict::FindIndex(LPCTSTR lpWord, int left, int right, BYTE *pumsa)
{
    int middle, flag;
    
    while (left < right) {
        middle = (left+right)>>1;
        lpCurIndex = lpIndex + middle * GetIndexSize();
        switch ( (flag = Comp(LPCTSTR(lpCurIndex), lpWord)) ) {
        case -1 : left = middle + 1;
                  break;
        case  0 : *pumsa = *(lpCurIndex + GetWordByteLen());
                  return middle;
        case  1 : right = middle - 1;
        }
    }
    
    lpCurIndex = lpIndex + left * GetIndexSize();
    if ( (flag = Comp(LPCTSTR(lpCurIndex), lpWord)) == 0) {
        *pumsa = *(lpCurIndex + GetWordByteLen());
        return left;
    }

    if (left && flag==1) {
        lpCurIndex -= GetIndexSize();
        return left-1;
    } else 
        return left;
}

int CDoubleFileBSDict::FindBlock(LPCTSTR lpWord, int left, int right)
{
    int middle;

    while (left <= right) {
        middle = (left+right)>>1;
        switch ( Comp(LPCTSTR(lpBuffer+middle*GetWordByteLen()), lpWord) ) {
        case -1 : left = middle + 1;
                  break;
        case  0 : return middle;
        case  1 : right = middle - 1;
        }
    }
    return -1;
}