/** \file lowlevel_indexrepository.cpp .
-----------------------------------------------------------------------------


 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.

-----------------------------------------------------------------------------

   Description:

-----------------------------------------------------------------------------


-------------------------------------------------------------------------- */

//#define DEBUG_VERBOSE
/* ----------------------------------------------------------------------- */
/*       Include dependencies                                              */
/* ----------------------------------------------------------------------- */
#include "uima/pragmas.hpp"

#include "uima/macros.h"

#include "uima/lowlevel_indexrepository.hpp"
#include "uima/lowlevel_index.hpp"
#include "uima/lowlevel_indexiterator.hpp"
#include "uima/lowlevel_internal_indexfactory.hpp"
#include "uima/internal_fspromoter.hpp"
#include "uima/engine.hpp"
#include "uima/msg.h"
/* ----------------------------------------------------------------------- */
/*       Constants                                                         */
/* ----------------------------------------------------------------------- */

/* ----------------------------------------------------------------------- */
/*       Forward declarations                                              */
/* ----------------------------------------------------------------------- */

/* ----------------------------------------------------------------------- */
/*       Types / Classes                                                   */
/* ----------------------------------------------------------------------- */

/* ----------------------------------------------------------------------- */
/*       Implementation                                                    */
/* ----------------------------------------------------------------------- */
using namespace std;
namespace uima {
  namespace lowlevel {

    IndexRepository::IndexRepository(IndexDefinition const & indexDef,
                                     uima::lowlevel::FSHeap & rFSHeap,
                                     CAS & cas)
        : iv_indexDefinition(indexDef),
        iv_cas(cas),
        iv_rFSHeap(rFSHeap),
        iv_bIsInitialized(false) {
      init();
    }

    void IndexRepository::init() {

      UIMA_TPRINT("constructing index store");
      iv_bIsInitialized = false;
      assert( !iv_bIsInitialized );

      iv_idMaximalTypeMapping.clear();
      iv_idNonMaximalTypeIndexes.clear();
      iv_indexes.clear();
      iv_cacheDirtyFlags.clear();
      iv_isUsed.clear();
      iv_usedIndexes.clear();

      size_t typeNum = iv_rFSHeap.getTypeSystem().getNumberOfTypes();
      iv_idMaximalTypeMapping.resize( typeNum + 1 );
      iv_indexes.resize( typeNum + 1);
      iv_idNonMaximalTypeIndexes.resize( typeNum + 1 );
      iv_cacheDirtyFlags.resize(typeNum+1);
      iv_isUsed.assign(typeNum+1, false);
      iv_bIsInitialized = true;
      UIMA_TPRINT("index store constructed");

      assert( iv_bIsInitialized );

      vector<IndexDefinition::TyIndexID> ids;
      iv_indexDefinition.getAllIndexIDs(ids);

      size_t i;

      for (i=0; i<ids.size(); ++i) {

        IndexDefinition::TyIndexID const & id = ids[i];
        uima::lowlevel::TyFSType indexType = iv_indexDefinition.getTypeForIndex(id);
        uima::lowlevel::internal::IndexFactory const * factory = iv_indexDefinition.getFactory(id);
        assert( EXISTS(factory) );

        vector<TyFSType> subsumedTypes;
        iv_indexDefinition.getTypeSystem().getSubsumedTypes(indexType, subsumedTypes);
        size_t i;
        // create the single indexes
        for (i=0; i<subsumedTypes.size(); ++i) {
          TyFSType type = subsumedTypes[i];
          internal::SingleIndex* ix = factory->createSingleIndex(*this, type);
          assert( type < iv_indexes.size() );
          iv_idMaximalTypeMapping[type][id] = iv_indexes[type].size();
          iv_indexes[type].push_back(ix);
        }

        // create all composite indexes
        for (i=0; i<subsumedTypes.size(); ++i) {
          TyFSType type = subsumedTypes[i];
          if (!iv_indexDefinition.getTypeSystem().isMaximalType(type)) {
            UIMA_TPRINT("creating index for non maximal type");
            internal::CompositeIndex* compIx = factory->createCompositeIndex(*this, type);
            iv_idNonMaximalTypeIndexes[type][id] = compIx;
            // add single indexes
            vector<TyFSType> subsumedTypes2;
            iv_indexDefinition.getTypeSystem().getSubsumedTypes(type, subsumedTypes2);
            size_t j;
            for (j=0; j<subsumedTypes2.size(); ++j) {
              TyFSType subsType = subsumedTypes2[j];
              assert( iv_idMaximalTypeMapping[subsType].find(id) != iv_idMaximalTypeMapping[subsType].end() );
              size_t pos = iv_idMaximalTypeMapping[subsType][id];
              compIx->addComponent( iv_indexes[subsType][pos] );
              UIMA_TPRINT("Adding single index of type " << iv_indexDefinition.getTypeSystem().getTypeName(subsType) );
            }
          }
        }
      }
    }


    IndexRepository::~IndexRepository() {
      clearAll();
    }

    void IndexRepository::clearAll() {
      size_t i,j;

      // delete indexes
      for (i=0; i<iv_indexes.size(); ++i) {
        for (j=0; j<iv_indexes[i].size(); ++j) {
          delete iv_indexes[i][j];
        }
      }
      // delete idNonMaximalTypeIndexes
      for (i=0; i<iv_idNonMaximalTypeIndexes.size(); ++i) {
        map<IndexDefinition::TyIndexID, internal::CompositeIndex*>::iterator it;
        for (it = iv_idNonMaximalTypeIndexes[i].begin(); it != iv_idNonMaximalTypeIndexes[i].end(); ++it) {
          delete (*it).second;
        }
      }

      iv_idMaximalTypeMapping.clear();
      iv_idNonMaximalTypeIndexes.clear();
      iv_indexes.clear();
      iv_cacheDirtyFlags.clear();
    }


    void IndexRepository::getUsedIndexes(vector<TyFSType>& fillit) {
      fillit.clear();
      fillit.assign(iv_usedIndexes.begin(), iv_usedIndexes.end());
    }

	void IndexRepository::getIndexedFSs(vector<TyFS>& fillit) {
      fillit.clear();
      for (size_t i=0;i < iv_undefinedindex.size(); i++ ) {
            TyFS tyFSHeapIndex = this->iv_undefinedindex[i];
            fillit.push_back(tyFSHeapIndex);
      }
	  for (size_t i=0; i<iv_usedIndexes.size(); ++i) {
          vector<uima::lowlevel::internal::SingleIndex*> const & crSingleIndexes =
            getAllSingleIndexesForType(iv_usedIndexes[i]);
          for (size_t j=0; j<crSingleIndexes.size(); ++j) {
            unique_ptr<uima::lowlevel::IndexIterator> apIt(crSingleIndexes[j]->createIterator());
            for (apIt->moveToFirst(); apIt->isValid(); apIt->moveToNext()) {
              uima::lowlevel::TyHeapCell pHeapCell = (uima::lowlevel::TyHeapCell) apIt->get();
              TyFS tyFSHeapIndex =  pHeapCell;
              fillit.push_back( tyFSHeapIndex );
            }
          }
      }
	  // eliminate duplicates
      sort(fillit.begin(), fillit.end());
      vector<TyFS>::iterator end = unique(fillit.begin(), fillit.end());
    }

    void IndexRepository::reset() {

      // clear undefined index
      iv_undefinedindex.clear();

      // check if anything to do
      if ( 0 == iv_usedIndexes.size())
        return;

      // Reset the indexes used
      for (size_t i=0; i<iv_usedIndexes.size(); ++i) {
        vector<uima::lowlevel::internal::SingleIndex*> const & crSingleIndexes = getAllSingleIndexesForType(iv_usedIndexes[i]);
        for (size_t j=0; j<crSingleIndexes.size(); ++j) {
          crSingleIndexes[j]->reset();
        }
        iv_cacheDirtyFlags[iv_usedIndexes[i]].clear();
        iv_isUsed[iv_usedIndexes[i]] = false;
      }
      iv_usedIndexes.clear();
    }


    void IndexRepository::resetDefinitions() {
      // reset all index data
      clearAll();
      init();
    }


    IndexABase const & IndexRepository::getLowlevelIndex(IndexDefinition::TyIndexID const & crID, TyFSType type) const {
      assert( iv_bIsInitialized );
      assert( iv_indexDefinition.getTypeSystem().isValidType(type) );
      assert( iv_indexDefinition.isValidIndexId(crID) );
      assert( iv_indexDefinition.getTypeSystem().subsumes( iv_indexDefinition.getTypeForIndex(crID), type) );

      IndexABase* result = NULL;
      if (iv_indexDefinition.getTypeSystem().isMaximalType(type)) {
        UIMA_TPRINT("requested index for maximal type");
        map<IndexDefinition::TyIndexID, size_t>::const_iterator cit = iv_idMaximalTypeMapping[type].find(crID);
        assert( cit != iv_idMaximalTypeMapping[type].end() );
        size_t i = (*cit).second;
        assert( (i >=0) && (i<iv_indexes[type].size()));
        result = iv_indexes[type][ i ];
      } else {
        UIMA_TPRINT("requested index for non maximal type");
        map<IndexDefinition::TyIndexID, internal::CompositeIndex*>::const_iterator cit = iv_idNonMaximalTypeIndexes[type].find(crID);
        assert( cit != iv_idNonMaximalTypeIndexes[type].end() );
        // composite index already exists
        result = (*cit).second;
      }
      assert( EXISTS(result) );
      return *result;
    }



    bool IndexRepository::contains(TyFS tyFS) const {
      assert( iv_bIsInitialized );
      TyFSType tyType = iv_rFSHeap.getType(tyFS);
      vector<internal::SingleIndex*> const & crSingleIndexes = getAllSingleIndexesForType(tyType);
      vector<internal::SingleIndex*>::const_iterator cit;
      for (cit = crSingleIndexes.begin(); cit != crSingleIndexes.end(); ++cit) {
        if ( (*cit)->contains(tyFS) ) {
          return true;
        }
      }
      return false;
    }


    void IndexRepository::add(TyFS fs) {
      assert( iv_bIsInitialized );
      TyFSType type = iv_rFSHeap.getType(fs);
      assert( iv_rFSHeap.getTypeSystem().isValidType(type) );
      UIMA_TPRINT("Adding fs of type " << iv_rFSHeap.getTypeSystem().getTypeName(type) << ": " << (int) fs);
      assert( type < iv_cacheDirtyFlags.size() );
      iv_cacheDirtyFlags[type].clear();

      assert( type < iv_indexes.size() );

      vector<internal::SingleIndex*>& typeIndexes = iv_indexes[type];

      if (!iv_isUsed[type]) {

        //if there is no index defined for this type
        if (typeIndexes.size() == 0 ) {
          iv_undefinedindex.push_back(fs);
          return;
        }

        iv_isUsed[type] = true;
        iv_usedIndexes.push_back(type);
      }


      // for all single indexes on the type of fs
      vector<internal::SingleIndex*>::iterator it;
      for (it = typeIndexes.begin(); it != typeIndexes.end(); ++it) {
        UIMA_TPRINT("index type: " << (*it)->getType());
        UIMA_TPRINT("     (" << iv_rFSHeap.getTypeSystem().getTypeName( (*it)->getType() ));
        assert( iv_rFSHeap.getTypeSystem().isValidType( (*it)->getType() ));
        assert( (*it)->getType() == type );
        (*it)->add(fs);
      }
    }


    void IndexRepository::clearDirtyFlagForIndex(IndexABase const * index) {
      assert(EXISTS(index) );
      TyFSType t = index->getType();
      assert( iv_indexDefinition.getTypeSystem().isValidType(t) );
      vector<TyFSType> types;
      iv_indexDefinition.getTypeSystem().getSubsumedTypes(t, types);
      vector<TyFSType>::const_iterator cit;
      for (cit = types.begin(); cit != types.end(); ++cit) {
        assert( (*cit) < iv_cacheDirtyFlags.size() );
        set<IndexABase const *> & rIndexSet = iv_cacheDirtyFlags[*cit];
        rIndexSet.insert(index);
      }
    }


    bool IndexRepository::isDirtyForIndex(IndexABase const * index) const {
      assert(EXISTS(index) );
      TyFSType t = index->getType();
      assert( iv_indexDefinition.getTypeSystem().isValidType(t) );
      vector<TyFSType> types;
      iv_indexDefinition.getTypeSystem().getSubsumedTypes(t, types);
      vector<TyFSType>::const_iterator cit;
      for (cit = types.begin(); cit != types.end(); ++cit) {
        assert( (*cit) < iv_cacheDirtyFlags.size() );
        set<IndexABase const *> const & crIndexSet = iv_cacheDirtyFlags[*cit];
        if ( crIndexSet.find(index) == crIndexSet.end() ) {
          return true;
        }
      }
      return false;
    }



    /*************************************************************/

#ifndef NDEBUG
    void IndexRepository::print(ostream& os) const {
      os << "===========================================" << endl;
      size_t i,j;
      for (i=1; i<iv_indexes.size(); ++i) {
        UIMA_TPRINT("index for type: " << i);
        assert( iv_indexDefinition.getTypeSystem().isValidType(i) );
        os << "Index for type " << iv_indexDefinition.getTypeSystem().getTypeName(i) << ":" << endl;
        for (j=0; j<iv_indexes[i].size(); ++j) {
          os << "  " << j << "th index: ";
          IndexABase* ix = iv_indexes[i][j];

          IndexIterator* it = ix->createIterator();
          for (it->moveToFirst(); it->isValid(); it->moveToNext() ) {
            os << (size_t) it->get()  << "  ";
          }
          os << endl;
          delete it;
        }
      }

      os << "===========================================" << endl;
    }
#endif


  }
}
/* ----------------------------------------------------------------------- */




