root/src/add-ons/kernel/file_systems/packagefs/indices/NameIndex.cpp
/*
 * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
 * Distributed under the terms of the MIT License.
 */


#include "NameIndex.h"

#include <TypeConstants.h>

#include "DebugSupport.h"
#include "IndexImpl.h"
#include "Node.h"
#include "TwoKeyAVLTree.h"
#include "Volume.h"


// #pragma mark - NameIndexPrimaryKey


class NameIndexPrimaryKey {
public:
        NameIndexPrimaryKey(const Node* entry, const char* name = NULL)
                :
                entry(entry),
                name(name ? name : entry->Name())
        {
        }

        NameIndexPrimaryKey(const char* name)
                :
                entry(NULL),
                name(name)
        {
        }

        const Node*     entry;
        const char*     name;
};


// #pragma mark - NameIndexGetPrimaryKey


class NameIndexGetPrimaryKey {
public:
        inline NameIndexPrimaryKey operator()(const Node* a)
        {
                return NameIndexPrimaryKey(a);
        }

        inline NameIndexPrimaryKey operator()(const Node* a) const
        {
                return NameIndexPrimaryKey(a);
        }
};


// #pragma mark - NameIndexPrimaryKeyCompare


class NameIndexPrimaryKeyCompare {
public:
        inline int operator()(const NameIndexPrimaryKey &a,
                const NameIndexPrimaryKey &b) const
        {
                if (a.entry != NULL && a.entry == b.entry)
                        return 0;
                return strcmp(a.name, b.name);
        }
};


// #pragma mark - EntryTree


typedef TwoKeyAVLTree<Node*, NameIndexPrimaryKey, NameIndexPrimaryKeyCompare,
        NameIndexGetPrimaryKey> _EntryTree;

class NameIndex::EntryTree : public _EntryTree {
};


// #pragma mark -  Iterator


struct NameIndex::IteratorPolicy {
        typedef NameIndex                                                                               Index;
        typedef const char*                                                                             Value;
        typedef NameIndex::EntryTree                                                    NodeTree;
        typedef GenericIndexIteratorTreePolicy<IteratorPolicy>  TreePolicy;

        static NodeTree* GetNodeTree(Index* index)
        {
                return index->fEntries;
        }

        static void GetNodeValue(Node* node, void* buffer, size_t* _keyLength)
        {
                strlcpy((char*)buffer, node->Name(), kMaxIndexKeyLength);
                *_keyLength = strlen(node->Name());
        }
};


struct NameIndex::Iterator : public GenericIndexIterator<IteratorPolicy> {
};


// #pragma mark - NameIndex


NameIndex::NameIndex()
        :
        Index(),
        fEntries(NULL)
{
}


NameIndex::~NameIndex()
{
        if (IsListening())
                fVolume->RemoveNodeListener(this);

        delete fEntries;
        // Actually we would need to maintain a list of iterators and unset the
        // still existing iterators here. But since the name index is deleted
        // when the volume is unmounted, there shouldn't be any iterators left
        // anymore.
}


status_t
NameIndex::Init(Volume* volume)
{
        status_t error = Index::Init(volume, "name", B_STRING_TYPE, false);
        if (error != B_OK)
                return error;

        fVolume->AddNodeListener(this, NULL);

        fEntries = new(std::nothrow) EntryTree;
        if (fEntries == NULL)
                return B_NO_MEMORY;

        return B_OK;
}


int32
NameIndex::CountEntries() const
{
        return fEntries->CountItems();
}


void
NameIndex::NodeAdded(Node* node)
{
        fEntries->Insert(node);

        // update live queries
        _UpdateLiveQueries(node, NULL, node->Name());
}


void
NameIndex::NodeRemoved(Node* node)
{
        fEntries->Remove(node, node);

        // update live queries
        _UpdateLiveQueries(node, node->Name(), NULL);
}


void
NameIndex::NodeChanged(Node* node, uint32 statFields,
        const OldNodeAttributes& oldAttributes)
{
        // nothing to do -- the name remains the same
}


AbstractIndexIterator*
NameIndex::InternalGetIterator()
{
        Iterator* iterator = new(std::nothrow) Iterator;
        if (iterator != NULL) {
                if (!iterator->SetTo(this, NULL, true)) {
                        delete iterator;
                        iterator = NULL;
                }
        }
        return iterator;
}


AbstractIndexIterator*
NameIndex::InternalFind(const void* _key, size_t length)
{
        if (length == 0)
                return NULL;

        const char* key = (const char*)_key;

        // if the key is not null-terminated, copy it
        char clonedKey[kMaxIndexKeyLength];
        if (key[length - 1] != '\0') {
                if (length >= kMaxIndexKeyLength)
                        length = kMaxIndexKeyLength - 1;

                memcpy(clonedKey, key, length);
                clonedKey[length] = '\0';
                length++;
                key = clonedKey;
        }

        Iterator* iterator = new(std::nothrow) Iterator;
        if (iterator != NULL) {
                if (!iterator->SetTo(this, (const char*)key)) {
                        delete iterator;
                        iterator = NULL;
                }
        }
        return iterator;
}


void
NameIndex::_UpdateLiveQueries(Node* entry, const char* oldName,
        const char* newName)
{
        fVolume->UpdateLiveQueries(entry, Name(), Type(),
                oldName, oldName ? strlen(oldName) : 0,
                newName, newName ? strlen(newName) : 0);
}