package bilab;

import java.util.Collection;
import java.util.LinkedList;

import java.io.*;


//import org.biojava.bio.Annotation;
//import org.biojava.bio.search.SeqSimilaritySearchResult; 
//import org.biojava.bio.program.sax.BlastLikeSAXParser;
//import org.biojava.bio.program.sax.FastaSearchSAXParser;
//import org.biojava.bio.search.*;
//import org.biojava.bio.seq.db.*;
//import org.biojava.bio.program.sax.*;
//import org.biojava.bio.*;
//import org.biojava.bio.program.ssbind.*;

import jalview.AlignmentPanel;
import jalview.DrawableSequence;
import jalview.FormatAdapter;
import jalview.ScorePanel;
import jalview.ScoreSequence;
import jalview.Sequence;

import scigol.List;
import scigol.TypeSpec;



// A list of sequences with alignment information
public class alignment extends List implements IAnnotated, IResourceIOProvider
{

  public alignment()
  {
    alignedSeqs = new Sequence[0];
    seqScores = new ScoreSequence[0];
    annotation = new scigol.Map();
  }
  
  
  public scigol.Map get_annotations()
  {
    return annotation;
  }
  
  
  @Sophistication(Sophistication.Advanced)
  public Sequence[] alignedSeqs;
  
  @Sophistication(Sophistication.Advanced)
  public ScoreSequence[] seqScores;

  
  protected scigol.Map annotation;

  
  
  private static final java.util.List<String> supportedImportResourceTypes;
  private static final java.util.List<String> supportedExportResourceTypes;
  
  static {
    // list of supported resource name type (not extensions)
    supportedImportResourceTypes = new LinkedList<String>();
    supportedImportResourceTypes.add("MSF");
    supportedImportResourceTypes.add("CLUSTALW");
    supportedImportResourceTypes.add("FASTA");
    supportedImportResourceTypes.add("BLC");
    supportedImportResourceTypes.add("PFAM");
    
    supportedExportResourceTypes = new LinkedList<String>();
    for(String s : supportedImportResourceTypes) supportedExportResourceTypes.add(s);
    supportedExportResourceTypes.add("PhylipMultiSeq");
  }
  
  
  public static java.util.List<String> getSupportedImportResourceTypes()
  {
    return supportedImportResourceTypes;
  }

  public static java.util.List<String> getSupportedExportResourceTypes()
  {
    return supportedExportResourceTypes;
  }

  
  
  public static Object importResource(ResourceManager rm, String resourceName, String resourceType)
  {
    try {
      scigol.Debug.WL("alignment.importResource(): asked to import "+resourceName+" of type "+resourceType);

      InputStreamReader inputStreamReader = new InputStreamReader(rm.findResourceStream(resourceName));
      if (inputStreamReader == null)
        throw new BilabException("unable to open resource:"+resourceName);
      BufferedReader buffReader = new BufferedReader(inputStreamReader);
      
      // read the entire alignment into a string first
      StringBuilder inputString = new StringBuilder();
      String line;
      do {
        line = buffReader.readLine();
        if (line!=null)
          inputString.append(line+"\n");
      } while (line != null);
      
      inputStreamReader.close();
      
      
      String jalViewType;
      if (resourceType.equals("CLUSTALW"))
        jalViewType = "CLUSTAL";
      else if (resourceType.equals("FASTA"))
        jalViewType = "FASTA";
      else if (resourceType.equals("MSF"))
        jalViewType = "MSF";
      else if (resourceType.equals("BLC"))
        jalViewType = "BLC";
      else if (resourceType.equals("PFAM"))
        jalViewType = "PFAM";
      else
        throw new BilabException("unsupported alignment resource type:"+resourceType);
      
      alignment aln = new alignment();
      
      aln.alignedSeqs = FormatAdapter.read(jalViewType, inputString.toString());
      aln.seqScores = new ScoreSequence[aln.alignedSeqs.length]; 
      for (int i=0;i < aln.alignedSeqs.length;i++) {
        aln.seqScores[i] = new ScoreSequence(aln.alignedSeqs[i]);
      }
        
      return aln;
      
    } catch (BilabException e) {
      throw e;
    } catch (Exception e) {
      throw new BilabException("unable to locate/import resource as alignment(s): "+resourceName+" - "+e);
    }
    
  }
  
  
  
  @Summary("create a resource containing data in a supported format from a seq")
  public static void exportResource(ResourceManager rm, alignment a, String resourceName, String resourceType)
  {
    try {
      String outString="";
      
      if (resourceType.equals("PhylipMultiSeq")) {
        StringBuilder sb = new StringBuilder();
        
        // get seqs upper position
        int seqLen = 0;
        for (Sequence seq : a.alignedSeqs) 
          if (seq.end > seqLen) seqLen = seq.end;
        
        // header line is #seqs & length
        sb.append("  "+a.alignedSeqs.length+"   "+seqLen+"\n");
        
        for(Sequence seq : a.alignedSeqs) {
          String rawSeq = seq.getSequence();
          String name = seq.getName();
          
          // pad name to exactly 10 chars
          if (name.length() > 10) 
            name = name.substring(0,10);
          else if (name.length() < 10)
            name = name + Util.spaces.substring(0,10-name.length());
          
          sb.append(name);
          
          rawSeq = rawSeq.replace(".","-"); // Phylip uses '-' for deletions
          // just dump it in a contigous line - Phylip doesn't seem to mind if there is
          //  no space every 10 chars
          sb.append(rawSeq+"\n");
        }
        
        outString = sb.toString();
        
      }
      else {
        String jalViewType;
        if (resourceType.equals("CLUSTALW"))
          jalViewType = "CLUSTAL";
        else if (resourceType.equals("FASTA"))
          jalViewType = "FASTA";
        else if (resourceType.equals("MSF"))
          jalViewType = "MSF";
        else if (resourceType.equals("BLC"))
          jalViewType = "BLC";
        else if (resourceType.equals("PFAM"))
          jalViewType = "PFAM";
        else
          throw new BilabException("unsupported alignment resource type:"+resourceType);
        
        outString = FormatAdapter.get(jalViewType, a.alignedSeqs);
      }

      // write outString to resource
      OutputStream outStream = rm.createResourceStream(resourceName);
      OutputStreamWriter outStreamWriter = new OutputStreamWriter(outStream);
      BufferedWriter buffWriter = new BufferedWriter(outStreamWriter);
      
      buffWriter.write(outString);
      buffWriter.flush();
      outStream.close();

    } catch (Exception e) {
      throw new BilabException("unable to export sequence as resource: "+resourceName);
    }
  }
  
  
  
  public String toString()
  {
    String s = "alignment(";
    for(int i=0; i<alignedSeqs.length;i++) {
      s += alignedSeqs[i].name;
      if (i!=alignedSeqs.length-1) s += ",";
    }
    s += ")";
    return s;
  }
  
  
  
}
