]> git.donarmstrong.com Git - mothur.git/blob - sffinfocommand.cpp
changing command name classify.shared to classifyrf.shared
[mothur.git] / sffinfocommand.cpp
1 /*
2  *  sffinfocommand.cpp
3  *  Mothur
4  *
5  *  Created by westcott on 7/7/10.
6  *  Copyright 2010 Schloss Lab. All rights reserved.
7  *
8  */
9
10 #include "sffinfocommand.h"
11 #include "endiannessmacros.h"
12 #include "trimoligos.h"
13 #include "sequence.hpp"
14 #include "qualityscores.h"
15
16 //**********************************************************************************************************************
17 vector<string> SffInfoCommand::setParameters(){ 
18         try {           
19                 CommandParameter psff("sff", "InputTypes", "", "", "none", "none", "none","",false,false,true); parameters.push_back(psff);
20         CommandParameter poligos("oligos", "InputTypes", "", "", "none", "none", "none","",false,false); parameters.push_back(poligos);
21                 CommandParameter paccnos("accnos", "InputTypes", "", "", "none", "none", "none","",false,false); parameters.push_back(paccnos);
22                 CommandParameter psfftxt("sfftxt", "String", "", "", "", "", "","",false,false); parameters.push_back(psfftxt);
23                 CommandParameter pflow("flow", "Boolean", "", "T", "", "", "","flow",false,false); parameters.push_back(pflow);
24                 CommandParameter ptrim("trim", "Boolean", "", "T", "", "", "","",false,false); parameters.push_back(ptrim);
25                 CommandParameter pfasta("fasta", "Boolean", "", "T", "", "", "","fasta",false,false); parameters.push_back(pfasta);
26                 CommandParameter pqfile("qfile", "Boolean", "", "T", "", "", "","qfile",false,false); parameters.push_back(pqfile);
27         CommandParameter ppdiffs("pdiffs", "Number", "", "0", "", "", "","",false,false); parameters.push_back(ppdiffs);
28                 CommandParameter pbdiffs("bdiffs", "Number", "", "0", "", "", "","",false,false); parameters.push_back(pbdiffs);
29         CommandParameter pldiffs("ldiffs", "Number", "", "0", "", "", "","",false,false); parameters.push_back(pldiffs);
30                 CommandParameter psdiffs("sdiffs", "Number", "", "0", "", "", "","",false,false); parameters.push_back(psdiffs);
31         CommandParameter ptdiffs("tdiffs", "Number", "", "0", "", "", "","",false,false); parameters.push_back(ptdiffs);
32                 CommandParameter pinputdir("inputdir", "String", "", "", "", "", "","",false,false); parameters.push_back(pinputdir);
33                 CommandParameter poutputdir("outputdir", "String", "", "", "", "", "","",false,false); parameters.push_back(poutputdir);
34                 
35                 vector<string> myArray;
36                 for (int i = 0; i < parameters.size(); i++) {   myArray.push_back(parameters[i].name);          }
37                 return myArray;
38         }
39         catch(exception& e) {
40                 m->errorOut(e, "SffInfoCommand", "setParameters");
41                 exit(1);
42         }
43 }
44 //**********************************************************************************************************************
45 string SffInfoCommand::getHelpString(){ 
46         try {
47                 string helpString = "";
48                 helpString += "The sffinfo command reads a sff file and extracts the sequence data, or you can use it to parse a sfftxt file.\n";
49                 helpString += "The sffinfo command parameters are sff, fasta, qfile, accnos, flow, sfftxt, oligos, bdiffs, tdiffs, ldiffs, sdiffs, pdiffs and trim. sff is required. \n";
50                 helpString += "The sff parameter allows you to enter the sff file you would like to extract data from.  You may enter multiple files by separating them by -'s.\n";
51                 helpString += "The fasta parameter allows you to indicate if you would like a fasta formatted file generated.  Default=True. \n";
52                 helpString += "The qfile parameter allows you to indicate if you would like a quality file generated.  Default=True. \n";
53         helpString += "The oligos parameter allows you to provide an oligos file to split your sff file into separate sff files by barcode. \n";
54         helpString += "The tdiffs parameter is used to specify the total number of differences allowed in the sequence. The default is pdiffs + bdiffs + sdiffs + ldiffs.\n";
55                 helpString += "The bdiffs parameter is used to specify the number of differences allowed in the barcode. The default is 0.\n";
56                 helpString += "The pdiffs parameter is used to specify the number of differences allowed in the primer. The default is 0.\n";
57         helpString += "The ldiffs parameter is used to specify the number of differences allowed in the linker. The default is 0.\n";
58                 helpString += "The sdiffs parameter is used to specify the number of differences allowed in the spacer. The default is 0.\n";
59                 helpString += "The flow parameter allows you to indicate if you would like a flowgram file generated.  Default=True. \n";
60                 helpString += "The sfftxt parameter allows you to indicate if you would like a sff.txt file generated.  Default=False. \n";
61                 helpString += "If you want to parse an existing sfftxt file into flow, fasta and quality file, enter the file name using the sfftxt parameter. \n";
62                 helpString += "The trim parameter allows you to indicate if you would like a sequences and quality scores trimmed to the clipQualLeft and clipQualRight values.  Default=True. \n";
63                 helpString += "The accnos parameter allows you to provide a accnos file containing the names of the sequences you would like extracted. You may enter multiple files by separating them by -'s. \n";
64                 helpString += "Example sffinfo(sff=mySffFile.sff, trim=F).\n";
65                 helpString += "Note: No spaces between parameter labels (i.e. sff), '=' and parameters (i.e.yourSffFileName).\n";
66                 return helpString;
67         }
68         catch(exception& e) {
69                 m->errorOut(e, "SffInfoCommand", "getHelpString");
70                 exit(1);
71         }
72 }
73
74 //**********************************************************************************************************************
75 string SffInfoCommand::getOutputPattern(string type) {
76     try {
77         string pattern = "";
78         
79         if (type == "fasta")            {   pattern =  "[filename],fasta-[filename],[tag],fasta";   }
80         else if (type == "flow")    {   pattern =  "[filename],flow";   }
81         else if (type == "sfftxt")        {   pattern =  "[filename],sff.txt";   }
82         else if (type == "sff")        {   pattern =  "[filename],[group],sff";   }
83         else if (type == "qfile")       {   pattern =  "[filename],qual-[filename],[tag],qual";   }
84         else { m->mothurOut("[ERROR]: No definition for type " + type + " output pattern.\n"); m->control_pressed = true;  }
85         
86         return pattern;
87     }
88     catch(exception& e) {
89         m->errorOut(e, "SffInfoCommand", "getOutputPattern");
90         exit(1);
91     }
92 }
93 //**********************************************************************************************************************
94 SffInfoCommand::SffInfoCommand(){       
95         try {
96                 abort = true; calledHelp = true; 
97                 setParameters();
98                 vector<string> tempOutNames;
99                 outputTypes["fasta"] = tempOutNames;
100                 outputTypes["flow"] = tempOutNames;
101                 outputTypes["sfftxt"] = tempOutNames;
102                 outputTypes["qfile"] = tempOutNames;
103         outputTypes["sff"] = tempOutNames;
104         }
105         catch(exception& e) {
106                 m->errorOut(e, "SffInfoCommand", "SffInfoCommand");
107                 exit(1);
108         }
109 }
110 //**********************************************************************************************************************
111
112 SffInfoCommand::SffInfoCommand(string option)  {
113         try {
114                 abort = false; calledHelp = false;   
115                 hasAccnos = false; hasOligos = false;
116         split = 1;
117                 
118                 //allow user to run help
119                 if(option == "help") { help(); abort = true; calledHelp = true; }
120                 else if(option == "citation") { citation(); abort = true; calledHelp = true;}
121                 
122                 else {
123                         //valid paramters for this command
124                         vector<string> myArray = setParameters();
125                         
126                         OptionParser parser(option);
127                         map<string, string> parameters = parser.getParameters();
128                         
129                         ValidParameters validParameter;
130                         //check to make sure all parameters are valid for command
131                         for (map<string,string>::iterator it = parameters.begin(); it != parameters.end(); it++) { 
132                                 if (validParameter.isValidParameter(it->first, myArray, it->second) != true) {  abort = true;  }
133                         }
134                         
135                         //initialize outputTypes
136                         vector<string> tempOutNames;
137                         outputTypes["fasta"] = tempOutNames;
138                         outputTypes["flow"] = tempOutNames;
139                         outputTypes["sfftxt"] = tempOutNames;
140                         outputTypes["qfile"] = tempOutNames;
141             outputTypes["sff"] = tempOutNames;
142                         
143                         //if the user changes the output directory command factory will send this info to us in the output parameter 
144                         outputDir = validParameter.validFile(parameters, "outputdir", false);           if (outputDir == "not found"){  outputDir = "";         }
145                         
146                         //if the user changes the input directory command factory will send this info to us in the output parameter 
147                         string inputDir = validParameter.validFile(parameters, "inputdir", false);        if (inputDir == "not found"){ inputDir = "";          }
148
149                         sffFilename = validParameter.validFile(parameters, "sff", false);
150                         if (sffFilename == "not found") { sffFilename = "";  }
151                         else { 
152                                 m->splitAtDash(sffFilename, filenames);
153                                 
154                                 //go through files and make sure they are good, if not, then disregard them
155                                 for (int i = 0; i < filenames.size(); i++) {
156                                         bool ignore = false;
157                                         if (filenames[i] == "current") { 
158                                                 filenames[i] = m->getSFFFile(); 
159                                                 if (filenames[i] != "") {  m->mothurOut("Using " + filenames[i] + " as input file for the sff parameter where you had given current."); m->mothurOutEndLine(); }
160                                                 else {  
161                                                         m->mothurOut("You have no current sfffile, ignoring current."); m->mothurOutEndLine(); ignore=true; 
162                                                         //erase from file list
163                                                         filenames.erase(filenames.begin()+i);
164                                                         i--;
165                                                 }
166                                         }
167                                         
168                                         if (!ignore) {
169                                                 if (inputDir != "") {
170                                                         string path = m->hasPath(filenames[i]);
171                                                         //if the user has not given a path then, add inputdir. else leave path alone.
172                                                         if (path == "") {       filenames[i] = inputDir + filenames[i];         }
173                                                 }
174                 
175                                                 ifstream in;
176                                                 int ableToOpen = m->openInputFile(filenames[i], in, "noerror");
177                                         
178                                                 //if you can't open it, try default location
179                                                 if (ableToOpen == 1) {
180                                                         if (m->getDefaultPath() != "") { //default path is set
181                                                                 string tryPath = m->getDefaultPath() + m->getSimpleName(filenames[i]);
182                                                                 m->mothurOut("Unable to open " + filenames[i] + ". Trying default " + tryPath); m->mothurOutEndLine();
183                                                                 ifstream in2;
184                                                                 ableToOpen = m->openInputFile(tryPath, in2, "noerror");
185                                                                 in2.close();
186                                                                 filenames[i] = tryPath;
187                                                         }
188                                                 }
189                                                 
190                                                 //if you can't open it, try default location
191                                                 if (ableToOpen == 1) {
192                                                         if (m->getOutputDir() != "") { //default path is set
193                                                                 string tryPath = m->getOutputDir() + m->getSimpleName(filenames[i]);
194                                                                 m->mothurOut("Unable to open " + filenames[i] + ". Trying output directory " + tryPath); m->mothurOutEndLine();
195                                                                 ifstream in2;
196                                                                 ableToOpen = m->openInputFile(tryPath, in2, "noerror");
197                                                                 in2.close();
198                                                                 filenames[i] = tryPath;
199                                                         }
200                                                 }
201                                                 
202                                                 in.close();
203                                                 
204                                                 if (ableToOpen == 1) { 
205                                                         m->mothurOut("Unable to open " + filenames[i] + ". It will be disregarded."); m->mothurOutEndLine();
206                                                         //erase from file list
207                                                         filenames.erase(filenames.begin()+i);
208                                                         i--;
209                                                 }else { m->setSFFFile(filenames[i]); }
210                                         }
211                                 }
212                                 
213                                 //make sure there is at least one valid file left
214                                 if (filenames.size() == 0) { m->mothurOut("no valid files."); m->mothurOutEndLine(); abort = true; }
215                         }
216                         
217                         accnosName = validParameter.validFile(parameters, "accnos", false);
218                         if (accnosName == "not found") { accnosName = "";  }
219                         else { 
220                                 hasAccnos = true;
221                                 m->splitAtDash(accnosName, accnosFileNames);
222                                 
223                                 //go through files and make sure they are good, if not, then disregard them
224                                 for (int i = 0; i < accnosFileNames.size(); i++) {
225                                         bool ignore = false;
226                                         if (accnosFileNames[i] == "current") { 
227                                                 accnosFileNames[i] = m->getAccnosFile(); 
228                                                 if (accnosFileNames[i] != "") {  m->mothurOut("Using " + accnosFileNames[i] + " as input file for the accnos parameter where you had given current."); m->mothurOutEndLine(); }
229                                                 else {  
230                                                         m->mothurOut("You have no current accnosfile, ignoring current."); m->mothurOutEndLine(); ignore=true; 
231                                                         //erase from file list
232                                                         accnosFileNames.erase(accnosFileNames.begin()+i);
233                                                         i--;
234                                                 }
235                                         }
236                                         
237                                         if (!ignore) {
238                                         
239                                                 if (inputDir != "") {
240                                                         string path = m->hasPath(accnosFileNames[i]);
241                                                         //if the user has not given a path then, add inputdir. else leave path alone.
242                                                         if (path == "") {       accnosFileNames[i] = inputDir + accnosFileNames[i];             }
243                                                 }
244                 
245                                                 ifstream in;
246                                                 int ableToOpen = m->openInputFile(accnosFileNames[i], in, "noerror");
247                                         
248                                                 //if you can't open it, try default location
249                                                 if (ableToOpen == 1) {
250                                                         if (m->getDefaultPath() != "") { //default path is set
251                                                                 string tryPath = m->getDefaultPath() + m->getSimpleName(accnosFileNames[i]);
252                                                                 m->mothurOut("Unable to open " + accnosFileNames[i] + ". Trying default " + tryPath); m->mothurOutEndLine();
253                                                                 ifstream in2;
254                                                                 ableToOpen = m->openInputFile(tryPath, in2, "noerror");
255                                                                 in2.close();
256                                                                 accnosFileNames[i] = tryPath;
257                                                         }
258                                                 }
259                                                 //if you can't open it, try default location
260                                                 if (ableToOpen == 1) {
261                                                         if (m->getOutputDir() != "") { //default path is set
262                                                                 string tryPath = m->getOutputDir() + m->getSimpleName(accnosFileNames[i]);
263                                                                 m->mothurOut("Unable to open " + accnosFileNames[i] + ". Trying output directory " + tryPath); m->mothurOutEndLine();
264                                                                 ifstream in2;
265                                                                 ableToOpen = m->openInputFile(tryPath, in2, "noerror");
266                                                                 in2.close();
267                                                                 accnosFileNames[i] = tryPath;
268                                                         }
269                                                 }
270                                                 in.close();
271                                                 
272                                                 if (ableToOpen == 1) { 
273                                                         m->mothurOut("Unable to open " + accnosFileNames[i] + ". It will be disregarded."); m->mothurOutEndLine();
274                                                         //erase from file list
275                                                         accnosFileNames.erase(accnosFileNames.begin()+i);
276                                                         i--;
277                                                 }
278                                         }
279                                 }
280                                 
281                                 //make sure there is at least one valid file left
282                                 if (accnosFileNames.size() == 0) { m->mothurOut("no valid files."); m->mothurOutEndLine(); abort = true; }
283                         }
284             
285             oligosfile = validParameter.validFile(parameters, "oligos", false);
286                         if (oligosfile == "not found") { oligosfile = "";  }
287                         else { 
288                                 hasOligos = true;
289                                 m->splitAtDash(oligosfile, oligosFileNames);
290                                 
291                                 //go through files and make sure they are good, if not, then disregard them
292                                 for (int i = 0; i < oligosFileNames.size(); i++) {
293                                         bool ignore = false;
294                                         if (oligosFileNames[i] == "current") { 
295                                                 oligosFileNames[i] = m->getOligosFile(); 
296                                                 if (oligosFileNames[i] != "") {  m->mothurOut("Using " + oligosFileNames[i] + " as input file for the accnos parameter where you had given current."); m->mothurOutEndLine(); }
297                                                 else {  
298                                                         m->mothurOut("You have no current oligosfile, ignoring current."); m->mothurOutEndLine(); ignore=true; 
299                                                         //erase from file list
300                                                         oligosFileNames.erase(oligosFileNames.begin()+i);
301                                                         i--;
302                                                 }
303                                         }
304                                         
305                                         if (!ignore) {
306                         
307                                                 if (inputDir != "") {
308                                                         string path = m->hasPath(oligosFileNames[i]);
309                                                         //if the user has not given a path then, add inputdir. else leave path alone.
310                                                         if (path == "") {       oligosFileNames[i] = inputDir + oligosFileNames[i];             }
311                                                 }
312                         
313                                                 ifstream in;
314                                                 int ableToOpen = m->openInputFile(oligosFileNames[i], in, "noerror");
315                         
316                                                 //if you can't open it, try default location
317                                                 if (ableToOpen == 1) {
318                                                         if (m->getDefaultPath() != "") { //default path is set
319                                                                 string tryPath = m->getDefaultPath() + m->getSimpleName(oligosFileNames[i]);
320                                                                 m->mothurOut("Unable to open " + oligosFileNames[i] + ". Trying default " + tryPath); m->mothurOutEndLine();
321                                                                 ifstream in2;
322                                                                 ableToOpen = m->openInputFile(tryPath, in2, "noerror");
323                                                                 in2.close();
324                                                                 oligosFileNames[i] = tryPath;
325                                                         }
326                                                 }
327                                                 //if you can't open it, try default location
328                                                 if (ableToOpen == 1) {
329                                                         if (m->getOutputDir() != "") { //default path is set
330                                                                 string tryPath = m->getOutputDir() + m->getSimpleName(oligosFileNames[i]);
331                                                                 m->mothurOut("Unable to open " + oligosFileNames[i] + ". Trying output directory " + tryPath); m->mothurOutEndLine();
332                                                                 ifstream in2;
333                                                                 ableToOpen = m->openInputFile(tryPath, in2, "noerror");
334                                                                 in2.close();
335                                                                 oligosFileNames[i] = tryPath;
336                                                         }
337                                                 }
338                                                 in.close();
339                                                 
340                                                 if (ableToOpen == 1) { 
341                                                         m->mothurOut("Unable to open " + oligosFileNames[i] + ". It will be disregarded."); m->mothurOutEndLine();
342                                                         //erase from file list
343                                                         oligosFileNames.erase(oligosFileNames.begin()+i);
344                                                         i--;
345                                                 }
346                                         }
347                                 }
348                                 
349                                 //make sure there is at least one valid file left
350                                 if (oligosFileNames.size() == 0) { m->mothurOut("no valid oligos files."); m->mothurOutEndLine(); abort = true; }
351                         }
352
353                         if (hasOligos) {
354                 split = 2;
355                                 if (oligosFileNames.size() != filenames.size()) { abort = true; m->mothurOut("If you provide a oligos file, you must have one for each sff file."); m->mothurOutEndLine(); }
356                         }
357             
358                         if (hasAccnos) {
359                                 if (accnosFileNames.size() != filenames.size()) { abort = true; m->mothurOut("If you provide a accnos file, you must have one for each sff file."); m->mothurOutEndLine(); }
360                         }
361                         
362                         string temp = validParameter.validFile(parameters, "qfile", false);                     if (temp == "not found"){       temp = "T";                             }
363                         qual = m->isTrue(temp); 
364                         
365                         temp = validParameter.validFile(parameters, "fasta", false);                            if (temp == "not found"){       temp = "T";                             }
366                         fasta = m->isTrue(temp); 
367                         
368                         temp = validParameter.validFile(parameters, "flow", false);                                     if (temp == "not found"){       temp = "T";                             }
369                         flow = m->isTrue(temp); 
370                         
371                         temp = validParameter.validFile(parameters, "trim", false);                                     if (temp == "not found"){       temp = "T";                             }
372                         trim = m->isTrue(temp); 
373             
374             temp = validParameter.validFile(parameters, "bdiffs", false);               if (temp == "not found") { temp = "0"; }
375                         m->mothurConvert(temp, bdiffs);
376                         
377                         temp = validParameter.validFile(parameters, "pdiffs", false);           if (temp == "not found") { temp = "0"; }
378                         m->mothurConvert(temp, pdiffs);
379             
380             temp = validParameter.validFile(parameters, "ldiffs", false);               if (temp == "not found") { temp = "0"; }
381                         m->mothurConvert(temp, ldiffs);
382             
383             temp = validParameter.validFile(parameters, "sdiffs", false);               if (temp == "not found") { temp = "0"; }
384                         m->mothurConvert(temp, sdiffs);
385                         
386                         temp = validParameter.validFile(parameters, "tdiffs", false);           if (temp == "not found") { int tempTotal = pdiffs + bdiffs + ldiffs + sdiffs;  temp = toString(tempTotal); }
387                         m->mothurConvert(temp, tdiffs);
388                         
389                         if(tdiffs == 0){        tdiffs = bdiffs + pdiffs + ldiffs + sdiffs;     }
390             
391                         temp = validParameter.validFile(parameters, "sfftxt", false);                           
392                         if (temp == "not found")        {       temp = "F";      sfftxt = false; sfftxtFilename = "";           }
393                         else if (m->isTrue(temp))       {       sfftxt = true;          sfftxtFilename = "";                            }
394                         else {
395                                 //you are a filename
396                                 if (inputDir != "") {
397                                         map<string,string>::iterator it = parameters.find("sfftxt");
398                                         //user has given a template file
399                                         if(it != parameters.end()){ 
400                                                 string path = m->hasPath(it->second);
401                                                 //if the user has not given a path then, add inputdir. else leave path alone.
402                                                 if (path == "") {       parameters["sfftxt"] = inputDir + it->second;           }
403                                         }
404                                 }
405                                 
406                                 sfftxtFilename = validParameter.validFile(parameters, "sfftxt", true);
407                                 if (sfftxtFilename == "not found") { sfftxtFilename = "";  }
408                                 else if (sfftxtFilename == "not open") { sfftxtFilename = "";  }
409                         }
410                         
411                         if ((sfftxtFilename == "") && (filenames.size() == 0)) {  
412                                 //if there is a current sff file, use it
413                                 string filename = m->getSFFFile(); 
414                                 if (filename != "") { filenames.push_back(filename); m->mothurOut("Using " + filename + " as input file for the sff parameter."); m->mothurOutEndLine(); }
415                                 else {  m->mothurOut("[ERROR]: you must provide a valid sff or sfftxt file."); m->mothurOutEndLine(); abort=true;  }
416                         }
417             
418             
419                 }
420         }
421         catch(exception& e) {
422                 m->errorOut(e, "SffInfoCommand", "SffInfoCommand");
423                 exit(1);
424         }
425 }
426 //**********************************************************************************************************************
427 int SffInfoCommand::execute(){
428         try {
429                 if (abort == true) { if (calledHelp) { return 0; }  return 2;   }
430                 
431                 for (int s = 0; s < filenames.size(); s++) {
432                         
433                         if (m->control_pressed) {  for (int i = 0; i < outputNames.size(); i++) {       m->mothurRemove(outputNames[i]);        } return 0; }
434                         
435                         int start = time(NULL);
436                         
437             filenames[s] = m->getFullPathName(filenames[s]);
438                         m->mothurOut("Extracting info from " + filenames[s] + " ..." ); m->mothurOutEndLine();
439                         
440                         string accnos = "";
441                         if (hasAccnos) { accnos = accnosFileNames[s]; }
442             
443             string oligos = "";
444             if (hasOligos) { oligos = oligosFileNames[s]; }
445                         
446                         int numReads = extractSffInfo(filenames[s], accnos, oligos);
447
448                         m->mothurOut("It took " + toString(time(NULL) - start) + " secs to extract " + toString(numReads) + ".");
449                 }
450                 
451                 if (sfftxtFilename != "") {  parseSffTxt(); }
452                 
453                 if (m->control_pressed) {  for (int i = 0; i < outputNames.size(); i++) {       m->mothurRemove(outputNames[i]);        } return 0; }
454                 
455                 //set fasta file as new current fastafile
456                 string current = "";
457                 itTypes = outputTypes.find("fasta");
458                 if (itTypes != outputTypes.end()) {
459                         if ((itTypes->second).size() != 0) { current = (itTypes->second)[0]; m->setFastaFile(current); }
460                 }
461                 
462                 itTypes = outputTypes.find("qfile");
463                 if (itTypes != outputTypes.end()) {
464                         if ((itTypes->second).size() != 0) { current = (itTypes->second)[0]; m->setQualFile(current); }
465                 }
466                 
467                 itTypes = outputTypes.find("flow");
468                 if (itTypes != outputTypes.end()) {
469                         if ((itTypes->second).size() != 0) { current = (itTypes->second)[0]; m->setFlowFile(current); }
470                 }
471                 
472                 //report output filenames
473                 m->mothurOutEndLine();
474                 m->mothurOut("Output File Names: "); m->mothurOutEndLine();
475                 for (int i = 0; i < outputNames.size(); i++) {  m->mothurOut(outputNames[i]); m->mothurOutEndLine();    }
476                 m->mothurOutEndLine();
477
478                 return 0;
479         }
480         catch(exception& e) {
481                 m->errorOut(e, "SffInfoCommand", "execute");
482                 exit(1);
483         }
484 }
485 //**********************************************************************************************************************
486 int SffInfoCommand::extractSffInfo(string input, string accnos, string oligos){
487         try {
488                 currentFileName = input;
489                 if (outputDir == "") {  outputDir += m->hasPath(input); }
490                 
491                 if (accnos != "")       {  readAccnosFile(accnos);  }
492                 else                            {       seqNames.clear();               }
493          
494         if (oligos != "")   {   readOligos(oligos);  split = 2;   }
495
496                 ofstream outSfftxt, outFasta, outQual, outFlow;
497                 string outFastaFileName, outQualFileName;
498         string rootName = outputDir + m->getRootName(m->getSimpleName(input));
499         if(rootName.find_last_of(".") == rootName.npos){ rootName += "."; }
500         
501         map<string, string> variables; 
502                 variables["[filename]"] = rootName;
503                 string sfftxtFileName = getOutputFileName("sfftxt",variables);
504                 string outFlowFileName = getOutputFileName("flow",variables);
505                 if (!trim) { variables["[tag]"] = "raw"; }
506                 outFastaFileName = getOutputFileName("fasta",variables);
507         outQualFileName = getOutputFileName("qfile",variables);
508         
509                 if (sfftxt) { m->openOutputFile(sfftxtFileName, outSfftxt); outSfftxt.setf(ios::fixed, ios::floatfield); outSfftxt.setf(ios::showpoint);  outputNames.push_back(sfftxtFileName);  outputTypes["sfftxt"].push_back(sfftxtFileName); }
510                 if (fasta)      { m->openOutputFile(outFastaFileName, outFasta);        outputNames.push_back(outFastaFileName); outputTypes["fasta"].push_back(outFastaFileName); }
511                 if (qual)       { m->openOutputFile(outQualFileName, outQual);          outputNames.push_back(outQualFileName); outputTypes["qfile"].push_back(outQualFileName);  }
512                 if (flow)       { m->openOutputFile(outFlowFileName, outFlow);          outputNames.push_back(outFlowFileName);  outFlow.setf(ios::fixed, ios::floatfield); outFlow.setf(ios::showpoint); outputTypes["flow"].push_back(outFlowFileName);  }
513                 
514                 ifstream in;
515                 in.open(input.c_str(), ios::binary);
516                 
517                 CommonHeader header; 
518                 readCommonHeader(in, header);
519         
520                 int count = 0;
521                 mycount = 0;
522                 
523                 //check magic number and version
524                 if (header.magicNumber != 779314790) { m->mothurOut("Magic Number is not correct, not a valid .sff file"); m->mothurOutEndLine(); return count; }
525                 if (header.version != "0001") { m->mothurOut("Version is not supported, only support version 0001."); m->mothurOutEndLine(); return count; }
526         
527                 //print common header
528                 if (sfftxt) {   printCommonHeader(outSfftxt, header);           }
529                 if (flow)       {       outFlow << header.numFlowsPerRead << endl;      }
530                         
531                 //read through the sff file
532                 while (!in.eof()) {
533                         
534                         bool print = true;
535                                                 
536                         //read data
537                         seqRead read;  Header readheader;
538                         readSeqData(in, read, header.numFlowsPerRead, readheader);
539             bool okay = sanityCheck(readheader, read);
540             if (!okay) { break; }
541             
542                         //if you have provided an accosfile and this seq is not in it, then dont print
543                         if (seqNames.size() != 0) {   if (seqNames.count(readheader.name) == 0) { print = false; }  }
544                         
545                         //print 
546                         if (print) {
547                                 if (sfftxt) { printHeader(outSfftxt, readheader); printSffTxtSeqData(outSfftxt, read, readheader); }
548                                 if (fasta)      {       printFastaSeqData(outFasta, read, readheader);  }
549                                 if (qual)       {       printQualSeqData(outQual, read, readheader);    }
550                                 if (flow)       {       printFlowSeqData(outFlow, read, readheader);    }
551                         }
552                         
553                         count++;
554                         mycount++;
555         
556                         //report progress
557                         if((count+1) % 10000 == 0){     m->mothurOut(toString(count+1)); m->mothurOutEndLine();         }
558                 
559                         if (m->control_pressed) { count = 0; break;   }
560                         
561                         if (count >= header.numReads) { break; }
562                 }
563                 
564                 //report progress
565                 if (!m->control_pressed) {   if((count) % 10000 != 0){  m->mothurOut(toString(count)); m->mothurOutEndLine();           }  }
566                 
567                 in.close();
568                 
569                 if (sfftxt) {  outSfftxt.close();       }
570                 if (fasta)      {  outFasta.close();    }
571                 if (qual)       {  outQual.close();             }
572                 if (flow)       {  outFlow.close();             }
573                 
574         if (split > 1) {
575             //create new common headers for each file with the correct number of reads
576             adjustCommonHeader(header);
577             
578                         map<string, string>::iterator it;
579                         set<string> namesToRemove;
580                         for(int i=0;i<filehandles.size();i++){
581                                 for(int j=0;j<filehandles[0].size();j++){
582                                         if (filehandles[i][j] != "") {
583                                                 if (namesToRemove.count(filehandles[i][j]) == 0) {
584                                                         if(m->isBlank(filehandles[i][j])){
585                                                                 m->mothurRemove(filehandles[i][j]);
586                                 m->mothurRemove(filehandlesHeaders[i][j]);
587                                                                 namesToRemove.insert(filehandles[i][j]);
588                             }
589                                                 }
590                                         }
591                                 }
592                         }
593             
594             //append new header to reads
595             for (int i = 0; i < filehandles.size(); i++) {
596                 for (int j = 0; j < filehandles[i].size(); j++) {
597                     m->appendFiles(filehandles[i][j], filehandlesHeaders[i][j]);
598                     m->renameFile(filehandlesHeaders[i][j], filehandles[i][j]);
599                     m->mothurRemove(filehandlesHeaders[i][j]);
600                     if (numSplitReads[i][j] == 0) { m->mothurRemove(filehandles[i][j]); }
601                 }
602             }
603                         
604                         //remove names for outputFileNames, just cleans up the output
605                         for(int i = 0; i < outputNames.size(); i++) { 
606                 if (namesToRemove.count(outputNames[i]) != 0) { 
607                     outputNames.erase(outputNames.begin()+i);
608                     i--;
609                 } 
610             }
611             
612             if(m->isBlank(noMatchFile)){  m->mothurRemove(noMatchFile); }
613             else { outputNames.push_back(noMatchFile); outputTypes["sff"].push_back(noMatchFile); }
614         }
615         
616                 return count;
617         }
618         catch(exception& e) {
619                 m->errorOut(e, "SffInfoCommand", "extractSffInfo");
620                 exit(1);
621         }
622 }
623 //**********************************************************************************************************************
624 int SffInfoCommand::readCommonHeader(ifstream& in, CommonHeader& header){
625         try {
626         
627                 if (!in.eof()) {
628
629                         //read magic number
630                         char buffer[4];
631                         in.read(buffer, 4);
632                         header.magicNumber = be_int4(*(unsigned int *)(&buffer));
633             
634                         //read version
635                         char buffer9[4];
636                         in.read(buffer9, 4);
637                         header.version = "";
638                         for (int i = 0; i < 4; i++) {  header.version += toString((int)(buffer9[i]));  }
639     
640                         //read offset
641                         char buffer2 [8];
642                         in.read(buffer2, 8);
643                         header.indexOffset =  be_int8(*(unsigned long long *)(&buffer2));
644                         
645                         //read index length
646                         char buffer3 [4];
647                         in.read(buffer3, 4);
648                         header.indexLength =  be_int4(*(unsigned int *)(&buffer3));
649             
650                         //read num reads
651                         char buffer4 [4];
652                         in.read(buffer4, 4);
653                         header.numReads =  be_int4(*(unsigned int *)(&buffer4));
654                                 
655                         //read header length
656                         char buffer5 [2];
657                         in.read(buffer5, 2);
658                         header.headerLength =  be_int2(*(unsigned short *)(&buffer5));
659                                         
660                         //read key length
661                         char buffer6 [2];
662                         in.read(buffer6, 2);
663                         header.keyLength = be_int2(*(unsigned short *)(&buffer6));
664                         
665                         //read number of flow reads
666                         char buffer7 [2];
667                         in.read(buffer7, 2);
668                         header.numFlowsPerRead =  be_int2(*(unsigned short *)(&buffer7));
669                                 
670                         //read format code
671                         char buffer8 [1];
672                         in.read(buffer8, 1);
673                         header.flogramFormatCode = (int)(buffer8[0]);
674                         
675                         //read flow chars
676                         char* tempBuffer = new char[header.numFlowsPerRead];
677                         in.read(&(*tempBuffer), header.numFlowsPerRead); 
678                         header.flowChars = tempBuffer;
679                         if (header.flowChars.length() > header.numFlowsPerRead) { header.flowChars = header.flowChars.substr(0, header.numFlowsPerRead);  }
680                         delete[] tempBuffer;
681                         
682                         //read key
683                         char* tempBuffer2 = new char[header.keyLength];
684                         in.read(&(*tempBuffer2), header.keyLength);
685                         header.keySequence = tempBuffer2;
686                         if (header.keySequence.length() > header.keyLength) { header.keySequence = header.keySequence.substr(0, header.keyLength);  }
687                         delete[] tempBuffer2;
688                         
689                         /* Pad to 8 chars */
690                         unsigned long long spotInFile = in.tellg();
691                         unsigned long long spot = (spotInFile + 7)& ~7;  // ~ inverts
692                         in.seekg(spot);
693             
694         }else{
695                         m->mothurOut("Error reading sff common header."); m->mothurOutEndLine();
696                 }
697         
698                 return 0;
699         
700         }
701         catch(exception& e) {
702                 m->errorOut(e, "SffInfoCommand", "readCommonHeader");
703                 exit(1);
704         }
705 }
706 //**********************************************************************************************************************
707 int SffInfoCommand::adjustCommonHeader(CommonHeader header){
708         try {
709
710         char* mybuffer = new char[4];
711         ifstream in;
712         in.open(currentFileName.c_str(), ios::binary);
713         
714         //magic number
715         in.read(mybuffer,4);
716         for (int i = 0; i < filehandlesHeaders.size(); i++) {  
717             for (int j = 0; j < filehandlesHeaders[i].size(); j++) {
718                 ofstream out;
719                 m->openOutputFileAppend(filehandlesHeaders[i][j], out);
720                 out.write(mybuffer, in.gcount()); 
721                 out.close();
722             }
723         }
724         delete[] mybuffer;
725         
726         //version
727         mybuffer = new char[4];
728         in.read(mybuffer,4);
729         for (int i = 0; i < filehandlesHeaders.size(); i++) {  
730             for (int j = 0; j < filehandlesHeaders[i].size(); j++) {
731                 ofstream out;
732                 m->openOutputFileAppend(filehandlesHeaders[i][j], out);
733                 out.write(mybuffer, in.gcount()); 
734                 out.close();
735             }
736         }
737         delete[] mybuffer;
738         
739         //offset
740         mybuffer = new char[8];
741         in.read(mybuffer,8);
742         for (int i = 0; i < filehandlesHeaders.size(); i++) {  
743             for (int j = 0; j < filehandlesHeaders[i].size(); j++) {
744                 unsigned long long offset = 0;
745                 char* thisbuffer = new char[8];
746                 thisbuffer[0] = (offset >> 56) & 0xFF;
747                 thisbuffer[1] = (offset >> 48) & 0xFF;
748                 thisbuffer[2] = (offset >> 40) & 0xFF;
749                 thisbuffer[3] = (offset >> 32) & 0xFF;
750                 thisbuffer[4] = (offset >> 24) & 0xFF;
751                 thisbuffer[5] = (offset >> 16) & 0xFF;
752                 thisbuffer[6] = (offset >> 8) & 0xFF;
753                 thisbuffer[7] = offset & 0xFF;
754                 ofstream out;
755                 m->openOutputFileAppend(filehandlesHeaders[i][j], out);
756                 out.write(thisbuffer, 8);
757                 out.close();
758             }
759         }
760         delete[] mybuffer;
761             
762                         
763         //read index length
764                 mybuffer = new char[4];
765         in.read(mybuffer,4);
766         for (int i = 0; i < filehandlesHeaders.size(); i++) {  
767             for (int j = 0; j < filehandlesHeaders[i].size(); j++) {
768                 ofstream out;
769                 m->openOutputFileAppend(filehandlesHeaders[i][j], out);
770                 int offset = 0;
771                 char* thisbuffer = new char[4];
772                 thisbuffer[0] = (offset >> 24) & 0xFF;
773                 thisbuffer[1] = (offset >> 16) & 0xFF;
774                 thisbuffer[2] = (offset >> 8) & 0xFF;
775                 thisbuffer[3] = offset & 0xFF;
776                 out.write(thisbuffer, 4);
777                 out.close();
778             }
779         }
780         delete[] mybuffer;
781                 
782         //change num reads
783         mybuffer = new char[4];
784         in.read(mybuffer,4);
785         delete[] mybuffer;
786         for (int i = 0; i < filehandlesHeaders.size(); i++) {  
787             for (int j = 0; j < filehandlesHeaders[i].size(); j++) {
788                 ofstream out;
789                 m->openOutputFileAppend(filehandlesHeaders[i][j], out);
790                 //convert number of reads to 4 byte char*
791                 char* thisbuffer = new char[4];
792                 thisbuffer[0] = (numSplitReads[i][j] >> 24) & 0xFF;
793                 thisbuffer[1] = (numSplitReads[i][j] >> 16) & 0xFF;
794                 thisbuffer[2] = (numSplitReads[i][j] >> 8) & 0xFF;
795                 thisbuffer[3] = numSplitReads[i][j] & 0xFF;
796                 out.write(thisbuffer, 4);
797                 out.close();
798                 delete[] thisbuffer;
799             }
800         }
801             
802         //read header length
803         mybuffer = new char[2];
804         in.read(mybuffer,2);
805         for (int i = 0; i < filehandlesHeaders.size(); i++) {  
806             for (int j = 0; j < filehandlesHeaders[i].size(); j++) {
807                 ofstream out;
808                 m->openOutputFileAppend(filehandlesHeaders[i][j], out);
809                 out.write(mybuffer, in.gcount()); 
810                 out.close();
811             }
812         }
813         delete[] mybuffer;
814             
815         //read key length
816         mybuffer = new char[2];
817         in.read(mybuffer,2);
818         for (int i = 0; i < filehandlesHeaders.size(); i++) {  
819             for (int j = 0; j < filehandlesHeaders[i].size(); j++) {
820                 ofstream out;
821                 m->openOutputFileAppend(filehandlesHeaders[i][j], out);
822                 out.write(mybuffer, in.gcount()); 
823                 out.close();
824             }
825         }
826         delete[] mybuffer;
827                         
828         //read number of flow reads
829         mybuffer = new char[2];
830         in.read(mybuffer,2);
831         for (int i = 0; i < filehandlesHeaders.size(); i++) {  
832             for (int j = 0; j < filehandlesHeaders[i].size(); j++) {
833                 ofstream out;
834                 m->openOutputFileAppend(filehandlesHeaders[i][j], out);
835                 out.write(mybuffer, in.gcount()); 
836                 out.close();
837             }
838         }
839         delete[] mybuffer;
840             
841         //read format code
842         mybuffer = new char[1];
843         in.read(mybuffer,1);
844         for (int i = 0; i < filehandlesHeaders.size(); i++) {  
845             for (int j = 0; j < filehandlesHeaders[i].size(); j++) {
846                 ofstream out;
847                 m->openOutputFileAppend(filehandlesHeaders[i][j], out);
848                 out.write(mybuffer, in.gcount()); 
849                 out.close();
850             }
851         }
852         delete[] mybuffer;
853                         
854         //read flow chars
855         mybuffer = new char[header.numFlowsPerRead];
856         in.read(mybuffer,header.numFlowsPerRead);
857         for (int i = 0; i < filehandlesHeaders.size(); i++) {  
858             for (int j = 0; j < filehandlesHeaders[i].size(); j++) {
859                 ofstream out;
860                 m->openOutputFileAppend(filehandlesHeaders[i][j], out);
861                 out.write(mybuffer, in.gcount()); 
862                 out.close();
863             }
864         }
865         delete[] mybuffer;
866                         
867         //read key
868         mybuffer = new char[header.keyLength];
869         in.read(mybuffer,header.keyLength);
870         for (int i = 0; i < filehandlesHeaders.size(); i++) {  
871             for (int j = 0; j < filehandlesHeaders[i].size(); j++) {
872                 ofstream out;
873                 m->openOutputFileAppend(filehandlesHeaders[i][j], out);
874                 out.write(mybuffer, in.gcount()); 
875                 out.close();
876             }
877         }
878         delete[] mybuffer;
879         
880                         
881         /* Pad to 8 chars */
882         unsigned long long spotInFile = in.tellg();
883         unsigned long long spot = (spotInFile + 7)& ~7;  // ~ inverts
884         in.seekg(spot);
885         
886         mybuffer = new char[spot-spotInFile];
887         for (int i = 0; i < filehandlesHeaders.size(); i++) { 
888             for (int j = 0; j < filehandlesHeaders[i].size(); j++) {
889                 ofstream out;
890                 m->openOutputFileBinaryAppend(filehandlesHeaders[i][j], out);
891                 out.write(mybuffer, spot-spotInFile); 
892                 out.close();
893             }
894         }
895         delete[] mybuffer;
896         in.close();
897                 return 0;
898         
899         }
900         catch(exception& e) {
901                 m->errorOut(e, "SffInfoCommand", "adjustCommonHeader");
902                 exit(1);
903         }
904 }
905 //**********************************************************************************************************************
906 int SffInfoCommand::readSeqData(ifstream& in, seqRead& read, int numFlowReads, Header& header){
907         try {
908         unsigned long long startSpotInFile = in.tellg();
909                 if (!in.eof()) {
910             
911             /*****************************************/
912             //read header
913             
914             //read header length
915                         char buffer [2];
916                         in.read(buffer, 2);
917                         header.headerLength = be_int2(*(unsigned short *)(&buffer));
918             
919                         //read name length
920                         char buffer2 [2];
921                         in.read(buffer2, 2);
922                         header.nameLength = be_int2(*(unsigned short *)(&buffer2));
923             
924                         //read num bases
925                         char buffer3 [4];
926                         in.read(buffer3, 4);
927                         header.numBases =  be_int4(*(unsigned int *)(&buffer3));
928                         
929                         //read clip qual left
930                         char buffer4 [2];
931                         in.read(buffer4, 2);
932                         header.clipQualLeft =  be_int2(*(unsigned short *)(&buffer4));
933                         header.clipQualLeft = 5; 
934                         
935                         //read clip qual right
936                         char buffer5 [2];
937                         in.read(buffer5, 2);
938                         header.clipQualRight =  be_int2(*(unsigned short *)(&buffer5));
939             
940                         //read clipAdapterLeft
941                         char buffer6 [2];
942                         in.read(buffer6, 2);
943                         header.clipAdapterLeft = be_int2(*(unsigned short *)(&buffer6));
944             
945                         //read clipAdapterRight
946                         char buffer7 [2];
947                         in.read(buffer7, 2);
948                         header.clipAdapterRight = be_int2(*(unsigned short *)(&buffer7));
949             
950                         //read name
951                         char* tempBuffer = new char[header.nameLength];
952                         in.read(&(*tempBuffer), header.nameLength);
953                         header.name = tempBuffer;
954                         if (header.name.length() > header.nameLength) { header.name = header.name.substr(0, header.nameLength);  }
955                         delete[] tempBuffer;
956                         
957                         //extract info from name
958                         decodeName(header.timestamp, header.region, header.xy, header.name);
959                         
960                         /* Pad to 8 chars */
961                         unsigned long long spotInFile = in.tellg();
962                         unsigned long long spot = (spotInFile + 7)& ~7;
963                         in.seekg(spot);
964
965             /*****************************************/
966             //sequence read 
967             
968                         //read flowgram
969                         read.flowgram.resize(numFlowReads);
970                         for (int i = 0; i < numFlowReads; i++) {  
971                                 char buffer [2];
972                                 in.read(buffer, 2);
973                                 read.flowgram[i] = be_int2(*(unsigned short *)(&buffer));
974                         }
975             
976                         //read flowIndex
977                         read.flowIndex.resize(header.numBases);
978                         for (int i = 0; i < header.numBases; i++) {  
979                                 char temp[1];
980                                 in.read(temp, 1);
981                                 read.flowIndex[i] = be_int1(*(unsigned char *)(&temp));
982                         }
983         
984                         //read bases
985                         char* tempBuffer6 = new char[header.numBases];
986                         in.read(&(*tempBuffer6), header.numBases);
987                         read.bases = tempBuffer6;
988                         if (read.bases.length() > header.numBases) { read.bases = read.bases.substr(0, header.numBases);  }
989                         delete[] tempBuffer6;
990
991                         //read qual scores
992                         read.qualScores.resize(header.numBases);
993                         for (int i = 0; i < header.numBases; i++) {  
994                                 char temp[1];
995                                 in.read(temp, 1);
996                                 read.qualScores[i] = be_int1(*(unsigned char *)(&temp));
997                         }
998         
999                         /* Pad to 8 chars */
1000                         spotInFile = in.tellg();
1001                         spot = (spotInFile + 7)& ~7;
1002                         in.seekg(spot);
1003             
1004             if (split > 1) {
1005                 char * mybuffer;
1006                 mybuffer = new char [spot-startSpotInFile];
1007                 ifstream in2;
1008                 in2.open(currentFileName.c_str(), ios::binary);
1009                 in2.seekg(startSpotInFile);
1010                 in2.read(mybuffer,spot-startSpotInFile);
1011                 in2.close();
1012                 
1013                 int barcodeIndex, primerIndex;
1014                 int trashCodeLength = findGroup(header, read, barcodeIndex, primerIndex);
1015                                 
1016                 if(trashCodeLength == 0){
1017                     ofstream out;
1018                     m->openOutputFileBinaryAppend(filehandles[barcodeIndex][primerIndex], out);
1019                     out.write(mybuffer, in2.gcount()); 
1020                     out.close();
1021                     delete[] mybuffer;
1022                     numSplitReads[barcodeIndex][primerIndex]++;
1023                                 }
1024                                 else{
1025                                         ofstream out;
1026                     m->openOutputFileBinaryAppend(noMatchFile, out);
1027                     out.write(mybuffer, in2.gcount()); 
1028                     out.close();
1029                     delete[] mybuffer;
1030                                 }
1031                                 
1032                         }
1033                 }else{
1034                         m->mothurOut("Error reading."); m->mothurOutEndLine();
1035                 }
1036
1037                 return 0;
1038         }
1039         catch(exception& e) {
1040                 m->errorOut(e, "SffInfoCommand", "readSeqData");
1041                 exit(1);
1042         }
1043 }
1044 //**********************************************************************************************************************
1045 int SffInfoCommand::findGroup(Header header, seqRead read, int& barcode, int& primer) {
1046         try {
1047         //find group read belongs to
1048         TrimOligos trimOligos(pdiffs, bdiffs, ldiffs, sdiffs, primers, barcodes, revPrimer, linker, spacer);
1049         
1050         int success = 1;
1051         string trashCode = "";
1052         int currentSeqsDiffs = 0;
1053         
1054         string seq = read.bases;
1055         
1056         if (trim) {
1057             if(header.clipQualRight < header.clipQualLeft){
1058                 if (header.clipQualRight == 0) { //don't trim right
1059                     seq = seq.substr(header.clipQualLeft-1);
1060                 }else {
1061                     seq = "NNNN";
1062                 }
1063             }
1064             else if((header.clipQualRight != 0) && ((header.clipQualRight-header.clipQualLeft) >= 0)){
1065                 seq = seq.substr((header.clipQualLeft-1), (header.clipQualRight-header.clipQualLeft));
1066             }
1067             else {
1068                 seq = seq.substr(header.clipQualLeft-1);
1069             }
1070         }else{
1071             //if you wanted the sfftxt then you already converted the bases to the right case
1072             if (!sfftxt) {
1073                 int endValue = header.clipQualRight;
1074                 //make the bases you want to clip lowercase and the bases you want to keep upper case
1075                 if(endValue == 0){      endValue = seq.length();        }
1076                 for (int i = 0; i < (header.clipQualLeft-1); i++) { seq[i] = tolower(seq[i]);  }
1077                 for (int i = (header.clipQualLeft-1); i < (endValue-1); i++)  {   seq[i] = toupper(seq[i]);  }
1078                 for (int i = (endValue-1); i < seq.length(); i++) {   seq[i] = tolower(seq[i]);  }
1079             }
1080         }
1081         
1082         Sequence currSeq(header.name, seq);
1083         QualityScores currQual;
1084         
1085         if(numLinkers != 0){
1086             success = trimOligos.stripLinker(currSeq, currQual);
1087             if(success > ldiffs)                {       trashCode += 'k';       }
1088             else{ currentSeqsDiffs += success;  }
1089             
1090         }
1091         
1092         if(barcodes.size() != 0){
1093             success = trimOligos.stripBarcode(currSeq, currQual, barcode);
1094             if(success > bdiffs)                {       trashCode += 'b';       }
1095             else{ currentSeqsDiffs += success;  }
1096         }
1097         
1098         if(numSpacers != 0){
1099             success = trimOligos.stripSpacer(currSeq, currQual);
1100             if(success > sdiffs)                {       trashCode += 's';       }
1101             else{ currentSeqsDiffs += success;  }
1102             
1103         }
1104         
1105         if(numFPrimers != 0){
1106             success = trimOligos.stripForward(currSeq, currQual, primer, true);
1107             if(success > pdiffs)                {       trashCode += 'f';       }
1108             else{ currentSeqsDiffs += success;  }
1109         }
1110         
1111         if (currentSeqsDiffs > tdiffs)  {       trashCode += 't';   }
1112         
1113         if(revPrimer.size() != 0){
1114             success = trimOligos.stripReverse(currSeq, currQual);
1115             if(!success)                                {       trashCode += 'r';       }
1116         }
1117
1118         
1119         return trashCode.length();
1120     }
1121         catch(exception& e) {
1122                 m->errorOut(e, "SffInfoCommand", "findGroup");
1123                 exit(1);
1124         }
1125 }     
1126 //**********************************************************************************************************************
1127 int SffInfoCommand::decodeName(string& timestamp, string& region, string& xy, string name) {
1128         try {
1129                 
1130                 if (name.length() >= 6) {
1131                         string time = name.substr(0, 6);
1132                         unsigned int timeNum = m->fromBase36(time);
1133                         
1134                         int q1 = timeNum / 60;
1135                         int sec = timeNum - 60 * q1;
1136                         int q2 = q1 / 60;
1137                         int minute = q1 - 60 * q2;
1138                         int q3 = q2 / 24;
1139                         int hr = q2 - 24 * q3;
1140                         int q4 = q3 / 32;
1141                         int day = q3 - 32 * q4;
1142                         int q5 = q4 / 13;
1143                         int mon = q4 - 13 * q5;
1144                         int year = 2000 + q5;
1145                 
1146                         timestamp = toString(year) + "_" + toString(mon) + "_" + toString(day) + "_" + toString(hr) + "_" + toString(minute) + "_" + toString(sec);
1147                 }
1148                 
1149                 if (name.length() >= 9) {
1150                         region = name.substr(7, 2);
1151                 
1152                         string xyNum = name.substr(9);
1153                         unsigned int myXy = m->fromBase36(xyNum);
1154                         int x = myXy >> 12;
1155                         int y = myXy & 4095;
1156                 
1157                         xy = toString(x) + "_" + toString(y);
1158                 }
1159                 
1160                 return 0;
1161         }
1162         catch(exception& e) {
1163                 m->errorOut(e, "SffInfoCommand", "decodeName");
1164                 exit(1);
1165         }
1166 }
1167 //**********************************************************************************************************************
1168 int SffInfoCommand::printCommonHeader(ofstream& out, CommonHeader& header) {
1169         try {
1170         
1171                 out << "Common Header:\nMagic Number: " << header.magicNumber << endl;
1172                 out << "Version: " << header.version << endl;
1173                 out << "Index Offset: " << header.indexOffset << endl;
1174                 out << "Index Length: " << header.indexLength << endl;
1175                 out << "Number of Reads: " << header.numReads << endl;
1176                 out << "Header Length: " << header.headerLength << endl;
1177                 out << "Key Length: " << header.keyLength << endl;
1178                 out << "Number of Flows: " << header.numFlowsPerRead << endl;
1179                 out << "Format Code: " << header.flogramFormatCode << endl;
1180                 out << "Flow Chars: " << header.flowChars << endl;
1181                 out << "Key Sequence: " << header.keySequence << endl << endl;
1182                         
1183                 return 0;
1184         }
1185         catch(exception& e) {
1186                 m->errorOut(e, "SffInfoCommand", "printCommonHeader");
1187                 exit(1);
1188         }
1189 }
1190 //**********************************************************************************************************************
1191 int SffInfoCommand::printHeader(ofstream& out, Header& header) {
1192         try {
1193                 
1194                 out << ">" << header.name << endl;
1195                 out << "Run Prefix: " << header.timestamp << endl;
1196                 out << "Region #:  " << header.region << endl;
1197                 out << "XY Location: " << header.xy << endl << endl;
1198                 
1199                 out << "Run Name:  " << endl;
1200                 out << "Analysis Name:  " << endl;
1201                 out << "Full Path: " << endl << endl;
1202                 
1203                 out << "Read Header Len: " << header.headerLength << endl;
1204                 out << "Name Length: " << header.nameLength << endl;
1205                 out << "# of Bases: " << header.numBases << endl;
1206                 out << "Clip Qual Left: " << header.clipQualLeft << endl;
1207                 out << "Clip Qual Right: " << header.clipQualRight << endl;
1208                 out << "Clip Adap Left: " << header.clipAdapterLeft << endl;
1209                 out << "Clip Adap Right: " << header.clipAdapterRight << endl << endl;
1210                 
1211                 return 0;
1212         }
1213         catch(exception& e) {
1214                 m->errorOut(e, "SffInfoCommand", "printHeader");
1215                 exit(1);
1216         }
1217 }
1218 //**********************************************************************************************************************
1219 bool SffInfoCommand::sanityCheck(Header& header, seqRead& read) {
1220         try {
1221         bool okay = true;
1222         string message = "[WARNING]: Your sff file may be corrupted! Sequence: " + header.name + "\n";
1223         
1224         if (header.clipQualLeft > read.bases.length()) {
1225             okay = false; message += "Clip Qual Left = " + toString(header.clipQualLeft) + ", but we only read " + toString(read.bases.length()) + " bases.\n";
1226         }
1227         if (header.clipQualRight > read.bases.length()) {
1228             okay = false; message += "Clip Qual Right = " + toString(header.clipQualRight) + ", but we only read " + toString(read.bases.length()) + " bases.\n";
1229         }
1230         if (header.clipQualLeft > read.qualScores.size()) {
1231             okay = false; message += "Clip Qual Left = " + toString(header.clipQualLeft) + ", but we only read " + toString(read.qualScores.size()) + " quality scores.\n";
1232         }
1233         if (header.clipQualRight > read.qualScores.size()) {
1234             okay = false; message += "Clip Qual Right = " + toString(header.clipQualRight) + ", but we only read " + toString(read.qualScores.size()) + " quality scores.\n";
1235         }
1236         
1237         if (okay == false) {
1238             m->mothurOut(message); m->mothurOutEndLine();
1239         }
1240         
1241                 return okay;
1242         }
1243         catch(exception& e) {
1244                 m->errorOut(e, "SffInfoCommand", "sanityCheck");
1245                 exit(1);
1246         }
1247 }
1248 //**********************************************************************************************************************
1249 int SffInfoCommand::printSffTxtSeqData(ofstream& out, seqRead& read, Header& header) {
1250         try {
1251                 out << "Flowgram: ";
1252                 for (int i = 0; i < read.flowgram.size(); i++) { out << setprecision(2) << (read.flowgram[i]/(float)100) << '\t';  }
1253                 
1254                 out << endl <<  "Flow Indexes: ";
1255                 int sum = 0;
1256                 for (int i = 0; i < read.flowIndex.size(); i++) {  sum +=  read.flowIndex[i];  out << sum << '\t'; }
1257                 
1258                 //make the bases you want to clip lowercase and the bases you want to keep upper case
1259         int endValue = header.clipQualRight;
1260                 if(endValue == 0){      endValue = read.bases.length(); }
1261                 for (int i = 0; i < (header.clipQualLeft-1); i++) { read.bases[i] = tolower(read.bases[i]); }
1262                 for (int i = (header.clipQualLeft-1); i < (endValue-1); i++) {   read.bases[i] = toupper(read.bases[i]);  }
1263                 for (int i = (endValue-1); i < read.bases.length(); i++) {   read.bases[i] = tolower(read.bases[i]);  }
1264                 
1265                 out << endl <<  "Bases: " << read.bases << endl << "Quality Scores: ";
1266                 for (int i = 0; i < read.qualScores.size(); i++) {   out << read.qualScores[i] << '\t';  }
1267         
1268                 
1269                 out << endl << endl;
1270                 
1271                 return 0;
1272         }
1273         catch(exception& e) {
1274                 m->errorOut(e, "SffInfoCommand", "printSffTxtSeqData");
1275                 exit(1);
1276         }
1277 }
1278 //**********************************************************************************************************************
1279 int SffInfoCommand::printFastaSeqData(ofstream& out, seqRead& read, Header& header) {
1280         try {
1281                 string seq = read.bases;
1282                 
1283         if (trim) {
1284                         if(header.clipQualRight < header.clipQualLeft){
1285                                 if (header.clipQualRight == 0) { //don't trim right
1286                     seq = seq.substr(header.clipQualLeft-1);
1287                 }else {
1288                     seq = "NNNN";
1289                 }
1290                         }
1291                         else if((header.clipQualRight != 0) && ((header.clipQualRight-header.clipQualLeft) >= 0)){
1292                                 seq = seq.substr((header.clipQualLeft-1), (header.clipQualRight-header.clipQualLeft));
1293                         }
1294                         else {
1295                                 seq = seq.substr(header.clipQualLeft-1);
1296                         }
1297                 }else{
1298                         //if you wanted the sfftxt then you already converted the bases to the right case
1299                         if (!sfftxt) {
1300                 int endValue = header.clipQualRight;
1301                                 //make the bases you want to clip lowercase and the bases you want to keep upper case
1302                                 if(endValue == 0){      endValue = seq.length();        }
1303                                 for (int i = 0; i < (header.clipQualLeft-1); i++) { seq[i] = tolower(seq[i]);  }
1304                                 for (int i = (header.clipQualLeft-1); i < (endValue-1); i++)  {   seq[i] = toupper(seq[i]);  }
1305                                 for (int i = (endValue-1); i < seq.length(); i++) {   seq[i] = tolower(seq[i]);  }
1306                         }
1307                 }
1308                 
1309                 out << ">" << header.name  << " xy=" << header.xy << endl;
1310                 out << seq << endl;
1311                 
1312                 return 0;
1313         }
1314         catch(exception& e) {
1315                 m->errorOut(e, "SffInfoCommand", "printFastaSeqData");
1316                 exit(1);
1317         }
1318 }
1319
1320 //**********************************************************************************************************************
1321 int SffInfoCommand::printQualSeqData(ofstream& out, seqRead& read, Header& header) {
1322         try {
1323                 
1324                 if (trim) {
1325                         if(header.clipQualRight < header.clipQualLeft){
1326                 if (header.clipQualRight == 0) { //don't trim right
1327                     out << ">" << header.name << " xy=" << header.xy << " length=" << (read.qualScores.size()-header.clipQualLeft) << endl;
1328                     for (int i = (header.clipQualLeft-1); i < read.qualScores.size(); i++) {   out << read.qualScores[i] << '\t';       }       
1329                 }else {
1330                     out << ">" << header.name << " xy=" << header.xy << endl;
1331                     out << "0\t0\t0\t0";
1332                 }
1333                         }
1334                         else if((header.clipQualRight != 0) && ((header.clipQualRight-header.clipQualLeft) >= 0)){
1335                                 out << ">" << header.name << " xy=" << header.xy << " length=" << (header.clipQualRight-header.clipQualLeft) << endl;
1336                                 for (int i = (header.clipQualLeft-1); i < (header.clipQualRight-1); i++) {   out << read.qualScores[i] << '\t'; }
1337                         }
1338                         else{
1339                                 out << ">" << header.name << " xy=" << header.xy << " length=" << (header.clipQualRight-header.clipQualLeft) << endl;
1340                                 for (int i = (header.clipQualLeft-1); i < read.qualScores.size(); i++) {   out << read.qualScores[i] << '\t';   }                       
1341                         }
1342                 }else{
1343                         out << ">" << header.name << " xy=" << header.xy << " length=" << read.qualScores.size() << endl;
1344                         for (int i = 0; i < read.qualScores.size(); i++) {   out << read.qualScores[i] << '\t';  }
1345                 }
1346                 
1347                 out << endl;
1348                 
1349                 return 0;
1350         }
1351         catch(exception& e) {
1352                 m->errorOut(e, "SffInfoCommand", "printQualSeqData");
1353                 exit(1);
1354         }
1355 }
1356
1357 //**********************************************************************************************************************
1358 int SffInfoCommand::printFlowSeqData(ofstream& out, seqRead& read, Header& header) {
1359         try {
1360         
1361         int endValue = header.clipQualRight;
1362         if (header.clipQualRight == 0) {
1363             endValue = read.flowIndex.size();
1364             if (m->debug) { m->mothurOut("[DEBUG]: " + header.name + " has clipQualRight=0.\n"); }
1365         }
1366         if(endValue > header.clipQualLeft){
1367             
1368             int rightIndex = 0;
1369             for (int i = 0; i < endValue; i++) {  rightIndex +=  read.flowIndex[i];      }
1370             
1371             out << header.name << ' ' << rightIndex;
1372             for (int i = 0; i < read.flowgram.size(); i++) { out << setprecision(2) << ' ' << (read.flowgram[i]/(float)100);  }
1373             out << endl;
1374         }
1375                 
1376                 
1377                 return 0;
1378         }
1379         catch(exception& e) {
1380                 m->errorOut(e, "SffInfoCommand", "printFlowSeqData");
1381                 exit(1);
1382         }
1383 }
1384 //**********************************************************************************************************************
1385 int SffInfoCommand::readAccnosFile(string filename) {
1386         try {
1387                 //remove old names
1388                 seqNames.clear();
1389                 
1390                 ifstream in;
1391                 m->openInputFile(filename, in);
1392                 string name;
1393                 
1394                 while(!in.eof()){
1395                         in >> name; m->gobble(in);
1396                                                 
1397                         seqNames.insert(name);
1398                         
1399                         if (m->control_pressed) { seqNames.clear(); break; }
1400                 }
1401                 in.close();             
1402                 
1403                 return 0;
1404         }
1405         catch(exception& e) {
1406                 m->errorOut(e, "SffInfoCommand", "readAccnosFile");
1407                 exit(1);
1408         }
1409 }
1410 //**********************************************************************************************************************
1411 int SffInfoCommand::parseSffTxt() {
1412         try {
1413                 
1414                 ifstream inSFF;
1415                 m->openInputFile(sfftxtFilename, inSFF);
1416                 
1417                 if (outputDir == "") {  outputDir += m->hasPath(sfftxtFilename); }
1418                 
1419                 //output file names
1420                 ofstream outFasta, outQual, outFlow;
1421                 string outFastaFileName, outQualFileName;
1422                 string fileRoot = m->getRootName(m->getSimpleName(sfftxtFilename));
1423                 if (fileRoot.length() > 0) {
1424                         //rip off last .
1425                         fileRoot = fileRoot.substr(0, fileRoot.length()-1);
1426                         fileRoot = m->getRootName(fileRoot);
1427                 }
1428                 
1429         map<string, string> variables; 
1430                 variables["[filename]"] = fileRoot;
1431                 string sfftxtFileName = getOutputFileName("sfftxt",variables);
1432                 string outFlowFileName = getOutputFileName("flow",variables);
1433                 if (!trim) { variables["[tag]"] = "raw"; }
1434                 outFastaFileName = getOutputFileName("fasta",variables);
1435         outQualFileName = getOutputFileName("qfile",variables);
1436                 
1437                 if (fasta)      { m->openOutputFile(outFastaFileName, outFasta);        outputNames.push_back(outFastaFileName); outputTypes["fasta"].push_back(outFastaFileName); }
1438                 if (qual)       { m->openOutputFile(outQualFileName, outQual);          outputNames.push_back(outQualFileName); outputTypes["qfile"].push_back(outQualFileName);  }
1439                 if (flow)       { m->openOutputFile(outFlowFileName, outFlow);          outputNames.push_back(outFlowFileName);  outFlow.setf(ios::fixed, ios::floatfield); outFlow.setf(ios::showpoint); outputTypes["flow"].push_back(outFlowFileName);  }
1440                 
1441                 //read common header
1442                 string commonHeader = m->getline(inSFF);
1443                 string magicNumber = m->getline(inSFF); 
1444                 string version = m->getline(inSFF);
1445                 string indexOffset = m->getline(inSFF);
1446                 string indexLength = m->getline(inSFF);
1447                 int numReads = parseHeaderLineToInt(inSFF);
1448                 string headerLength = m->getline(inSFF);
1449                 string keyLength = m->getline(inSFF);
1450                 int numFlows = parseHeaderLineToInt(inSFF);
1451                 string flowgramCode = m->getline(inSFF);
1452                 string flowChars = m->getline(inSFF);
1453                 string keySequence = m->getline(inSFF);
1454                 m->gobble(inSFF);
1455                 
1456                 string seqName;
1457                 
1458                 if (flow)       {       outFlow << numFlows << endl;    }
1459                 
1460                 for(int i=0;i<numReads;i++){
1461                         
1462                         //sanity check
1463                         if (inSFF.eof()) { m->mothurOut("[ERROR]: Expected " + toString(numReads) + " but reached end of file at " + toString(i+1) + "."); m->mothurOutEndLine(); break; }
1464                         
1465                         Header header;
1466                         
1467                         //parse read header
1468                         inSFF >> seqName;
1469                         seqName = seqName.substr(1);
1470                         m->gobble(inSFF);
1471                         header.name = seqName;
1472                         
1473                         string runPrefix = parseHeaderLineToString(inSFF);              header.timestamp = runPrefix;
1474                         string regionNumber = parseHeaderLineToString(inSFF);   header.region = regionNumber;
1475                         string xyLocation = parseHeaderLineToString(inSFF);             header.xy = xyLocation;
1476                         m->gobble(inSFF);
1477                                 
1478                         string runName = parseHeaderLineToString(inSFF);
1479                         string analysisName = parseHeaderLineToString(inSFF);
1480                         string fullPath = parseHeaderLineToString(inSFF);
1481                         m->gobble(inSFF);
1482                         
1483                         string readHeaderLen = parseHeaderLineToString(inSFF);  convert(readHeaderLen, header.headerLength);
1484                         string nameLength = parseHeaderLineToString(inSFF);             convert(nameLength, header.nameLength);
1485                         int numBases = parseHeaderLineToInt(inSFF);                             header.numBases = numBases;
1486                         string clipQualLeft = parseHeaderLineToString(inSFF);   convert(clipQualLeft, header.clipQualLeft);
1487                         int clipQualRight = parseHeaderLineToInt(inSFF);                header.clipQualRight = clipQualRight;
1488                         string clipAdapLeft = parseHeaderLineToString(inSFF);   convert(clipAdapLeft, header.clipAdapterLeft);
1489                         string clipAdapRight = parseHeaderLineToString(inSFF);  convert(clipAdapRight, header.clipAdapterRight);
1490                         m->gobble(inSFF);
1491                                 
1492                         seqRead read;
1493                         
1494                         //parse read
1495                         vector<unsigned short> flowVector = parseHeaderLineToFloatVector(inSFF, numFlows);      read.flowgram = flowVector;
1496                         vector<unsigned int> flowIndices = parseHeaderLineToIntVector(inSFF, numBases); 
1497                         
1498                         //adjust for print
1499                         vector<unsigned int> flowIndicesAdjusted; flowIndicesAdjusted.push_back(flowIndices[0]);
1500                         for (int j = 1; j < flowIndices.size(); j++) {   flowIndicesAdjusted.push_back(flowIndices[j] - flowIndices[j-1]);   }
1501                         read.flowIndex = flowIndicesAdjusted;
1502                         
1503                         string bases = parseHeaderLineToString(inSFF);                                                                          read.bases = bases;
1504                         vector<unsigned int> qualityScores = parseHeaderLineToIntVector(inSFF, numBases);       read.qualScores = qualityScores;
1505                         m->gobble(inSFF);
1506                                         
1507                         //if you have provided an accosfile and this seq is not in it, then dont print
1508                         bool print = true;
1509                         if (seqNames.size() != 0) {   if (seqNames.count(header.name) == 0) { print = false; }  }
1510                         
1511                         //print 
1512                         if (print) {
1513                                 if (fasta)      {       printFastaSeqData(outFasta, read, header);      }
1514                                 if (qual)       {       printQualSeqData(outQual, read, header);        }
1515                                 if (flow)       {       printFlowSeqData(outFlow, read, header);        }
1516                         }
1517                         
1518                         //report progress
1519                         if((i+1) % 10000 == 0){ m->mothurOut(toString(i+1)); m->mothurOutEndLine();             }
1520                         
1521                         if (m->control_pressed) {  break;  }
1522                 }
1523                 
1524                 //report progress
1525                 if (!m->control_pressed) {   if((numReads) % 10000 != 0){       m->mothurOut(toString(numReads)); m->mothurOutEndLine();                }  }
1526                 
1527                 inSFF.close();
1528                 
1529                 if (fasta)      {  outFasta.close();    }
1530                 if (qual)       {  outQual.close();             }
1531                 if (flow)       {  outFlow.close();             }
1532                 
1533                 return 0;
1534         }
1535         catch(exception& e) {
1536                 m->errorOut(e, "SffInfoCommand", "parseSffTxt");
1537                 exit(1);
1538         }
1539 }
1540 //**********************************************************************************************************************
1541
1542 int SffInfoCommand::parseHeaderLineToInt(ifstream& file){
1543         try {
1544                 int number;
1545                 
1546                 while (!file.eof())     {
1547                         
1548                         char c = file.get(); 
1549                         if (c == ':'){
1550                                 file >> number;
1551                                 break;
1552                         }
1553                         
1554                 }
1555                 m->gobble(file);
1556                 return number;
1557         }
1558         catch(exception& e) {
1559                 m->errorOut(e, "SffInfoCommand", "parseHeaderLineToInt");
1560                 exit(1);
1561         }
1562         
1563 }
1564
1565 //**********************************************************************************************************************
1566
1567 string SffInfoCommand::parseHeaderLineToString(ifstream& file){
1568         try {
1569                 string text;
1570                 
1571                 while (!file.eof())     {
1572                         char c = file.get(); 
1573                         
1574                         if (c == ':'){
1575                                 //m->gobble(file);
1576                                 //text = m->getline(file);      
1577                                 file >> text;
1578                                 break;
1579                         }
1580                 }
1581                 m->gobble(file);
1582                 
1583                 return text;
1584         }
1585         catch(exception& e) {
1586                 m->errorOut(e, "SffInfoCommand", "parseHeaderLineToString");
1587                 exit(1);
1588         }
1589 }
1590
1591 //**********************************************************************************************************************
1592
1593 vector<unsigned short> SffInfoCommand::parseHeaderLineToFloatVector(ifstream& file, int length){
1594         try {
1595                 vector<unsigned short> floatVector(length);
1596                 
1597                 while (!file.eof())     {
1598                         char c = file.get(); 
1599                         if (c == ':'){
1600                                 float temp;
1601                                 for(int i=0;i<length;i++){
1602                                         file >> temp;
1603                                         floatVector[i] = temp * 100;
1604                                 }
1605                                 break;
1606                         }
1607                 }
1608                 m->gobble(file);        
1609                 return floatVector;
1610         }
1611         catch(exception& e) {
1612                 m->errorOut(e, "SffInfoCommand", "parseHeaderLineToFloatVector");
1613                 exit(1);
1614         }
1615 }
1616
1617 //**********************************************************************************************************************
1618
1619 vector<unsigned int> SffInfoCommand::parseHeaderLineToIntVector(ifstream& file, int length){
1620         try {
1621                 vector<unsigned int> intVector(length);
1622                 
1623                 while (!file.eof())     {
1624                         char c = file.get(); 
1625                         if (c == ':'){
1626                                 for(int i=0;i<length;i++){
1627                                         file >> intVector[i];
1628                                 }
1629                                 break;
1630                         }
1631                 }
1632                 m->gobble(file);        
1633                 return intVector;
1634         }
1635         catch(exception& e) {
1636                 m->errorOut(e, "SffInfoCommand", "parseHeaderLineToIntVector");
1637                 exit(1);
1638         }
1639 }
1640 //***************************************************************************************************************
1641
1642 bool SffInfoCommand::readOligos(string oligoFile){
1643         try {
1644         filehandles.clear();
1645         numSplitReads.clear();
1646         filehandlesHeaders.clear();
1647         
1648                 ifstream inOligos;
1649                 m->openInputFile(oligoFile, inOligos);
1650                 
1651                 string type, oligo, group;
1652         
1653                 int indexPrimer = 0;
1654                 int indexBarcode = 0;
1655                 
1656                 while(!inOligos.eof()){
1657             
1658                         inOligos >> type; 
1659             
1660                         if(type[0] == '#'){
1661                                 while (!inOligos.eof()) {       char c = inOligos.get();  if (c == 10 || c == 13){      break;  }       } // get rest of line if there's any crap there
1662                                 m->gobble(inOligos);
1663                         }
1664                         else{
1665                                 m->gobble(inOligos);
1666                                 //make type case insensitive
1667                                 for(int i=0;i<type.length();i++){       type[i] = toupper(type[i]);  }
1668                                 
1669                                 inOligos >> oligo;
1670                                 
1671                                 for(int i=0;i<oligo.length();i++){
1672                                         oligo[i] = toupper(oligo[i]);
1673                                         if(oligo[i] == 'U')     {       oligo[i] = 'T'; }
1674                                 }
1675                                 
1676                                 if(type == "FORWARD"){
1677                                         group = "";
1678                                         
1679                                         // get rest of line in case there is a primer name
1680                                         while (!inOligos.eof()) {       
1681                                                 char c = inOligos.get(); 
1682                                                 if (c == 10 || c == 13 || c == -1){     break;  }
1683                                                 else if (c == 32 || c == 9){;} //space or tab
1684                                                 else {  group += c;  }
1685                                         } 
1686                                         
1687                                         //check for repeat barcodes
1688                                         map<string, int>::iterator itPrime = primers.find(oligo);
1689                                         if (itPrime != primers.end()) { m->mothurOut("primer " + oligo + " is in your oligos file already."); m->mothurOutEndLine();  }
1690                                         
1691                                         primers[oligo]=indexPrimer; indexPrimer++;              
1692                                         primerNameVector.push_back(group);
1693                                 }else if(type == "REVERSE"){
1694                                         //Sequence oligoRC("reverse", oligo);
1695                                         //oligoRC.reverseComplement();
1696                     string oligoRC = reverseOligo(oligo);
1697                                         revPrimer.push_back(oligoRC);
1698                                 }
1699                                 else if(type == "BARCODE"){
1700                                         inOligos >> group;
1701                                         
1702                                         //check for repeat barcodes
1703                                         map<string, int>::iterator itBar = barcodes.find(oligo);
1704                                         if (itBar != barcodes.end()) { m->mothurOut("barcode " + oligo + " is in your oligos file already."); m->mothurOutEndLine();  }
1705                     
1706                                         barcodes[oligo]=indexBarcode; indexBarcode++;
1707                                         barcodeNameVector.push_back(group);
1708                                 }else if(type == "LINKER"){
1709                                         linker.push_back(oligo);
1710                                 }else if(type == "SPACER"){
1711                                         spacer.push_back(oligo);
1712                                 }
1713                                 else{   m->mothurOut("[WARNING]: " + type + " is not recognized as a valid type. Choices are forward, reverse, and barcode. Ignoring " + oligo + "."); m->mothurOutEndLine(); }
1714                         }
1715                         m->gobble(inOligos);
1716                 }       
1717                 inOligos.close();
1718                 
1719                 if(barcodeNameVector.size() == 0 && primerNameVector[0] == ""){ split = 1;      }
1720                 
1721                 //add in potential combos
1722                 if(barcodeNameVector.size() == 0){
1723                         barcodes[""] = 0;
1724                         barcodeNameVector.push_back("");                        
1725                 }
1726                 
1727                 if(primerNameVector.size() == 0){
1728                         primers[""] = 0;
1729                         primerNameVector.push_back("");                 
1730                 }
1731                 
1732                 filehandles.resize(barcodeNameVector.size());
1733                 for(int i=0;i<filehandles.size();i++){
1734                         filehandles[i].assign(primerNameVector.size(), "");
1735                 }
1736                         
1737                 if(split > 1){
1738                         set<string> uniqueNames; //used to cleanup outputFileNames
1739                         for(map<string, int>::iterator itBar = barcodes.begin();itBar != barcodes.end();itBar++){
1740                                 for(map<string, int>::iterator itPrimer = primers.begin();itPrimer != primers.end(); itPrimer++){
1741                                         
1742                                         string primerName = primerNameVector[itPrimer->second];
1743                                         string barcodeName = barcodeNameVector[itBar->second];
1744                                         
1745                                         string comboGroupName = "";
1746                                         string fastaFileName = "";
1747                                         string qualFileName = "";
1748                                         string nameFileName = "";
1749                                         
1750                                         if(primerName == ""){
1751                                                 comboGroupName = barcodeNameVector[itBar->second];
1752                                         }
1753                                         else{
1754                                                 if(barcodeName == ""){
1755                                                         comboGroupName = primerNameVector[itPrimer->second];
1756                                                 }
1757                                                 else{
1758                                                         comboGroupName = barcodeNameVector[itBar->second] + "." + primerNameVector[itPrimer->second];
1759                                                 }
1760                                         }
1761                                         
1762                                         ofstream temp;
1763                     map<string, string> variables; 
1764                     variables["[filename]"] = outputDir + m->getRootName(m->getSimpleName(currentFileName));
1765                     variables["[group]"] = comboGroupName;
1766                                         string thisFilename = getOutputFileName("sff",variables);
1767                                         if (uniqueNames.count(thisFilename) == 0) {
1768                                                 outputNames.push_back(thisFilename);
1769                                                 outputTypes["sff"].push_back(thisFilename);
1770                                                 uniqueNames.insert(thisFilename);
1771                                         }
1772                                         
1773                                         filehandles[itBar->second][itPrimer->second] = thisFilename;
1774                                         m->openOutputFile(thisFilename, temp);          temp.close();
1775                                 }
1776                         }
1777                 }
1778                 numFPrimers = primers.size();
1779         numLinkers = linker.size();
1780         numSpacers = spacer.size();
1781         map<string, string> variables; 
1782         variables["[filename]"] = outputDir + m->getRootName(m->getSimpleName(currentFileName));
1783         variables["[group]"] = "scrap";
1784                 noMatchFile = getOutputFileName("sff",variables);
1785         m->mothurRemove(noMatchFile);
1786         
1787                 bool allBlank = true;
1788                 for (int i = 0; i < barcodeNameVector.size(); i++) {
1789                         if (barcodeNameVector[i] != "") {
1790                                 allBlank = false;
1791                                 break;
1792                         }
1793                 }
1794                 for (int i = 0; i < primerNameVector.size(); i++) {
1795                         if (primerNameVector[i] != "") {
1796                                 allBlank = false;
1797                                 break;
1798                         }
1799                 }
1800                 
1801         filehandlesHeaders.resize(filehandles.size());
1802         numSplitReads.resize(filehandles.size());
1803         for (int i = 0; i < filehandles.size(); i++) { 
1804             numSplitReads[i].resize(filehandles[i].size(), 0); 
1805             for (int j = 0; j < filehandles[i].size(); j++) {
1806                 filehandlesHeaders[i].push_back(filehandles[i][j]+"headers");
1807             }
1808         }
1809                              
1810                 if (allBlank) {
1811                         m->mothurOut("[WARNING]: your oligos file does not contain any group names.  mothur will not create a split the sff file."); m->mothurOutEndLine();
1812                         split = 1;
1813                         return false;
1814                 }
1815                 
1816                 return true;
1817                 
1818         }
1819         catch(exception& e) {
1820                 m->errorOut(e, "SffInfoCommand", "readOligos");
1821                 exit(1);
1822         }
1823 }
1824 //********************************************************************/
1825 string SffInfoCommand::reverseOligo(string oligo){
1826         try {
1827         string reverse = "";
1828         
1829         for(int i=oligo.length()-1;i>=0;i--){
1830             
1831             if(oligo[i] == 'A')         {       reverse += 'T'; }
1832             else if(oligo[i] == 'T'){   reverse += 'A'; }
1833             else if(oligo[i] == 'U'){   reverse += 'A'; }
1834             
1835             else if(oligo[i] == 'G'){   reverse += 'C'; }
1836             else if(oligo[i] == 'C'){   reverse += 'G'; }
1837             
1838             else if(oligo[i] == 'R'){   reverse += 'Y'; }
1839             else if(oligo[i] == 'Y'){   reverse += 'R'; }
1840             
1841             else if(oligo[i] == 'M'){   reverse += 'K'; }
1842             else if(oligo[i] == 'K'){   reverse += 'M'; }
1843             
1844             else if(oligo[i] == 'W'){   reverse += 'W'; }
1845             else if(oligo[i] == 'S'){   reverse += 'S'; }
1846             
1847             else if(oligo[i] == 'B'){   reverse += 'V'; }
1848             else if(oligo[i] == 'V'){   reverse += 'B'; }
1849             
1850             else if(oligo[i] == 'D'){   reverse += 'H'; }
1851             else if(oligo[i] == 'H'){   reverse += 'D'; }
1852             
1853             else                                                {       reverse += 'N'; }
1854         }
1855         
1856         
1857         return reverse;
1858     }
1859         catch(exception& e) {
1860                 m->errorOut(e, "SffInfoCommand", "reverseOligo");
1861                 exit(1);
1862         }
1863 }
1864
1865 //**********************************************************************************************************************
1866
1867
1868                                 
1869