/*****************************************************************************
#   Copyright (C) 1994-2008 by David Gordon.
#   All rights reserved.                           
#                                                                           
#   This software is part of a beta-test version of the Consed/Autofinish
#   package.  It should not be redistributed or
#   used for any commercial purpose, including commercially funded
#   sequencing, without written permission from the author and the
#   University of Washington.
#   
#   This software is provided ``AS IS'' and any express or implied
#   warranties, including, but not limited to, the implied warranties of
#   merchantability and fitness for a particular purpose, are disclaimed.
#   In no event shall the authors or the University of Washington be
#   liable for any direct, indirect, incidental, special, exemplary, or
#   consequential damages (including, but not limited to, procurement of
#   substitute goods or services; loss of use, data, or profits; or
#   business interruption) however caused and on any theory of liability,
#   whether in contract, strict liability, or tort (including negligence
#   or otherwise) arising in any way out of the use of this software, even
#   if advised of the possibility of such damage.
#
#   Building Consed from source is error prone and not simple which is
#   why I provide executables.  Due to time limitations I cannot
#   provide any assistance in building Consed.  Even if you do not
#   modify the source, you may introduce errors due to using a
#   different version of the compiler, a different version of motif,
#   different versions of other libraries than I used, etc.  For this
#   reason, if you discover Consed bugs, I can only offer help with
#   those bugs if you first reproduce those bugs with an executable
#   provided by me--not an executable you have built.
# 
#   Modifying Consed is also difficult.  Although Consed is modular,
#   some modules are used by many other modules.  Thus making a change
#   in one place can have unforeseen effects on many other features.
#   It may takes months for you to notice these other side-effects
#   which may not seen connected at all.  It is not feasable for me to
#   provide help with modifying Consed sources because of the
#   potentially huge amount of time involved.
#
#*****************************************************************************/
#include    "lookForPerfect4MerFalsePrimerMatchesOfOnePrimerInOneContig.h"
#include    "contig.h"
#include    "nLengthOf4Mer.h"
#include    "nFindScoreOfMatch.h"
#include    "contigMatchTablesType.h"
#include    "consedParameters.h"
#include    "whyIsPrimerNotAcceptableTypes.h"


void lookForPerfect4MerFalsePrimerMatchesOfOnePrimerInOneContig( 
                             primerType* pPrimer,
                             Contig* pContigOfTarget,
                             const bool bComplementedContig,
                             const bool bLookEverywhereInContig,
                             const int nUnpaddedConsPosOfTargetStart,
                             const int nUnpaddedConsPosOfTargetEnd,
                             const bool bForwardNotReversePrimer ) {


   int n4MerToLookup = pPrimer->n3Prime4Bases_;

   contigMatchTablesType* pUnpaddedContig = bComplementedContig ?
      pContigOfTarget->pUnpaddedContigComplemented_ :
      pContigOfTarget->pUnpaddedContig_;

   
   int nUnpaddedConsPosOfTargetStartPossiblyComplemented;
   int nUnpaddedConsPosOfTargetEndPossiblyComplemented;

   if ( ! bLookEverywhereInContig ) {

         if (bComplementedContig ) {
         nUnpaddedConsPosOfTargetStartPossiblyComplemented = 
            pContigOfTarget->nComplementUnpaddedIndex( nUnpaddedConsPosOfTargetEnd );
         nUnpaddedConsPosOfTargetEndPossiblyComplemented =
            pContigOfTarget->nComplementUnpaddedIndex( nUnpaddedConsPosOfTargetStart );
      }
      else {
         nUnpaddedConsPosOfTargetStartPossiblyComplemented =
            nUnpaddedConsPosOfTargetStart;
         nUnpaddedConsPosOfTargetEndPossiblyComplemented =
            nUnpaddedConsPosOfTargetEnd;
      }

   }


   blockOfLocationsOfA4MerType* pBlockOfLocationsOfA4Mer =
      &( pUnpaddedContig->blockOfLocationsOfA4Mer_[ n4MerToLookup ] );

   bool bAgain = true;
   while( bAgain ) {
      
      for( int nIndexWithinBlock = 0; 
           nIndexWithinBlock < pBlockOfLocationsOfA4Mer->nCurrentLength_;
           ++nIndexWithinBlock ) {

         int nUnpaddedPosOfMatchingContig4Mer =
            pBlockOfLocationsOfA4Mer->nUnpaddedPosition_[ nIndexWithinBlock ];

         int nContigZeroBasedUnpaddedOfFirstBase = 
            nUnpaddedPosOfMatchingContig4Mer + nLengthOf4Mer -
            pPrimer->nUnpaddedLength_ - 1;


         if ( !bLookEverywhereInContig ) {
            if ( ! (
              ( nUnpaddedConsPosOfTargetStartPossiblyComplemented <= 
                nContigZeroBasedUnpaddedOfFirstBase )
              &&
              ( nContigZeroBasedUnpaddedOfFirstBase <= 
                nUnpaddedConsPosOfTargetEndPossiblyComplemented ) 
                 ) ) {
            
               continue; // target is not in the same clone as the primer
            }
         }


         if ( nContigZeroBasedUnpaddedOfFirstBase < 0 )
            continue;  // target is too close to beginning of contig

         if ( bForwardNotReversePrimer &&
              !bComplementedContig &&
              (pContigOfTarget == pPrimer->pContig_ ) &&
              (nContigZeroBasedUnpaddedOfFirstBase == 
                   ( pPrimer->nUnpaddedStart_ - 1 ) )
              )
            continue;  // primer is the same as the target 

         if ( !bForwardNotReversePrimer &&
              bComplementedContig &&
              (pContigOfTarget == pPrimer->pContig_ ) ) {
            int nComplementedStartOfPrimer =
               pPrimer->pContig_->nComplementUnpaddedIndex( pPrimer->nUnpaddedEnd_ );
            if ( nContigZeroBasedUnpaddedOfFirstBase ==
                 nComplementedStartOfPrimer - 1 )
               continue;  // primer is the same as the target
         }



         char *szFalseMatch =
            pUnpaddedContig->szUnpaddedBases_
            + nContigZeroBasedUnpaddedOfFirstBase;

         int nPosOfMaxCumulativeScore;
         
         int nScoreOfFalseMatch = nFindScoreOfMatch( 
                                                pPrimer->nUnpaddedLength_,
                                                szFalseMatch,
                                                nPosOfMaxCumulativeScore );

         // at least the last 4 bases must match
         assert( nScoreOfFalseMatch >= 4 );


         if (nScoreOfFalseMatch > pPrimer->nScoreOfStickiestFalseMatch_ ) {
            pPrimer->nScoreOfStickiestFalseMatch_ = nScoreOfFalseMatch;
            pPrimer->pContigOfStickiestFalseMatch_ = pContigOfTarget;
            pPrimer->nUnpaddedOfStickiestFalseMatch_ = 
               nContigZeroBasedUnpaddedOfFirstBase + 1;
            pPrimer->bContigOfStickiestFalseMatchIsComplemented_ = 
               bComplementedContig;

            
            if ( pPrimer->nScoreOfStickiestFalseMatch_ >
                 pCP->nPrimersMaxMatchElsewhereScoreToUse_ ) {
               pPrimer->bAcceptable_ = false;
               pPrimer->nWhyIsPrimerNotAcceptable_ = BAD_PRIMER_STICKS_TO_SOMEWHERE_ELSE;
               // this saves checking for other false matches
               return;
            }





               
         }
         
      } //       for( int nIndexWithinBlock = 0; 

      if ( pBlockOfLocationsOfA4Mer->pNextBlockOfLocationsOfA4Mer_ )
         pBlockOfLocationsOfA4Mer =
            pBlockOfLocationsOfA4Mer->pNextBlockOfLocationsOfA4Mer_;
      else
         bAgain = false;
   }


}