/*TITLE implementation of logical layer classes*/

/****keyword-flag*** "%v %f %n" */
/* "9 11-May-98,18:38:46 NEWQUANT.CPP" */

#include "common.h"

FreeSpaceArrayPtr::FreeSpaceArrayPtr()
{
    m_FSA = new FreeSpaceArray;
    m_FSA->m_ReferenceCount = 1;
}

FreeSpaceArrayPtr::FreeSpaceArrayPtr(QuantumFile *p_QuantumFile)
{
    m_FSA = new FreeSpaceArray(p_QuantumFile);
    m_FSA->m_ReferenceCount = 1;
}


FreeSpaceArrayPtr::FreeSpaceArrayPtr(const FreeSpaceArrayPtr& p_FSAP)
{
    m_FSA = p_FSAP.m_FSA;
    m_FSA->m_ReferenceCount++;
}


FreeSpaceArrayPtr::FreeSpaceArray *FreeSpaceArrayPtr::operator->()
{
    return m_FSA;
}

FreeSpaceArrayPtr& FreeSpaceArrayPtr::operator=(const FreeSpaceArrayPtr& p_FSAP)
{
    m_FSA->m_ReferenceCount--;
    if (m_FSA->m_ReferenceCount <= 0 && m_FSA != p_FSAP.m_FSA)
        delete m_FSA;
    m_FSA = p_FSAP.m_FSA;
    m_FSA->m_ReferenceCount ++;
    return *this;
}

FreeSpaceArrayPtr::~FreeSpaceArrayPtr()
{
    m_FSA->m_ReferenceCount --;
    if (m_FSA->m_ReferenceCount <= 0)
        delete m_FSA;
}

FreeSpaceArrayPtr::FreeSpaceArray::FreeSpaceArray():
m_FreeSpaceListCount(0),
m_FreeSpaceListBlockCount(0),
m_CurrentLowestFreeBlock(0),
m_QuantumBlockNumberAdjustment(0)
{
}

FreeSpaceArrayPtr::FreeSpaceArray::~FreeSpaceArray()
{
}

FreeSpaceArrayPtr::FreeSpaceArray::FreeSpaceArray(QuantumFile *p_MRU)
{
    ArrayIndex i;

    m_CurrentLowestFreeBlock = 0;
    m_FreeSpaceListCount = p_MRU->QGetFreeSpaceListCount();
    m_FreeSpaceListBlockCount = p_MRU->QGetFreeSpaceListBlockCount();
    m_QuantumBlockNumberAdjustment = p_MRU->GetQuantumNumberAdjustment();
    m_BlockPtr.SetSize(p_MRU->QGetFreeSpaceListBlockCount());
    for (i = 0; i < m_BlockPtr.GetSize(); i ++)
        m_BlockPtr[i] = p_MRU->MakeFreeSpaceBlockPtr(i);
}

QFreeSpaceEntry FreeSpaceArrayPtr::FreeSpaceArray::Get(ArrayIndex p_Index)
{
    ArrayIndex Block;
    ArrayIndex Element;
    QFreeSpaceEntry Result;

    if (p_Index >= m_FreeSpaceListCount)
        {
        Result.m_ObjectNumber = 0;
        Result.m_FreeSpaceCode = 0;
        return Result;
        }

    Block = p_Index / FreeSpaceEntriesPerBlock;
    Element = p_Index % FreeSpaceEntriesPerBlock;
    Result = m_BlockPtr[Block]->Get(Element);

    return Result;
}

void FreeSpaceArrayPtr::FreeSpaceArray::Set(ArrayIndex p_Index, 
    QFreeSpaceEntry p_Entry)
{
    ArrayIndex Block;
    ArrayIndex Element;
    
    if (p_Index >= m_FreeSpaceListCount)
        return; // can't store off the end

    Block = p_Index / FreeSpaceEntriesPerBlock;
    Element = p_Index % FreeSpaceEntriesPerBlock;
    m_BlockPtr[Block]->Set(Element, p_Entry);
    if ((p_Entry.m_FreeSpaceCode == AvailableQuantum)
        && (p_Index < m_CurrentLowestFreeBlock))
            m_CurrentLowestFreeBlock = p_Index;

    return;
}

QuantumNumber FreeSpaceArrayPtr::FreeSpaceArray::FindEmptyBlock()
{
    ArrayIndex Block;
    ArrayIndex Element;
    ArrayIndex Result = BadArrayIndex;

    Block = m_CurrentLowestFreeBlock / FreeSpaceEntriesPerBlock;
    Element = m_CurrentLowestFreeBlock % FreeSpaceEntriesPerBlock;
    for (; Block < m_FreeSpaceListBlockCount; Block ++)
        {
        for (; Element < FreeSpaceEntriesPerBlock; Element ++)
            {
            if (m_BlockPtr[Block]->Get(Element).m_FreeSpaceCode
                == AvailableQuantum)
                {
                Result = Block * FreeSpaceEntriesPerBlock + Element;
                break;
                }
            }
        if (Result != BadArrayIndex)
            break;
        Element = 0;
        }

    m_CurrentLowestFreeBlock = Result;

    return Result;
}


QuantumNumber FreeSpaceArrayPtr::FreeSpaceArray::FindSpaceForItem(
    ObjectNumber p_ObjectNumber, ArrayIndex p_ItemSize)
{
    ArrayIndex Block;
    ArrayIndex Element;
    ArrayIndex Result = BadArrayIndex;
    ArrayIndex ItemSizeCode = p_ItemSize / FreeSpaceConversion;
    QFreeSpaceEntry TempFreeSpaceEntry;
    LeafBlockPtr TempLeafBlockPtr;

    for (Block = 0; Block < m_FreeSpaceListBlockCount; Block ++)
        {
        for (Element = 0; Element < FreeSpaceEntriesPerBlock; Element ++)
            {
            TempFreeSpaceEntry = m_BlockPtr[Block]->Get(Element);
            if (TempFreeSpaceEntry.m_FreeSpaceCode == AvailableQuantum)
                {
                TempFreeSpaceEntry.m_ObjectNumber = p_ObjectNumber;
                m_BlockPtr[Block]->Set(Element,TempFreeSpaceEntry);
                Result = Block * FreeSpaceEntriesPerBlock + Element;
                TempLeafBlockPtr = 
                    m_BlockPtr[Block]->MakeLeafBlockPtr(Result);
                TempLeafBlockPtr->Clear();
                TempLeafBlockPtr->SetQuantumType(LEAF_NODE);
                TempLeafBlockPtr->SetMainObjectNumber(p_ObjectNumber);
                break;
                }
            if (TempFreeSpaceEntry.m_ObjectNumber == p_ObjectNumber && 
              TempFreeSpaceEntry.m_FreeSpaceCode > ItemSizeCode)
                {
                Result = Block * FreeSpaceEntriesPerBlock + Element;
                TempLeafBlockPtr = 
                    m_BlockPtr[Block]->MakeLeafBlockPtr(Result);
                if (TempLeafBlockPtr->CalculateFreeSpace() > p_ItemSize)
                    break;
                else
                    Result = BadArrayIndex;
                }
            }
        if (Result != BadArrayIndex)
            break;
        }

    return Result;
}

MainObjectArrayPtr::MainObjectArrayPtr()
{
    m_MOA = new MainObjectArray;
    m_MOA->m_ReferenceCount = 1;
}


MainObjectArrayPtr::MainObjectArrayPtr(QuantumFile *p_QuantumFile)
{
    m_MOA = new MainObjectArray(p_QuantumFile);
    m_MOA->m_ReferenceCount = 1;
}


MainObjectArrayPtr::MainObjectArrayPtr(const MainObjectArrayPtr& p_MOAP)
{
    m_MOA = p_MOAP.m_MOA;
    m_MOA->m_ReferenceCount++;
}


MainObjectArrayPtr::MainObjectArray *MainObjectArrayPtr::operator->()
{
    return m_MOA;
}

MainObjectArrayPtr& MainObjectArrayPtr::operator=(const MainObjectArrayPtr& p_MOAP)
{
    m_MOA->m_ReferenceCount--;
    if (m_MOA->m_ReferenceCount <= 0 && m_MOA != p_MOAP.m_MOA)
        delete m_MOA;
    m_MOA = p_MOAP.m_MOA;
    m_MOA->m_ReferenceCount ++;
    return *this;
}

MainObjectArrayPtr::~MainObjectArrayPtr()
{
    m_MOA->m_ReferenceCount --;
    if (m_MOA->m_ReferenceCount <= 0)
        delete m_MOA;
}

MainObjectArrayPtr::MainObjectArray::MainObjectArray():
m_QuantumFile(0),
m_BlockPtr(ArrayIndex(0)),
m_MainObjectCount(0),
m_MainObjectBlockCount(0),
m_CurrentLowestFreeObject(0)
{
}

MainObjectArrayPtr::MainObjectArray::~MainObjectArray()
{
}

MainObjectArrayPtr::MainObjectArray::MainObjectArray(QuantumFile *p_MRU)
{
    ArrayIndex i;

    if (p_MRU)
        {
        m_QuantumFile = p_MRU;
        m_MainObjectCount = p_MRU->GetMainObjectCount();
        m_MainObjectBlockCount = p_MRU->GetMainObjectBlockCount();
        m_CurrentLowestFreeObject = 0;
        m_BlockPtr.SetSize(m_MainObjectCount);
        for (i = 0; i < m_BlockPtr.GetSize(); i ++)
            m_BlockPtr[i] = p_MRU->MakeMainObjectBlockPtr(i);
        }
}

MainObjectEntry MainObjectArrayPtr::MainObjectArray::Get(ArrayIndex p_Index)
{
    ArrayIndex Block;
    ArrayIndex Element;
    MainObjectEntry Result;

    if (p_Index >= m_MainObjectCount)
        return(NoObject); // say there's no space here

    Block = p_Index / MainObjectEntriesPerBlock;
    Element = p_Index % MainObjectEntriesPerBlock;
    Result = m_BlockPtr[Block]->Get(Element);

    return Result;
}

void MainObjectArrayPtr::MainObjectArray::Set(ArrayIndex p_Index, 
  MainObjectEntry p_Entry)
{
    ArrayIndex Block;
    ArrayIndex Element;
    
    if (p_Index >= m_MainObjectCount)
        return; // can't store off the end

    Block = p_Index / MainObjectEntriesPerBlock;
    Element = p_Index % MainObjectEntriesPerBlock;
    m_BlockPtr[Block]->Set(Element, p_Entry);
    if ((p_Entry == NoObject) && (p_Index < m_CurrentLowestFreeObject))
        m_CurrentLowestFreeObject = p_Index;

    return;
}

ObjectNumber MainObjectArrayPtr::MainObjectArray::FindObjectByName(
    ModifiableElement p_ObjectName)
{
    ObjectNumber i;
    ModifiableElement TempElement;

// note: there is no object numbered 0
    for (i = 1; i < m_MainObjectCount; i ++)
        {
        TempElement = GetModifiableElement(MainObjectDirectory,i);
        if (p_ObjectName == TempElement)
            return i;
        }
    return NoObject;
}


void MainObjectArrayPtr::MainObjectArray::CreateMainObject(
    ModifiableElement p_ObjectName, ObjectNumber p_ObjectNumber,
    ArrayIndex p_ElementCount, ArrayIndex p_MaxElementCount)
{
    QuantumNumber NewBigPointerQuantum;
    BigArrayHeader NewBigArrayHeader;
    SVector<QuantumNumber> NewBigPointerArray;
    SVector<ItemReference> NewLittlePointerArray;
    ArrayIndex LittlePointerBlockCount;
    ArrayIndex i;
    ArrayIndex NewQuantum;
    QFreeSpaceEntry TempFreeSpaceEntry;

    if (p_ElementCount == 0)
        p_ElementCount = 1;  // this is the simplest handling for 0-length arrays

    TempFreeSpaceEntry.m_ObjectNumber = p_ObjectNumber;
    TempFreeSpaceEntry.m_FreeSpaceCode = 0;
    NewBigPointerQuantum = m_QuantumFile->FindEmptyBlock();

    BigPointerBlockPtr NewBigPointerBlock =
        m_QuantumFile->MakeBigPointerBlockPtr(NewBigPointerQuantum);
    NewBigPointerBlock->Clear();
    NewBigPointerBlock->SetQuantumType(BIG_POINTER_ARRAY);
    NewBigPointerBlock->SetMainObjectNumber(p_ObjectNumber);
    NewBigArrayHeader.m_ElementCount = p_ElementCount;
    NewBigArrayHeader.m_MaxElementCount = p_MaxElementCount;
    NewBigArrayHeader.m_LastQuantumAddedTo = NoQuantum;
    
    NewBigPointerBlock->AddItem(&NewBigArrayHeader,
        sizeof(BigArrayHeader), BIG_ARRAY_HEADER, 0);
    
    LittlePointerBlockCount = (p_ElementCount-1)/ItemReferencesPerBlock + 1;
    NewBigPointerArray = SVector<QuantumNumber>(LittlePointerBlockCount);
    NewLittlePointerArray = SVector<ItemReference>(ItemReferencesPerBlock);

    for (i = 0; i < LittlePointerBlockCount; i ++)
        {
        NewQuantum = m_QuantumFile->FindEmptyBlock();
        m_QuantumFile->SetFreeSpace(NewQuantum,TempFreeSpaceEntry);
        NewBigPointerArray[i] = NewQuantum;

        LittlePointerBlockPtr NewLittlePointerBlock = 
           m_QuantumFile->MakeLittlePointerBlockPtr(NewQuantum);
        NewLittlePointerBlock->Clear();
        NewLittlePointerBlock->SetQuantumType(LITTLE_POINTER_ARRAY);
        NewLittlePointerBlock->SetMainObjectNumber(p_ObjectNumber);
        NewLittlePointerBlock->AddItem(NewLittlePointerArray.GetDataAddress(),
            NewLittlePointerArray.GetSize()*sizeof(ItemReference),
            LITTLE_POINTER_ARRAY,0);
        NewLittlePointerBlock->ClearLittleArray();
        m_QuantumFile->SetFreeSpace(NewQuantum,TempFreeSpaceEntry);
        }

    NewBigPointerBlock->AddItem(NewBigPointerArray.GetDataAddress(),
        NewBigPointerArray.GetSize()*sizeof(QuantumNumber),
        BIG_POINTER_ARRAY,0);
    
    m_QuantumFile->SetFreeSpace(NewBigPointerQuantum,TempFreeSpaceEntry);
    Set(p_ObjectNumber,NewBigPointerQuantum);
    PutElement(MainObjectDirectory, p_ObjectNumber, p_ObjectName);
}


ArrayIndex MainObjectArrayPtr::MainObjectArray::GrowMainObject(
    ObjectNumber p_ObjectNumber, ArrayIndex p_NewElementCount)
{
    MainObjectEntry BPAQuantumNumber;
    BigPointerBlockPtr BigPointerBlock;
    LittlePointerBlockPtr NewLittlePointerBlock;
    SVector<ItemReference> NewLittlePointerArray;
    BigPointerArray OldBigPointerArray;
    SVector<QuantumNumber> NewBigPointerArray;
    ArrayIndex NewLittlePointerBlockCount;
    ArrayIndex OldLittlePointerBlockCount;
    ArrayIndex i;
    ArrayIndex NewQuantum;
    QFreeSpaceEntry TempFreeSpaceEntry;
    ArrayIndex UpdatedElementCount;

    BPAQuantumNumber = Get(p_ObjectNumber);
    BigPointerBlock = m_QuantumFile->MakeBigPointerBlockPtr(BPAQuantumNumber);
    OldBigPointerArray = BigPointerBlock->GetBigPointerArray(); // big pointer array
    NewBigPointerArray = OldBigPointerArray;

    NewLittlePointerBlockCount = (p_NewElementCount-1)/ItemReferencesPerBlock + 1;
    UpdatedElementCount = NewLittlePointerBlockCount * ItemReferencesPerBlock;
    OldLittlePointerBlockCount = NewBigPointerArray.GetSize();
    if (NewLittlePointerBlockCount == OldLittlePointerBlockCount) // first overflow
        {
        BigPointerBlock->SetBigArrayElementCount(UpdatedElementCount);
        return UpdatedElementCount;
        }

    NewBigPointerArray.SetSize(NewLittlePointerBlockCount);
    BigPointerBlock->SetBigArrayElementCount(UpdatedElementCount);

    TempFreeSpaceEntry.m_ObjectNumber = p_ObjectNumber;
    TempFreeSpaceEntry.m_FreeSpaceCode = 0;

    NewLittlePointerArray = SVector<ItemReference>(ItemReferencesPerBlock);
    for (i = OldLittlePointerBlockCount; i < NewLittlePointerBlockCount; i ++)
        {
        NewQuantum = m_QuantumFile->FindEmptyBlock();
        m_QuantumFile->SetFreeSpace(NewQuantum,TempFreeSpaceEntry);
        NewBigPointerArray[i] = NewQuantum;
        NewLittlePointerBlock =
            m_QuantumFile->MakeLittlePointerBlockPtr(NewQuantum);
        NewLittlePointerBlock->Clear();
        NewLittlePointerBlock->SetQuantumType(LITTLE_POINTER_ARRAY);
        NewLittlePointerBlock->SetMainObjectNumber(p_ObjectNumber);
        NewLittlePointerBlock->AddItem(NewLittlePointerArray.GetDataAddress(),
            NewLittlePointerArray.GetSize()*sizeof(ItemReference),
            LITTLE_POINTER_ARRAY,0);
        NewLittlePointerBlock->ClearLittleArray();
        m_QuantumFile->SetFreeSpace(NewQuantum,TempFreeSpaceEntry);
        }
    BigPointerBlock->DeleteItem(2); // big pointer array
    BigPointerBlock->AddItem(NewBigPointerArray.GetDataAddress(),
        NewBigPointerArray.GetSize()*sizeof(QuantumNumber),
        BIG_POINTER_ARRAY,0);
    m_QuantumFile->SetFreeSpace(BPAQuantumNumber,TempFreeSpaceEntry);
    return UpdatedElementCount;
}


ObjectNumber MainObjectArrayPtr::MainObjectArray::FindAvailableObject()
{
    ArrayIndex Block;
    ArrayIndex Element;
    ObjectNumber Result = NoObject;

    Block = m_CurrentLowestFreeObject / MainObjectEntriesPerBlock;
    Element = m_CurrentLowestFreeObject % MainObjectEntriesPerBlock;
    for (; Block < m_MainObjectBlockCount; Block ++)
        {
        for (; Element < MainObjectEntriesPerBlock; Element ++)
            {
            if (m_BlockPtr[Block]->Get(Element) == NoObject)
                {
                Result = (ObjectNumber) 
                    (Block * MainObjectEntriesPerBlock + Element);
                break;
                }
            }
        if (Result != NoObject)
            break;
        }
    m_CurrentLowestFreeObject = Result;

    return Result;
}

ModifiableElement MainObjectArrayPtr::MainObjectArray::GetModifiableElement(
    ArrayIndex p_MainObjectNumber, ArrayIndex p_ElementIndex)
{
    MainObjectEntry BPAQuantumNumber;
    BigPointerBlockPtr BigPointerBlock;
    LittlePointerBlockPtr LittlePointerBlock;
    LeafBlockPtr ElementBlock;
    ArrayIndex BigPointerIndex;
    ArrayIndex LittlePointerIndex;
    QuantumNumber LPAQuantumNumber;
    ItemReference ElementRef;
    ModifiableElement Element;

    BPAQuantumNumber = Get(p_MainObjectNumber);

    BigPointerBlock =
        m_QuantumFile->MakeBigPointerBlockPtr(BPAQuantumNumber);

    BigPointerIndex = p_ElementIndex / ItemReferencesPerBlock;

    LPAQuantumNumber =
        BigPointerBlock->GetBigArrayElement(BigPointerIndex);

    LittlePointerBlock =
        m_QuantumFile->MakeLittlePointerBlockPtr(LPAQuantumNumber);

    LittlePointerIndex = p_ElementIndex % ItemReferencesPerBlock;
    ElementRef = LittlePointerBlock->GetLittleArrayElement(LittlePointerIndex);

    if (ElementRef.IsReference())
        {
        ElementBlock =
            m_QuantumFile->MakeLeafBlockPtr(ElementRef.GetQuantumNumber());

        Element =
            ElementBlock->GetModifiableItem(ElementRef.GetItemNumber());
        }
    else
        Element = ModifiableElement();

    return Element;
}

int MainObjectArrayPtr::MainObjectArray::PutElement(
    ObjectNumber p_MainObjectNumber, ArrayIndex p_ElementIndex, 
    ModifiableElement p_Element)
{
    MainObjectEntry BPAQuantumNumber;
    BigPointerBlockPtr BigPointerBlock;
    LittlePointerBlockPtr LittlePointerBlock;
    LeafBlockPtr ElementBlock;
    ArrayIndex BigPointerIndex;
    ArrayIndex LittlePointerIndex;
    QuantumNumber LPAQuantumNumber;
    ItemReference ElementRef;
    ItemReference NewElementRef;
    ModifiableElement Element;
    QFreeSpaceEntry SpaceAvailable;
    QuantumNumber NewQuantum;
    QuantumNumber PossibleQuantum;
    LeafBlockPtr NewElementBlock;
    ArrayIndex FreeSpace;
    ArrayIndex ActualFreeSpace;
    ArrayIndex NewItemNumber;
    ObjectNumber LeafObjectNumber;

    qfassert (p_Element.GetSize() < MaxItemSize);

    BigPointerIndex = p_ElementIndex / ItemReferencesPerBlock;

    BPAQuantumNumber = Get(p_MainObjectNumber);

    BigPointerBlock = m_QuantumFile->MakeBigPointerBlockPtr(BPAQuantumNumber);

    LPAQuantumNumber = BigPointerBlock->GetBigArrayElement(BigPointerIndex);

    LittlePointerBlock = 
        m_QuantumFile->MakeLittlePointerBlockPtr(LPAQuantumNumber);

    LittlePointerIndex = p_ElementIndex % ItemReferencesPerBlock;
    ElementRef = LittlePointerBlock->GetLittleArrayElement(LittlePointerIndex);

    if (ElementRef.IsReference())
        {
        ElementBlock = 
            m_QuantumFile->MakeLeafBlockPtr(ElementRef.GetQuantumNumber());
        ElementBlock->DeleteItem(ElementRef.GetItemNumber());
        }

    if (p_Element.GetSize() == 0) // nothing to store
        {
        ElementRef.SetQuantumNumber(NoQuantum);
        ElementRef.SetItemNumber(NoItem);
        LittlePointerBlock->SetLittleArrayElement(LittlePointerIndex,ElementRef);
        return 0;
        }

    NewQuantum = NoQuantum;
    PossibleQuantum = BigPointerBlock->GetLastQuantumAddedTo();
    if (PossibleQuantum != NoQuantum)
       {
       SpaceAvailable = m_QuantumFile->QGetFreeSpace(PossibleQuantum);
       FreeSpace = SpaceAvailable.m_FreeSpaceCode * FreeSpaceConversion;
       if (SpaceAvailable.m_FreeSpaceCode != AvailableQuantum &&
         FreeSpace > p_Element.GetSize())
        {
        NewElementBlock = m_QuantumFile->MakeLeafBlockPtr(PossibleQuantum);
        ActualFreeSpace = NewElementBlock->CalculateFreeSpace();
        if (ActualFreeSpace > p_Element.GetSize())
            NewQuantum = PossibleQuantum;
        }
       }

    if (NewQuantum == NoQuantum)
        {
        NewQuantum = m_QuantumFile->FindSpaceForItem(p_MainObjectNumber, 
            p_Element.GetSize());
        NewElementBlock = m_QuantumFile->MakeLeafBlockPtr(NewQuantum);
        LeafObjectNumber = NewElementBlock->GetMainObjectNumber();
        qfassert(LeafObjectNumber == p_MainObjectNumber);
        }

    BigPointerBlock->SetLastQuantumAddedTo(NewQuantum);
    NewElementRef.SetQuantumNumber(NewQuantum);

    NewItemNumber = NewElementBlock->AddItem(p_Element, 
        VARIABLE_LENGTH_STRING, p_ElementIndex);
    NewElementRef.SetItemNumber(NewItemNumber);

    LeafObjectNumber = NewElementBlock->GetMainObjectNumber();
    qfassert(LeafObjectNumber == p_MainObjectNumber);

    NewElementBlock->UpdateFreeSpace();

    LittlePointerBlock->SetLittleArrayElement(LittlePointerIndex,NewElementRef);

    return 0;
}

ArrayIndex MainObjectArrayPtr::MainObjectArray::GetMainObjectElementCount(
    ArrayIndex p_MainObjectNumber)
{
    MainObjectEntry BPAQuantumNumber;
    BigPointerBlockPtr BigPointerBlock;

    BPAQuantumNumber = Get(p_MainObjectNumber);
    BigPointerBlock = m_QuantumFile->MakeBigPointerBlockPtr(BPAQuantumNumber);
    return BigPointerBlock->GetBigArrayElementCount();
}

ArrayIndex MainObjectArrayPtr::MainObjectArray::GetMainObjectMaxElementCount(
    ArrayIndex p_MainObjectNumber)
{
    MainObjectEntry BPAQuantumNumber;
    BigPointerBlockPtr BigPointerBlock;

    BPAQuantumNumber = Get(p_MainObjectNumber);
    BigPointerBlock = m_QuantumFile->MakeBigPointerBlockPtr(BPAQuantumNumber);
    return BigPointerBlock->GetBigArrayMaxElementCount();
}

FlexArray::FlexArray()
{
    m_MOAIndex = 0;
}

FlexArray::FlexArray(MainObjectArrayPtr p_MOA, ObjectNumber p_MOAIndex)
{
    m_MOA = p_MOA;
    m_MOAIndex = p_MOAIndex;
    m_ElementCount = m_MOA->GetMainObjectElementCount(m_MOAIndex);
    m_MaxElementCount = m_MOA->GetMainObjectMaxElementCount(m_MOAIndex);
}

FlexArray::FlexArray(QuantumFile *p_QF, ModifiableElement p_ArrayName, 
    ArrayIndex p_ElementCount, ArrayIndex p_MaxElementCount)
{
    Open(p_QF,p_ArrayName,p_ElementCount,p_MaxElementCount);
}

void FlexArray::Open(QuantumFile *p_QF, ModifiableElement p_ArrayName, 
    ArrayIndex p_ElementCount, ArrayIndex p_MaxElementCount)
{
    m_MOA = MainObjectArrayPtr(p_QF);

    m_MOAIndex = m_MOA->FindObjectByName(p_ArrayName);

    if (m_MOAIndex == NoObject)
        {
        m_MOAIndex = m_MOA->FindAvailableObject();
        m_MOA->CreateMainObject(p_ArrayName,m_MOAIndex,
            p_ElementCount, p_MaxElementCount);
        }

    m_ElementCount = m_MOA->GetMainObjectElementCount(m_MOAIndex);
    m_MaxElementCount = m_MOA->GetMainObjectMaxElementCount(m_MOAIndex);
}

FlexArrayRef::FlexArrayRef(MainObjectArrayPtr &p_MOA, ObjectNumber p_MOAIndex, 
    ArrayIndex p_ElementIndex)
 :      m_MOA(p_MOA), m_MOAIndex(p_MOAIndex), m_ElementIndex(p_ElementIndex)
{
}

FlexArrayRef& FlexArrayRef::operator=(ModifiableElement p_ROE)
{
    m_MOA->PutElement(m_MOAIndex, m_ElementIndex, p_ROE);
    return *this;
}

FlexArrayRef::operator ModifiableElement()
{
    return m_MOA->GetModifiableElement(m_MOAIndex, m_ElementIndex);
}

FlexArrayRef FlexArray::operator[](ArrayIndex p_ElementIndex)
{

    qfassert(p_ElementIndex < m_MaxElementCount);

    if (p_ElementIndex >= m_ElementCount)
        m_ElementCount = m_MOA->GrowMainObject(m_MOAIndex,p_ElementIndex+1);
        
    return FlexArrayRef(m_MOA, m_MOAIndex, p_ElementIndex);
}

AccessVector<Ulong> MainObjectArrayPtr::MainObjectArray::GetAccessVectorUlong(
    ArrayIndex p_MainObjectNumber, ArrayIndex p_ElementIndex)
{
    MainObjectEntry BPAQuantumNumber;
    BigPointerBlockPtr BigPointerBlock;
    LittlePointerBlockPtr LittlePointerBlock;
    LeafBlockPtr ElementBlock;
    ArrayIndex BigPointerIndex;
    ArrayIndex LittlePointerIndex;
    QuantumNumber LPAQuantumNumber;
    ItemReference ElementRef;
    AccessVector<Ulong> Result;

    BPAQuantumNumber = Get(p_MainObjectNumber);

    BigPointerBlock =
        m_QuantumFile->MakeBigPointerBlockPtr(BPAQuantumNumber);

    BigPointerIndex = p_ElementIndex / ItemReferencesPerBlock;

    LPAQuantumNumber =
        BigPointerBlock->GetBigArrayElement(BigPointerIndex);

    LittlePointerBlock =
        m_QuantumFile->MakeLittlePointerBlockPtr(LPAQuantumNumber);

    LittlePointerIndex = p_ElementIndex % ItemReferencesPerBlock;
    ElementRef = LittlePointerBlock->GetLittleArrayElement(LittlePointerIndex);

    if (ElementRef.IsReference())
        {
        ElementBlock =
            m_QuantumFile->MakeLeafBlockPtr(ElementRef.GetQuantumNumber());

        Result =
            ElementBlock->GetAccessVectorUlong(ElementRef.GetItemNumber());
        }

    return Result;
}

void MainObjectArrayPtr::MainObjectArray::SetModified(
    ArrayIndex p_MainObjectNumber, ArrayIndex p_ElementIndex)
{
    MainObjectEntry BPAQuantumNumber;
    BigPointerBlockPtr BigPointerBlock;
    LittlePointerBlockPtr LittlePointerBlock;
    LeafBlockPtr ElementBlock;
    ArrayIndex BigPointerIndex;
    ArrayIndex LittlePointerIndex;
    QuantumNumber LPAQuantumNumber;
    ItemReference ElementRef;
    ModifiableElement Element;
    QuantumNumber LeafBlockNumber;

    BPAQuantumNumber = Get(p_MainObjectNumber);

    BigPointerBlock =
        m_QuantumFile->MakeBigPointerBlockPtr(BPAQuantumNumber);

    BigPointerIndex = p_ElementIndex / ItemReferencesPerBlock;

    LPAQuantumNumber =
        BigPointerBlock->GetBigArrayElement(BigPointerIndex);

    LittlePointerBlock =
        m_QuantumFile->MakeLittlePointerBlockPtr(LPAQuantumNumber);

    LittlePointerIndex = p_ElementIndex % ItemReferencesPerBlock;
    ElementRef = LittlePointerBlock->GetLittleArrayElement(LittlePointerIndex);

    if (ElementRef.IsReference())
        {
        ElementBlock =
            m_QuantumFile->MakeLeafBlockPtr(ElementRef.GetQuantumNumber());
        LeafBlockNumber = ElementRef.GetQuantumNumber()-
            m_QuantumFile->GetQuantumNumberAdjustment();
        m_QuantumFile->SetModified(LeafBlockNumber);
        }
}


