text: /*****************************************************************************
   *                                                                           *
   *   PLAST : Parallel Local Alignment Search Tool                            *
   *   Version 2.3, released November 2015                                     *
   *   Copyright (c) 2009-2015 Inria-Cnrs-Ens                                  *
   *                                                                           *
   *   PLAST is free software; you can redistribute it and/or modify it under  *
   *   the Affero GPL ver 3 License, that is compatible with the GNU General   *
   *   Public License                                                          *
   *                                                                           *
   *   This program is distributed in the hope that it will be useful,         *
   *   but WITHOUT ANY WARRANTY; without even the implied warranty of          *
   *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the            *
   *   Affero GPL ver 3 License for more details.                              *
   *****************************************************************************/
  
  #include <misc/api/macros.hpp>
  #include <seed/impl/BasicSeedModel.hpp>
  
  #include <stdio.h>
  #define DEBUG(a)    //printf a
  #define VERBOSE(a)
  
  using namespace std;
  using namespace database;
  
  /********************************************************************************/
  namespace seed { namespace impl {
  /********************************************************************************/
  
  /*********************************************************************
  ** METHOD  :
  ** PURPOSE :
  ** INPUT   :
  ** OUTPUT  :
  ** RETURN  :
  ** REMARKS :
  *********************************************************************/
  BasicSeedModel::BasicSeedModel (Encoding encoding, size_t span, size_t extraspan)
      : AbstractSeedModel(span,extraspan),_seedsMaxNumber(1)
  {
      /** We compute the maximum number of seeds. */
      _seedsMaxNumber = 1;
      for (size_t i=1; i<=_span; i++)   {  _seedsMaxNumber *= _alphabet->size; }
  
      DEBUG (("BasicSeedModel::BasicSeedModel:  span=%d  alphabetSize=%d  maxNb=%ld\n", _span, _alphabet->size, _seedsMaxNumber));
  }
  
  /*********************************************************************
  ** METHOD  :
  ** PURPOSE :
  ** INPUT   :
  ** OUTPUT  :
  ** RETURN  :
  ** REMARKS :
  *********************************************************************/
  BasicSeedModel::~BasicSeedModel ()
  {
  }
  
  /*********************************************************************
  ** METHOD  :
  ** PURPOSE :
  ** INPUT   :
  ** OUTPUT  :
  ** RETURN  :
  ** REMARKS :
  *********************************************************************/
  ISeedIterator* BasicSeedModel::createSeedsIterator (const database::IWord& data)
  {
      return new DataSeedIterator (this, data);
  }
  
  /*********************************************************************
  ** METHOD  :
  ** PURPOSE :
  ** INPUT   :
  ** OUTPUT  :
  ** RETURN  :
  ** REMARKS :
  *********************************************************************/
  ISeedIterator* BasicSeedModel::createAllSeedsIterator ()
  {
      return new AllSeedsIterator (this);
  }
  
  /*********************************************************************
  ** METHOD  :
  ** PURPOSE :
  ** INPUT   :
  ** OUTPUT  :
  ** RETURN  :
  ** REMARKS :
  *********************************************************************/
  bool BasicSeedModel::getSeedByString (const std::string& seedAscii, ISeed& seed)
  {
      bool result = false;
  
      ISeedIterator* it = createAllSeedsIterator ();
      LOCAL(it);
  
      for (it->first(); result==false && !it->isDone(); it->next())
      {
          const ISeed* current = it->currentItem();
  
          if (current->kmer.toString().compare (seedAscii) == 0)
          {
              seed = *current;
              result = true;
          }
      }
  
      return result;
  }
  
  /*********************************************************************
  ** METHOD  :
  ** PURPOSE :
  ** INPUT   :
  ** OUTPUT  :
  ** RETURN  :
  ** REMARKS :
  *********************************************************************/
  BasicSeedModel::DataSeedIterator::DataSeedIterator (BasicSeedModel* model, const database::IWord& data)
      : AbstractSeedIterator (model,0,0,true), _specificModel(model)
  {
      setData (data);
  }
  
  /*********************************************************************
  ** METHOD  :
  ** PURPOSE :
  ** INPUT   :
  ** OUTPUT  :
  ** RETURN  :
  ** REMARKS :
  *********************************************************************/
  bool BasicSeedModel::DataSeedIterator::findNextValidItem (void)
  {
      bool found = false;
  
      /** Shortcuts. */
      LETTER* out    = _currentItem.kmer.letters.data;
      LETTER* buffer = _data.letters.data;
  
      /** We check that we have enough letters for building a correct word. */
      while (found==false && _currentIdx <= _lastIdx)
      {
          size_t badLetterIdx = 0;
          bool   isBadLetter  = false;
  
          /** We look whether there is a bad letter in the current seed. */
          for (size_t i=0; i <_span; i++)
          {
              VERBOSE (("DataSeedIterator::findNextValidLetter: data[%ld]=%d  \n" ,i, _data.letters[i+_currentIdx]));
  
              /** We retrieve the current letter. */
              LETTER l = buffer[i+_currentIdx];
  
              /** We check that we have no bad letter. */
              if (l >= (char)_alphabetSize)
              {
                  isBadLetter  = true;
                  badLetterIdx = i +_currentIdx;
              }
              else
              {
                  /** We translate the output word. */
                  out[i] = l;
              }
          }
  
          if (isBadLetter)
          {
              _currentIdx = badLetterIdx + 1;
          }
          else
          {
              found = true;
          }
  
      } /* end of while (found==false && _currentIdx <= _lastIdx) */
  
      VERBOSE (("DataSeedIterator::findNextValidLetter: ------------------- _currentIdx=%ld  _lastIdx=%ld  found=%d\n", _currentIdx, _lastIdx, found));
  
      if (found)
      {
          /** We set the hash code. The output word is supposed to have been translated above. */
          _currentItem.code  = _specificModel->getHashCode (_currentItem.kmer);
  
          /** We set the index. */
          _currentItem.offset  = _currentIdx;
      }
  
      return found;
  }
  
  /*********************************************************************
  ** METHOD  :
  ** PURPOSE :
  ** INPUT   :
  ** OUTPUT  :
  ** RETURN  :
  ** REMARKS :
  *********************************************************************/
  BasicSeedModel::AllSeedsIterator::AllSeedsIterator (BasicSeedModel* model, size_t firstIdx, size_t lastIdx)
      : AbstractSeedIterator (model, firstIdx, lastIdx, false), _specificModel(model), _totalNumber(0)
  {
      /** By convention, if we have a first index greater than the last index,
       *  it means that we want to have the whole set of iterated items. */
      if (firstIdx > lastIdx)
      {
          _firstIdx = 0;
          _lastIdx  = _model->getSeedsMaxNumber() - 1;
      }
      else
      {
          _firstIdx = firstIdx;
          _lastIdx  = lastIdx;
      }
  
      _totalNumber = _lastIdx - _firstIdx + 1;
  
      /** We fill the indexes vector. */
      _seedsIdx.resize (_totalNumber);
      for (size_t i=0; i<_totalNumber; i++)  {  _seedsIdx[i] = i; }
  
      DEBUG (("BasicSeedModel::AllSeedsIterator::AllSeedsIterator 1: [%ld,%ld] => [%ld,%ld]\n", firstIdx, lastIdx, _firstIdx, _lastIdx));
  }
  
  /*********************************************************************
  ** METHOD  :
  ** PURPOSE :
  ** INPUT   :
  ** OUTPUT  :
  ** RETURN  :
  ** REMARKS :
  *********************************************************************/
  BasicSeedModel::AllSeedsIterator::AllSeedsIterator (BasicSeedModel* model, const std::vector<size_t>& seedsIdx)
      : AbstractSeedIterator (model, 0, 0, false),
        _specificModel(model), _totalNumber(0)
  {
      if (seedsIdx.empty() == false)
      {
          _firstIdx = 0;
          _lastIdx  = seedsIdx.size()-1;
      }
      else
      {
          /** We have nothing to iterate, just be sure that the first is greater than the last. */
          _firstIdx = 1;
          _lastIdx  = 0;
      }
  
      /** We compute the total number of seed. */
      _totalNumber = seedsIdx.size();
  
      /** We copy the vector of seeds indexes. */
      _seedsIdx = seedsIdx;
  
      DEBUG (("BasicSeedModel::AllSeedsIterator::AllSeedsIterator 2: seedsIdx.size()=%ld\n", seedsIdx.size() ));
  }
  
  /*********************************************************************
  ** METHOD  :
  ** PURPOSE :
  ** INPUT   :
  ** OUTPUT  :
  ** RETURN  :
  ** REMARKS :
  *********************************************************************/
  BasicSeedModel::AllSeedsIterator::~AllSeedsIterator ()
  {
  }
  
  /*********************************************************************
  ** METHOD  :
  ** PURPOSE :
  ** INPUT   :
  ** OUTPUT  :
  ** RETURN  :
  ** REMARKS :
  *********************************************************************/
  ISeedIterator* BasicSeedModel::AllSeedsIterator::extract (size_t firstIdx, size_t lastIdx)
  {
      return new AllSeedsIterator (_specificModel, firstIdx, lastIdx);
  }
  
  /*********************************************************************
  ** METHOD  :
  ** PURPOSE :
  ** INPUT   :
  ** OUTPUT  :
  ** RETURN  :
  ** REMARKS :
  *********************************************************************/
  ISeedIterator* BasicSeedModel::AllSeedsIterator::createFilteredIterator (const std::vector<size_t>& seedsIdx)
  {
      DEBUG (("BasicSeedModel::AllSeedsIterator::createFilteredIterator   seedsIdx.size()=%ld\n", seedsIdx.size() ));
  
      /** We just clone, we don't filter anything. TO BE IMPROVED... */
      return new AllSeedsIterator (_specificModel, seedsIdx);
  }
  
  /*********************************************************************
  ** METHOD  :
  ** PURPOSE :
  ** INPUT   :
  ** OUTPUT  :
  ** RETURN  :
  ** REMARKS :
  *********************************************************************/
  void BasicSeedModel::AllSeedsIterator::updateItem (void)
  {
      /** A little shortcut. */
      LETTER* out = _currentItem.kmer.letters.data;
  
      /** We retrieve the actual index of the seed. */
      size_t initIdx = _seedsIdx [_currentIdx - _firstIdx];
  
      size_t actualIdx = initIdx;
  
      /** We convert the letters of the current data according to the model. */
      for (size_t i=0; i<_span; i++)
      {
          out[i] =  actualIdx % _alphabetSize;
          actualIdx   /= _alphabetSize;
      }
  
      _currentItem.code   = initIdx;
      _currentItem.offset = 0;
  }
  
  /********************************************************************************/
  } } /* end of namespaces. */
  /********************************************************************************/
  