package aliview.importer;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import it.unimi.dsi.io.ByteBufferInpStream;
import aliview.sequencelist.MemoryMappedSequencesFile;
import aliview.sequences.FileSequence;
import aliview.sequences.NexusFileSequence;
import aliview.sequences.PhylipFileSequence;
import aliview.sequences.PositionToPointer;
import aliview.sequences.Sequence;
import aliview.subprocesses.SubThreadProgressWindow;
public class NexusFileIndexer implements FileIndexer{
private static final Logger logger = Logger.getLogger(NexusFileIndexer.class);
long estimateTotalSeqInFile = 0;
long fileSize = -1;
public ArrayList<Sequence> findSequencesInFile(MemoryMappedSequencesFile sequencesFile, long filePointerStart, int seqOffset, int nSeqsToRetrieve,
SubThreadProgressWindow progressWin) throws AlignmentImportException {
ByteBufferInpStream mappedBuff = sequencesFile.getMappedBuff();
ArrayList<Sequence> allSeqs = new ArrayList<Sequence>();
try{
this.fileSize = mappedBuff.length();
int longestSequenceLength = 0;
mappedBuff.position(filePointerStart);
logger.info("Nexus file ix");
/*
MappedBuffReaderHelper readerHelper = new MappedBuffReaderHelper(mappedBuff);
ArrayList<String> allTokens = readerHelper.readAllNexusTokensUntil("MATRIX");
for(int n = 0; n < allTokens.size(); n ++){
String token = allTokens.get(n);
logger.info(token);
}
// determine file type
int NEXUS_TYPE_SEQUENTIAL = 0;
int NEXUS_TYPE_INTERLEAVED = 1;
int importerType = NEXUS_TYPE_SEQUENTIAL;
if(tokenExists(allTokens,"interleave")){
importerType = NEXUS_TYPE_INTERLEAVED;
String token = tokenAfter(allTokens, "interleave");
if(token != null){
if(StringUtils.equalsIgnoreCase(token, "NO")){
importerType = NEXUS_TYPE_SEQUENTIAL;
}
}
}
int nChar = 0;
String value = tokenAfter(allTokens, "nchar");
if(value != null){
nChar = Integer.parseInt(value);
}
int nTax = 0;
value = tokenAfter(allTokens, "ntax");
if(value != null){
nTax = Integer.parseInt(value);
}
// load depending on file type
if(importerType == NEXUS_TYPE_SEQUENTIAL){
for(int n = 0; n < nTax; n ++){
String name = readerHelper.readNextNexusSeqName();
long nameStartPointer = mappedBuff.position() - name.length();
long seqStartPointer = readerHelper.posOfNextNonWhiteNexusChar();
long seqEndPointer = readerHelper.getPosOfNonWhiteNexusCharacter(nChar - 1); // minus one because first is already read when loooking for startpoint
NexusFileSequence seq = new NexusFileSequence( fileMMSequenceList, seqOffset + n, nameStartPointer);
seq.addName(name);
seq.add(new PositionToPointer(0, nChar - 1, seqStartPointer, seqEndPointer));
allSeqs.add(seq);
if(n % 1000 == 0){
progressWin.setMessage("Indexing file " + n + "/" + nTax + "\n");
if(progressWin.wasSubThreadInterruptedByUser()){
break;
}
}
}
}
// load depending on file type
if(importerType == NEXUS_TYPE_INTERLEAVED){
logger.info("NEXUS_TYPE_INTERLEAVED");
// first lines
for(int n = 0; n < nTax; n ++){
String name = readerHelper.readNextNexusSeqName();
//logger.info(name);
long nameStartPointer = mappedBuff.position() - name.length();
long seqStartPointer = readerHelper.posOfNextNonWhiteNexusChar();
long seqEndPointer = readerHelper.posOfNextNewline() - 1; // minus one because we dont want newline
NexusFileSequence seq = new NexusFileSequence( fileMMSequenceList, seqOffset + n, nameStartPointer);
seq.addName(name);
seq.add(new PositionToPointer(0, (int)(seqEndPointer - seqStartPointer), seqStartPointer, seqEndPointer));
allSeqs.add(seq);
if(n % 1000 == 0){
progressWin.setMessage("Indexing file " + n + "/" + nTax + "\n");
if(progressWin.wasSubThreadInterruptedByUser()){
break;
}
}
}
// loop until all characters are found
while(allSeqs.get(0).getLength() < nChar){
for(int n = 0; n < nTax; n ++){
String name = readerHelper.readNextNexusSeqName();
long nameStartPointer = mappedBuff.position() - name.length();
long segmentStartPointer = readerHelper.posOfNextNonWhiteNexusChar();
long segmentEndPointer = readerHelper.posOfNextNewline(); // minus one because we dont want newline
NexusFileSequence appendSeq = (NexusFileSequence) allSeqs.get(n);
int segmentLength = (int)(segmentEndPointer - segmentStartPointer);
int segmentStartPos = appendSeq.getLength(); // startpos (because pos start at 0 so length is next startPos)
int segmentEndPos = segmentStartPos + segmentLength - 1; // -1 because seqment length and seqm start pos otherwise is one to much
appendSeq.add(new PositionToPointer(segmentStartPos, segmentEndPos, segmentStartPointer, segmentEndPointer));
}
}
}
*/
}catch(Exception exc){
logger.info("could not read as nexus");
exc.printStackTrace();
throw new AlignmentImportException("Could not read nexus format");
}
return allSeqs;
}
private int tokenIndex(ArrayList<String> allTokens, String target) {
for(int n = 0; n < allTokens.size(); n++){
String token = allTokens.get(n);
if(StringUtils.equalsIgnoreCase(token, target)){
return n;
}
}
return -1;
}
private boolean tokenExists(ArrayList<String> allTokens, String target) {
if(tokenIndex(allTokens, target) > -1){
return true;
}else{
return false;
}
}
private String tokenAfter(ArrayList<String> allTokens, String target) {
int index = tokenIndex(allTokens, target);
if(index > -1 && allTokens.size() > index){
return allTokens.get(index + 1);
}
else{
return null;
}
}
}