/* 
 * This software was written by Phillip Lord (p.lord@hgmp.mrc.ac.uk)
 * whilst at the University of Manchester as a Pfizer post-doctoral 
 * Research Fellow. 
 *
 * The initial code base is copyright by Pfizer, or the University
 * of Manchester. Modifications to the initial code base are copyright
 * of their respective authors, or their employers as appropriate. 
 * Authorship of the modifications may be determined from the ChangeLog
 * placed at the end of this file
 */

package uk.ac.man.bioinf.apps.commandline; // Package name inserted by JPack
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import uk.ac.man.bioinf.io.ParserException;
import uk.ac.man.bioinf.io.ParserExceptionHandler;
import uk.ac.man.bioinf.io.parsers.PIRProteinAlignmentParser;
import uk.ac.man.bioinf.sequence.Sequences;
import uk.ac.man.bioinf.sequence.alignment.GappedSequence;
import uk.ac.man.bioinf.sequence.alignment.SequenceAlignment;
import uk.ac.man.bioinf.sequence.identifier.FileSource;
import uk.ac.man.bioinf.sequence.identifier.SimpleIdentifier;
import org.apache.regexp.RE;
import org.apache.regexp.RECompiler;
import uk.ac.man.bioinf.analysis.regexp.SequenceCharacterIterator;


/**
 * CheckMotifLocationAgainstPrints.java
 * 
 * This class moves through all the SequenceAlignments in the current
 * directory. It then extracts the motif information from PRINTS-S,
 * and sees whether they are still in the same position. 
 *
 * Created: Tue Feb  6 15:21:55 2001
 *
 * @author Phillip Lord
 * @version $Id: CheckMotifLocationAgainstPrints.java,v 1.1 2001/02/19 17:23:49 lord Exp $
 */

public class CheckMotifLocationAgainstPrints 
{
  
  private static PrintWriter log;
  private static PrintWriter error;
  private static PrintWriter report;
  
  
  private static Connection conn;
  
  private static int filesChecked, filesIgnored, alignmentsNotInPrints, sequencesChecked, 
    motifsChecked, offEndOfSequence, motifMatching, motifNotMatching,
    motifFoundInstead, motifNotFoundAtAll, offEndOfSequenceFoundElsewhere, offEndOfSequenceNotFoundElsewhere;
  

  public static void main( String[] args ) throws Throwable
  {
    try{
      log   = new PrintWriter
        ( new BufferedWriter( new FileWriter( new File( "log.txt" ) ) ) );
      error = new PrintWriter
        ( new BufferedWriter( new FileWriter( new File( "error.txt" ) ) ) );
      report = new PrintWriter
        ( new BufferedWriter( new FileWriter( new File( "results.txt" ) ) ) );

      File director = new File( args[ 0 ] );
      File[] files = director.listFiles();
      
      Class.forName( "postgresql.Driver" );
      conn = DriverManager.getConnection
        ( "jdbc:postgresql://methionine/prints_s", "lord", "" );
      
      for( int i = 0; i < files.length; i++ ){
        if( files[ i ].getName().endsWith( "seqs" ) ){
          check( files[ i ] );
          filesChecked++;
        }
        else{
          error.println( "Ignoring " + files[ i ].getName() );
          filesIgnored++;
        }
      }
    }
    

    catch( Throwable t ){
      log.close();
      error.close();
      throw t;
    }

    log.close();
    error.close();
    printReport();
    report.close();
  } //end main method 
  

  public static void printReport()
  {
    report.println( "Final report" );
    report.println( "=============" );
    
    report.println( "Files Checked: \t\t\t\t" + filesChecked );
    report.println( "Files Ignored: \t\t\t\t" + filesIgnored );
    report.println( "Alignments not in prints: \t\t" + alignmentsNotInPrints );
    report.println( "Sequences checked: \t\t\t" + sequencesChecked );
    report.println( "Motifs checked: \t\t\t" + motifsChecked );
    report.println( "Motifs off end of sequence: \t\t" + offEndOfSequence );
    report.println( "Motifs off end found elsewhere: \t" + offEndOfSequenceFoundElsewhere );
    report.println( "Motifs off end not found: \t\t" + offEndOfSequenceNotFoundElsewhere );
    report.println( "Motifs matching: \t\t\t" + motifMatching );
    report.println( "Motifs not matching: \t\t\t" + motifNotMatching );
    report.println( "Motifs found elsewhere: \t\t" + motifFoundInstead );
    report.println( "Motifs not found at all: \t\t" + motifNotFoundAtAll );
  }
  
  // check a sequence alignment file. 
  public static void check( File file ) throws Throwable
  {
    log.println( "Checking " + file );
    SequenceAlignment alignment = openFile( file );
    
    Statement stat = conn.createStatement();
    ResultSet res = stat.executeQuery
	( "select fprint_accn from fingerprint where identifier ='"
	  + alignment.getIdentifier().getTitle() + "';" );
    
    if( !res.next() ){
      error.println( "Fingerprint for alignment " + alignment.getIdentifier().getTitle() + " not in prints_s " );
      alignmentsNotInPrints++;
      return;
    }
    
    String fprint_accn = res.getString( "fprint_accn" );
    
    stat.close();
    res.close();
    
    for( int i = 1; i < alignment.getNumberSequences() + 1; i ++ ){
      checkSequence( alignment.getIdentifier().getTitle(), fprint_accn, alignment.getSequenceAt( i ) );
      sequencesChecked++;
    }
  }
  
  private static RE regexp = new RE();
  private static RECompiler comp = new RECompiler();
  
  public static void checkSequence( String alignmentTitle, String fprint_accn, GappedSequence seq ) throws Throwable
  {
    log.println( "    Checking " + seq.getIdentifier().getTitle() );
    
    String title = seq.getIdentifier().getTitle();
    
    if( title.indexOf( '[' ) != -1 ){
      title = title.substring( 0, title.indexOf( '[' ) - 1 );
    }
    
    
    // translate title to seqn_id if needed
    if( title.indexOf( '_' ) != -1 ){
      Statement stat = conn.createStatement();
      
      ResultSet res = stat.executeQuery
        ( "select seqn_accn from seqn where seqn_id = '" + title + "';" );
      
      if( res.next() ){
        title = res.getString( "seqn_accn" );
      }
      
      stat.close();
      res.close();
    }
    
    
    // now get the motif
    Statement stat = conn.createStatement();
    
    ResultSet res = stat.executeQuery
      ( "select start_position, seqn_fragment from motif where fprint_accn = '" 
        + fprint_accn + "' and seqn_accn = '" + title + "';" );// and final = true;" );
    
    int i = 1;
    // get the results
    while( res.next() ){
      motifsChecked++;
      log.println( "        Checking motif " + i );
      int start = res.getInt( "start_position" );
      String dataMotif = res.getString( "seqn_fragment" );
      int length = dataMotif.length();
      
      if( (start + length) > seq.getLength() ){
        error.println( "For " + alignmentTitle + " motif " + i  
                       + " appears to start after the end of the sequence " + title );
        offEndOfSequence++;
        
        regexp.setProgram( comp.compile( dataMotif ) );
        if( regexp.match( new SequenceCharacterIterator( seq ), 0 ) ){
          error.println( "Found instead at " + regexp.getParenStart( 0 ) + " to " + regexp.getParenEnd( 0 ) );
          offEndOfSequenceFoundElsewhere++;
        }
        else{
          error.println( "Not found motif in sequence" );
          offEndOfSequenceNotFoundElsewhere++;
        }
        
        return;
      }
      
      String seqMotif = Sequences.getSequenceAsString( seq.getSubSequence( start, length ) );
      
      if( !dataMotif.equals( seqMotif ) ){
        motifNotMatching++;
        error.println( "For " + alignmentTitle + " motif " + i  
                       + " " + seqMotif + " does not match " + dataMotif + " for seq " + title );
        
        regexp.setProgram( comp.compile( dataMotif ) );
        if( regexp.match( new SequenceCharacterIterator( seq ), 0 ) ){
          error.println( "Found instead at " + regexp.getParenStart( 0 ) + " to " + regexp.getParenEnd( 0 ) );
          motifFoundInstead++;
        }
        else{
          error.println( "Not found motif in sequence" );
          motifNotFoundAtAll++;
        }
      }else{
        motifMatching++;
      }
      i++;
    }
    
    stat.close();
    res.close();
  }
  
  public static SequenceAlignment openFile( File inputFile ) throws Throwable
  {
    
    PIRProteinAlignmentParser parser = new PIRProteinAlignmentParser();
    
    ParserExceptionHandler exp = new ParserExceptionHandler(){
        public void handleException( ParserException e )
        {
          //e.printStackTrace();
        }
      };
    
    String fileName = inputFile.getName();
    int i = fileName.lastIndexOf( '.' );
    String fileNameNoExtension = fileName;
    if( i > 0 && i < fileName.length() - 1 ){
	    fileNameNoExtension = fileName.substring( 0, i );
    }
    fileNameNoExtension = fileNameNoExtension.toUpperCase();

    
    SequenceAlignment alignment = parser.parse
      ( new SimpleIdentifier( fileNameNoExtension,new FileSource( inputFile )),
        new BufferedReader( new FileReader( inputFile ) ), exp );
    return alignment;
  }
  
} // CheckMotifLocationAgainstPrints



/*
 * ChangeLog
 * $Log: CheckMotifLocationAgainstPrints.java,v $
 * Revision 1.1  2001/02/19 17:23:49  lord
 * Initial checkin
 *
 */
