/*
 * Copyright (C) 2014 Indeed Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the
 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied. See the License for the specific language governing permissions and
 * limitations under the License.
 */
 package com.indeed.flamdex.lucene;

import com.indeed.flamdex.api.StringTermIterator;
import org.apache.log4j.Logger;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.Term;
import org.apache.lucene.index.TermEnum;

import java.io.IOException;

class LuceneStringTermIterator implements StringTermIterator, LuceneTermIterator {
    private static final Logger log = Logger.getLogger(LuceneStringTermIterator.class);

    private final IndexReader reader;
    private final String field;
    private TermEnum termEnum; // if this is null it signal initialize needs to be called
    private boolean hasNext = false;
    private String firstTerm = "";

    public LuceneStringTermIterator(final IndexReader reader, final String field) {
        this.reader = reader;
        this.field = field;
    }

    @Override
    public void reset(final String term) {
        firstTerm = term;
        closeTermEnum();
    }

    private void closeTermEnum() {
        if (termEnum == null) return;
        try {
           termEnum.close();
        } catch (IOException e) {
            throw LuceneUtils.ioRuntimeException(e);
        }
        termEnum = null;
    }

    private boolean initialize() {
        try {
            termEnum = reader.terms(new Term(field, firstTerm));
        } catch (IOException e) {
            throw LuceneUtils.ioRuntimeException(e);
        }
        hasNext = termEnum.term() != null && field.equals(termEnum.term().field());
        return hasNext;
    }

    @Override
    public String term() {
        sanityCheck();
        return termEnum.term().text();
    }

    @Override
    public boolean next() {
        if (termEnum == null) {
            return initialize();
        }

        if (!hasNext) return false;

        final boolean nextSuccessful;
        try {
            nextSuccessful = termEnum.next();
        } catch (IOException e) {
            throw LuceneUtils.ioRuntimeException(e);
        }
        hasNext = nextSuccessful && termEnum.term() != null && field.equals(termEnum.term().field());
        return hasNext;
    }

    @Override
    public int docFreq() {
        sanityCheck();
        return termEnum.docFreq();
    }

    @Override
    public void close() {
        if (termEnum != null) {
            try {
                closeTermEnum();
            } catch (RuntimeException e) {
                log.error("error closing TermEnum", e);
            }
        }
    }

    @Override
    public TermEnum termEnum() {
        sanityCheck();
        return termEnum;
    }

    private void sanityCheck() {
        if (!hasNext) {
            throw new IllegalArgumentException("Invalid operation given iterators current state");
        }
    }
}
