#include "KinoSearch/Util/ToolSet.h"

#define KINO_WANT_LEXREADER_VTABLE
#include "KinoSearch/Index/LexReader.r"

#include "KinoSearch/Schema.r"
#include "KinoSearch/Index/IndexFileNames.h"
#include "KinoSearch/Index/SegInfo.r"
#include "KinoSearch/Index/SegLexicon.r"
#include "KinoSearch/Index/Term.r"
#include "KinoSearch/Index/TermInfo.r"
#include "KinoSearch/Index/SegLexCache.r"
#include "KinoSearch/Store/Folder.r"

LexReader*
LexReader_new(Schema *schema, Folder *folder, SegInfo *seg_info)
{
    u32_t i;
    SegLexicon **lexicons;
    CREATE(self, LexReader, LEXREADER);

    /* assign */
    self->schema         = REFCOUNT_INC(schema);
    self->folder         = REFCOUNT_INC(folder);
    self->seg_info       = REFCOUNT_INC(seg_info);

    /* derive */
    self->num_fields   = Schema_Num_Fields(schema);
    self->index_interval = schema->index_interval;
    self->skip_interval  = schema->skip_interval;

    /* build an array of SegLexicon objects */
    lexicons = CALLOCATE(self->num_fields, SegLexicon*);
    self->lexicons = lexicons;
    for (i = 0; i < self->num_fields; i++) {
        ByteBuf *field = SegInfo_Field_Name(seg_info, i);
        SegLexCache *lex_cache 
            = SegLexCache_new(schema, folder, seg_info, field);
        if (lex_cache == NULL)
            continue;
        lexicons[i] = SegLex_new(schema, folder, seg_info, field, 
            lex_cache, false);
        REFCOUNT_DEC(lex_cache);
    }

    return self;
}

void
LexReader_close(LexReader *self)
{
    u32_t i;
    SegLexicon **lexicons = self->lexicons;

    /* release each lexicon and NULL out array */
    for (i = 0; i < self->num_fields; i++) {
        REFCOUNT_DEC(lexicons[i]);
    }
    memset(lexicons, 0, self->num_fields * sizeof(void*));
}

void
LexReader_destroy(LexReader *self)
{
    LexReader_Close(self);
    free(self->lexicons);
    REFCOUNT_DEC(self->schema);
    REFCOUNT_DEC(self->folder);
    REFCOUNT_DEC(self->seg_info);
    free(self);
}

static SegLexicon*
obtain_lexicon(LexReader *self, ByteBuf *field)
{
    i32_t field_num = SegInfo_Field_Num(self->seg_info, field);
    SegLexicon *orig;

    if (field_num > (i32_t)self->num_fields) /* sanity check */
        CONFESS("Field num too big: %d %u", field_num, self->num_fields);

    /* if field isn't known, bail out */
    if (field_num == -1)
        return NULL;
    
    /* bail out if the field isn't indexed or isn't in seg */
    orig = self->lexicons[field_num];
    if (orig == NULL)
        return NULL;

    return (SegLexicon*)SegLex_Clone(orig);
}



SegLexicon*
LexReader_look_up_term(LexReader *self, Term *target) 
{
    SegLexicon *lexicon;

    /* one null deserves another */
    if (target == NULL)
        return NULL;

    /* get a lexicon and seek it */
    lexicon = obtain_lexicon(self, target->field);
    if (lexicon != NULL)
        SegLex_Seek(lexicon, target);

    return lexicon;
}

SegLexicon*
LexReader_look_up_field(LexReader *self, ByteBuf *field)
{
    SegLexicon *lexicon = obtain_lexicon(self, field);
    if (lexicon != NULL)
        SegLex_Reset(lexicon);
    return lexicon;
}

TermInfo*
LexReader_fetch_term_info(LexReader *self, Term *target) 
{
    if (target != NULL) {
        i32_t field_num = SegInfo_Field_Num(self->seg_info, target->field);
        if (field_num > (i32_t)self->num_fields) /* sanity check */
            CONFESS("Field num too big: %d %u", field_num, self->num_fields);

        if (field_num != -1) {
            SegLexicon *lexicon = self->lexicons[field_num];


            if (lexicon != NULL) {
                Term *found;

                /* iterate until the result is ge the term */ 
                SegLex_Seek(lexicon, target);

                /*if found matches target, return info; otherwise NULL */
                found = SegLex_Get_Term(lexicon);
                if (found != NULL && Term_Equals(target, (Obj*)found)) {
                    return SegLex_Get_Term_Info(lexicon);
                }
            }
        }
    }
    return NULL;
}

u32_t
LexReader_get_skip_interval(LexReader *self)
{
    return self->skip_interval;
}



/* Copyright 2006-2007 Marvin Humphrey
 *
 * This program is free software; you can redistribute it and/or modify
 * under the same terms as Perl itself.
 */