/*****************************************************************************
#   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.
#
#*****************************************************************************/
//
// choose_contig.cpp
//
// implementation for ChooseContig class
//
// Used to put up a dialog box with fragments and contigs, get a user response,
// and return a contig
//
// gordon
//


#include    "rwcregexp.h"
#include    "contig.h"
#include    "choose_contig.h"
#include    "fragment_and_contig.h"
#include    "consed.h"
#include    "contigwin.h"
#include    "guiTopWindow.h"



ChooseContig :: ChooseContig( Assembly* pAssembly, 
                              const RWCString& soOptionalPattern ) 
   : pAssembly_( pAssembly ), bHadToTruncateReadList_( false ),
     bNumberOfReadsMatchingPatternSet_( false ),
     soOptionalPattern_( soOptionalPattern ) {

   daFragmentAndContig_.soName_ = "ChooseContig::daFragmentAndContig_";

}

int ChooseContig :: nGetNumberOfReadsMatchingPattern() {

   // if there is no pattern, count total number of reads in assembly

   RWCRegexp* pReg = NULL;

   if ( !soOptionalPattern_.bIsNull() ) {
      pReg = new RWCRegexp( soOptionalPattern_ );
   }

   int nNumberOfReadsMatchingPattern = 0;

   Assembly* pAssembly = ConsEd::pGetAssembly();
   for( int nContig = 0; nContig < pAssembly->nNumContigs(); ++nContig ) {
      Contig* pContig = pAssembly->pGetContig( nContig );

      for( int nLocatedFragment = 0; 
           nLocatedFragment < pContig->nGetNumberOfFragsInContig();
           ++nLocatedFragment ) {

         RWCString soReadName = 
            pContig->pLocatedFragmentGet( nLocatedFragment )->soGetName();
         
         if ( pReg ) {
            if ( soReadName.index( *pReg ) 
                 != RW_NPOS ) {
               ++nNumberOfReadsMatchingPattern;
            }
         }
         else {
            ++nNumberOfReadsMatchingPattern;
         }
      }
   }

   nNumberOfReadsMatchingPattern_ = nNumberOfReadsMatchingPattern;
   bNumberOfReadsMatchingPatternSet_ = true;

   return( nNumberOfReadsMatchingPattern_ );
}


void ChooseContig :: fillThyself( const bool bLimitNumberOfReads ) {

   // this says there is no case in which this routine is used
   // in which the # of reads is limited and there is a pattern
   if ( !soOptionalPattern_.bIsNull() ) {
      assert( !bLimitNumberOfReads );
   }


   Assembly* pAssembly = ConsEd::pGetAssembly();

   if ( bNumberOfReadsMatchingPatternSet_ ) {
      daFragmentAndContig_.resize( nNumberOfReadsMatchingPattern_ );
   }
   else {
      if ( !bLimitNumberOfReads ||
           ( pAssembly->nGetNumberOfReadsInAssembly() <= 
             pCP->nMaximumReadsInReadList_ ) ) {

         daFragmentAndContig_.resize( pAssembly->nGetNumberOfReadsInAssembly() );
      }
   }


   if ( soOptionalPattern_.isNull() ) {

      if ( bLimitNumberOfReads &&
           ( pAssembly->nGetNumberOfReadsInAssembly() > 
             pCP->nMaximumReadsInReadList_ ) ) {
         bHadToTruncateReadList_ = true;
      }
      else {

         for( int nContig = 0; nContig < pAssembly->nNumContigs(); ++nContig ) {
            Contig* pContig = pAssembly->pGetContig( nContig );

            for( int nLocatedFragment = 0; 
                 nLocatedFragment < pContig->nGetNumberOfFragsInContig();
                 ++nLocatedFragment ) {
         
               FragmentAndContig* pFragmentAndContig = 
                  new FragmentAndContig( 
                                        pContig->pLocatedFragmentGet( nLocatedFragment )  
                                        );

               daFragmentAndContig_.insert( pFragmentAndContig );

            }
         }
      }  // if ( bLimitNumberOfReads ... else 
   } // if ( soOptionalPattern.isNull() )
   else {

      RWCRegexp reg( soOptionalPattern_ );


      for( int nContig = 0; nContig < pAssembly->nNumContigs(); ++nContig ) {
         Contig* pContig = pAssembly->pGetContig( nContig );

         for( int nLocatedFragment = 0;
              nLocatedFragment < pContig->nGetNumberOfFragsInContig();
              ++nLocatedFragment ) {
            
            RWCString soReadName = 
               pContig->pLocatedFragmentGet( nLocatedFragment )->soGetName();
            

            if ( soReadName.index( reg ) 
                 != RW_NPOS ) {

               // found one that fits the pattern

               FragmentAndContig* pFragmentAndContig =
                  new FragmentAndContig(
                         pContig->pLocatedFragmentGet( nLocatedFragment )
                                         );

               daFragmentAndContig_.insert( pFragmentAndContig );

               // currently this option is not used
//                if ( bLimitNumberOfReads &&
//                     ( daFragmentAndContig_.length() >=
//                       pCP->nMaximumReadsInReadList_ ) ) {

//                   bHadToTruncateReadList_ = true;
//                   break;
//                }
            }
         }
      }
   } // if ( soOptionalPattern.isNull() ) else


   // sort the list so that fwd/rev pairs are close to each other
   daFragmentAndContig_.resort();
}



ChooseContig :: ~ChooseContig() {
   daFragmentAndContig_.clearAndDestroy();
}
   



void ChooseContig    ::  getChosenContig( 
                                   const int nIndex, 
                                   const bool bFragmentListNotContigList,
                                   Contig*& pContig,
                                   LocatedFragment*& pLocatedFragment )
{


   // subtract 1 since the index is 1 based (this is the way X returns
   // the indices of a list )
   if ( bFragmentListNotContigList ) {
      pContig = daFragmentAndContig_[ nIndex - 1 ]->pContig_;
      pLocatedFragment = 
        daFragmentAndContig_[ nIndex - 1 ]->pLocatedFragment_;
   }
   else {
      pContig = pAssembly_->pGetContig( nIndex - 1 );
      pLocatedFragment = NULL;
   }

}