//
//  createdatabasecommand.cpp
//  Mothur
//
//  Created by Sarah Westcott on 3/28/12.
//  Copyright (c) 2012 Schloss Lab. All rights reserved.
//

#include "createdatabasecommand.h"
#include "inputdata.h"

//**********************************************************************************************************************
vector<string> CreateDatabaseCommand::setParameters(){	
	try {
		CommandParameter pfasta("repfasta", "InputTypes", "", "", "none", "none", "none","database",false,false,true); parameters.push_back(pfasta);
		CommandParameter pname("repname", "InputTypes", "", "", "NameCount", "none", "none","",false,false,true); parameters.push_back(pname);
        CommandParameter pcount("count", "InputTypes", "", "", "NameCount-CountGroup", "none", "none","",false,false,true); parameters.push_back(pcount);
		CommandParameter pgroup("group", "InputTypes", "", "", "CountGroup", "none", "none","",false,false,true); parameters.push_back(pgroup);
		CommandParameter pconstaxonomy("constaxonomy", "InputTypes", "", "", "none", "none", "none","",false,true,true); parameters.push_back(pconstaxonomy);
		CommandParameter plist("list", "InputTypes", "", "", "ListShared", "ListShared", "none","",false,false,true); parameters.push_back(plist);
        CommandParameter pshared("shared", "InputTypes", "", "", "ListShared", "ListShared", "none","",false,false,true); parameters.push_back(pshared);
        CommandParameter prelabund("relabund", "InputTypes", "", "", "ListShared", "ListShared", "none","",false,false,true); parameters.push_back(prelabund);
		CommandParameter plabel("label", "String", "", "", "", "", "","",false,false); parameters.push_back(plabel);
		CommandParameter pseed("seed", "Number", "", "0", "", "", "","",false,false); parameters.push_back(pseed);
        CommandParameter pinputdir("inputdir", "String", "", "", "", "", "","",false,false); parameters.push_back(pinputdir);
		CommandParameter poutputdir("outputdir", "String", "", "", "", "", "","",false,false); parameters.push_back(poutputdir);
        
        abort = false; calledHelp = false;
        
        vector<string> tempOutNames;
        outputTypes["database"] = tempOutNames;
		
		vector<string> myArray;
		for (int i = 0; i < parameters.size(); i++) {	myArray.push_back(parameters[i].name);		}
		return myArray;
	}
	catch(exception& e) {
		m->errorOut(e, "CreateDatabaseCommand", "setParameters");
		exit(1);
	}
}
//**********************************************************************************************************************
string CreateDatabaseCommand::getHelpString(){	
	try {
		string helpString = "";
		helpString += "The create.database command reads a list, shared or relabund file, *.cons.taxonomy, and optional *.rep.fasta, *.rep.names, groupfile, or count file and creates a database file.\n";
		helpString += "The create.database command parameters are repfasta, list, shared, repname, constaxonomy, group, count and label. List or shared and constaxonomy are required.\n";
        helpString += "The repfasta file is fasta file outputted by get.oturep(fasta=yourFastaFile, list=yourListfile, column=yourDistFile, name=yourNameFile).\n";
        helpString += "The repname file is the name file outputted by get.oturep(fasta=yourFastaFile, list=yourListfile, column=yourDistFile, name=yourNameFile).\n";
        helpString += "The count file is the count file outputted by get.oturep(fasta=yourFastaFile, list=yourListfile, column=yourDistFile, count=yourCountFile). If it includes group info, mothur will give you the abundance breakdown by group. \n";
        helpString += "The constaxonomy file is the taxonomy file outputted by classify.otu(list=yourListfile, taxonomy=yourTaxonomyFile, name=yourNameFile).\n";
        helpString += "The group file is optional and will just give you the abundance breakdown by group.\n";
        helpString += "The label parameter allows you to specify a label to be used from your listfile.\n";
        helpString += "NOTE: Make SURE the repfasta, repnames and contaxonomy are for the same label as the listfile.\n";
        helpString += "The create.database command should be in the following format: \n";
		helpString += "create.database(repfasta=yourFastaFileFromGetOTURep, repname=yourNameFileFromGetOTURep, contaxonomy=yourConTaxFileFromClassifyOTU, list=yourListFile) \n";	
		helpString += "Example: create.database(repfasta=final.an.0.03.rep.fasta, repname=final.an.0.03.rep.names, list=final.an.list, label=0.03, contaxonomy=final.an.0.03.cons.taxonomy) \n";
		return helpString;
	}
	catch(exception& e) {
		m->errorOut(e, "CreateDatabaseCommand", "getHelpString");
		exit(1);
	}
}
//**********************************************************************************************************************
string CreateDatabaseCommand::getOutputPattern(string type) {
    try {
        string pattern = "";
        
        if (type == "database") {  pattern = "[filename],database"; }
        else { m->mothurOut("[ERROR]: No definition for type " + type + " output pattern.\n"); m->setControl_pressed(true);  }
        
        return pattern;
    }
    catch(exception& e) {
        m->errorOut(e, "CreateDatabaseCommand", "getOutputPattern");
        exit(1);
    }
}
//**********************************************************************************************************************
CreateDatabaseCommand::CreateDatabaseCommand(string option)  {
	try{
		//allow user to run help
		if (option == "help") { 
			help(); abort = true; calledHelp = true;
		}else if(option == "citation") { citation(); abort = true; calledHelp = true;}
        else if(option == "category") {  abort = true; calledHelp = true;  } 
		else {
			OptionParser parser(option, setParameters());
			map<string, string> parameters = parser.getParameters();
			
			ValidParameters validParameter;
			
			
			//check for required parameters
			listfile = validParameter.validFile(parameters, "list");
			if (listfile == "not found") {	listfile = "";			}
			else if (listfile == "not open") { listfile = ""; abort = true; }	
			else { current->setListFile(listfile); }
            
            sharedfile = validParameter.validFile(parameters, "shared");
			if (sharedfile == "not found") {	sharedfile = "";			}
			else if (sharedfile == "not open") { sharedfile = ""; abort = true; }	
			else { current->setSharedFile(sharedfile); }
            
            relabundfile = validParameter.validFile(parameters, "relabund");
            if (relabundfile == "not found") {	relabundfile = "";			}
            else if (relabundfile == "not open") { relabundfile = ""; abort = true; }
            else { current->setRelAbundFile(relabundfile); }
            
            if ((sharedfile == "") && (listfile == "") && (relabundfile == "")) {
				//is there are current file available for either of these?
				//give priority to list, then shared, then relabund
				listfile = current->getListFile(); 
				if (listfile != "") {  m->mothurOut("Using " + listfile + " as input file for the list parameter.\n");  }
				else { 
					sharedfile = current->getSharedFile(); 
					if (sharedfile != "") {  m->mothurOut("Using " + sharedfile + " as input file for the shared parameter.\n");  }
					else { 
                        relabundfile = current->getRelAbundFile();
                        if (relabundfile != "") {  m->mothurOut("Using " + relabundfile + " as input file for the relabund parameter.\n");  }
                        else {
                            m->mothurOut("[ERROR]: No valid current files. You must provide a shared, list or relabund file before you can use the create.database command.\n");  abort = true;
                        }
					}
				}
			}
			else if ((sharedfile != "") && (listfile != "")) { m->mothurOut("When executing a create.database command you must enter ONLY ONE of the following: relabund, shared or list.\n"); abort = true; }
            
            if (sharedfile != "") { if (outputdir == "") { outputdir = util.hasPath(sharedfile); } }
            else if (listfile != ""){ if (outputdir == "") { outputdir = util.hasPath(listfile); } }
            else { if (outputdir == "") { outputdir = util.hasPath(relabundfile); } }
			
			contaxonomyfile = validParameter.validFile(parameters, "constaxonomy");
			if (contaxonomyfile == "not found") {  //if there is a current list file, use it
               contaxonomyfile = "";  m->mothurOut("The constaxonomy parameter is required, aborting.\n");  abort = true;
			}
			else if (contaxonomyfile == "not open") { contaxonomyfile = ""; abort = true; }

            repfastafile = validParameter.validFile(parameters, "repfasta");
			if (repfastafile == "not found") { repfastafile = ""; }
			else if (repfastafile == "not open") { repfastafile = ""; abort = true; }

            repnamesfile = validParameter.validFile(parameters, "repname");
			if (repnamesfile == "not found") {  repnamesfile = "";  			}
			else if (repnamesfile == "not open") { repnamesfile = ""; abort = true; }
            
            if ((repnamesfile != "") && (repfastafile == "")) { m->mothurOut("[ERROR]: You must provide a repfasta file if you are using a repnames file.\n");
                abort = true; }
            
            countfile = validParameter.validFile(parameters, "count");
			if (countfile == "not found") {  countfile = "";  			}
			else if (countfile == "not open") { countfile = ""; abort = true; }
            
			groupfile = validParameter.validFile(parameters, "group");
			if (groupfile == "not open") { groupfile = ""; abort = true; }	
			else if (groupfile == "not found") { groupfile = ""; }
			else { current->setGroupFile(groupfile); }
			
			//check for optional parameter and set defaults
			// ...at some point should added some additional type checking...
            label = validParameter.valid(parameters, "label");			
			if (label == "not found") { label = ""; m->mothurOut("You did not provide a label, I will use the first label in your file.\n");}
        }
	}
	catch(exception& e) {
		m->errorOut(e, "CreateDatabaseCommand", "CreateDatabaseCommand");
		exit(1);
	}
}
//**********************************************************************************************************************
int CreateDatabaseCommand::execute(){
	try {
		
		if (abort) { if (calledHelp) { return 0; }  return 2;	}
        
        //taxonomies holds the taxonomy info for each Otu
        //classifyOtuSizes holds the size info of each Otu to help with error checking
        vector<string> taxonomies;
        vector<string> otuLabels;
        vector<int> classifyOtuSizes = readTax(taxonomies, otuLabels);
        
        if (m->getControl_pressed()) { return 0; }
        
        vector<Sequence> seqs;
        vector<int> repOtusSizes;
        if (repfastafile != "") { repOtusSizes = readFasta(seqs); }
        
        if (m->getControl_pressed()) { return 0; }
        
        //names redundants to uniques. backwards to how we normally do it, but each bin is the list file will be a key entry in the map.
        map<string, string> repNames;
        map<string, int> nameMap;
        int numUniqueNamesFile = 0;
        CountTable ct;
        if (repnamesfile != "") {
            numUniqueNamesFile = util.readNames(repnamesfile, repNames, 1);
            //the repnames file does not have the same order as the list file bins so we need to sort and reassemble for the search below
            map<string, string> tempRepNames;
            for (map<string, string>::iterator it = repNames.begin(); it != repNames.end();) {
                string bin = it->first;
                vector<string> temp;
                util.splitAtChar(bin, temp, ',');
                sort(temp.begin(), temp.end());
                bin = "";
                for (int i = 0; i < temp.size()-1; i++) {
                    bin += temp[i] + ',';
                }
                bin += temp[temp.size()-1];
                tempRepNames[bin] = it->second;
                repNames.erase(it++);
            }
            repNames = tempRepNames;
        }else if (countfile != ""){
            ct.readTable(countfile, true, false);
            numUniqueNamesFile = ct.getNumUniqueSeqs();
            nameMap = ct.getNameMap();
        }
        
        if (m->getControl_pressed()) { return 0; }
        
        if (repfastafile != "") {
            
            //are there the same number of otus in the fasta and name files
            if (repOtusSizes.size() != numUniqueNamesFile) { m->mothurOut("[ERROR]: you have " + toString(numUniqueNamesFile) + " unique seqs in your repname file, but " + toString(repOtusSizes.size()) + " seqs in your repfasta file.  These should match.\n"); m->setControl_pressed(true); }
            
            //are there the same number of OTUs in the tax and fasta file
            if (classifyOtuSizes.size() != repOtusSizes.size()) { m->mothurOut("[ERROR]: you have " + toString(classifyOtuSizes.size()) + " taxonomies in your contaxonomy file, but " + toString(repOtusSizes.size()) + " seqs in your repfasta file.  These should match.\n"); m->setControl_pressed(true); }
            
            if (m->getControl_pressed()) { return 0; }
            
            //at this point we have the same number of OTUs. Are the sizes we have found so far accurate?
            for (int i = 0; i < classifyOtuSizes.size(); i++) {
                if (classifyOtuSizes[i] != repOtusSizes[i]) {
                    m->mothurOut("[ERROR]: OTU size info does not match for bin " + toString(i+1) + ". The contaxonomy file indicated the OTU represented " + toString(classifyOtuSizes[i]) + " sequences, but the repfasta file had " + toString(repOtusSizes[i]) + ".  These should match. Make sure you are using files for the same distance.\n"); m->setControl_pressed(true);
                }
            }
        }
        
        if (m->getControl_pressed()) { return 0; }
        
        
        map<string, string> variables; 
        if (listfile != "") {  variables["[filename]"] = outputdir + util.getRootName(util.getSimpleName(listfile)); }
        else if (sharedfile != "") { variables["[filename]"] = outputdir + util.getRootName(util.getSimpleName(sharedfile)); }
        else {  variables["[filename]"] = outputdir + util.getRootName(util.getSimpleName(relabundfile)); }
        string outputFileName = getOutputFileName("database", variables); 
        outputNames.push_back(outputFileName); outputTypes["database"].push_back(outputFileName);
        
        ofstream out;
        util.openOutputFile(outputFileName, out);
        
        string header = "OTUNumber\tAbundance";

        
        if (listfile != "") {
            //at this point we are fairly sure the repfasta, repnames and contaxonomy files match so lets proceed with the listfile
            ListVector* list = getList();
            
            if (otuLabels.size() != list->getNumBins()) { 
                m->mothurOut("[ERROR]: you have " + toString(otuLabels.size()) + " otus in your contaxonomy file, but your list file has " + toString(list->getNumBins()) + " otus. These should match. Make sure you are using files for the same distance.\n"); m->setControl_pressed(true);  }
            
            if (m->getControl_pressed()) { delete list; return 0; }
            
            GroupMap* groupmap = NULL;
            if (groupfile != "") {
                groupmap = new GroupMap(groupfile);
                groupmap->readMap();
            }
            
            if (m->getControl_pressed()) { delete list; if (groupfile != "") { delete groupmap; } return 0; }
            
            if (groupfile != "") { 
                header = "OTUNumber";
                for (int i = 0; i < groupmap->getNamesOfGroups().size(); i++) { header += '\t' + (groupmap->getNamesOfGroups())[i]; }
            }else if (countfile != "") {
                if (ct.hasGroupInfo()) {
                    header = "OTUNumber";
                    for (int i = 0; i < ct.getNamesOfGroups().size(); i++) { header += '\t' + (ct.getNamesOfGroups())[i]; }
                }
            }
            
            if (repfastafile != "") {  header += "\trepSeqName\trepSeq";  }
            header += "\tOTUConTaxonomy";
            out << header << endl;
            
            vector<string> binLabels = list->getLabels();
            for (int i = 0; i < list->getNumBins(); i++) {
                
                int index = findIndex(otuLabels, binLabels[i]);
                if (index == -1) {  m->mothurOut("[ERROR]: " + binLabels[i] + " is not in your constaxonomy file, aborting.\n"); m->setControl_pressed(true); }
                
                if (m->getControl_pressed()) { break; }
                
                out << otuLabels[index];
                
                vector<string> binNames;
                string bin = list->get(i);
                util.splitAtComma(bin, binNames);
                
                string seqRepName = "";
                int numSeqsRep = binNames.size();
                
                if (repnamesfile != "") {
                    sort(binNames.begin(), binNames.end());
                    bin = "";
                    for (int j = 0; j < binNames.size()-1; j++) {
                        bin += binNames[j] + ',';
                    }
                    bin += binNames[binNames.size()-1];
                    map<string, string>::iterator it = repNames.find(bin);
                    
                    if (it == repNames.end()) {
                        m->mothurOut("[ERROR: OTU " + otuLabels[index] + " is not in the repnames file. Make sure you are using files for the same distance.\n"); m->setControl_pressed(true);   break;
                    }else { seqRepName = it->second;  numSeqsRep = binNames.size(); }
                    
                    //sanity check
                    if (binNames.size() != classifyOtuSizes[index]) {
                        m->mothurOut("[ERROR: OTU " + otuLabels[index] + " contains " + toString(binNames.size()) + " sequence, but the rep and taxonomy files indicated this OTU should have " + toString(classifyOtuSizes[index]) + ". Make sure you are using files for the same distance.\n"); m->setControl_pressed(true);   break;
                    }
                }else if ((countfile != "") && (repfastafile != "")) {
                    //find rep sequence in bin
                    for (int j = 0; j < binNames.size(); j++) {
                        map<string, int>::iterator itNameMap = nameMap.find(binNames[j]); //if you are in the counttable you must be the rep. because get.oturep with a countfile only includes the rep sequences in the rep.count file.
                        if (itNameMap != nameMap.end()) {
                            seqRepName = itNameMap->first;
                            numSeqsRep = itNameMap->second;
                            j += binNames.size(); //exit loop
                        }
                    }
                    
                    if (seqRepName == "") {
                        m->mothurOut("[ERROR: OTU " + otuLabels[index] + " is not in the count file. Make sure you are using files for the same distance.\n"); m->setControl_pressed(true);   break;
                    }
                    
                    if (numSeqsRep != classifyOtuSizes[i]) {
                        m->mothurOut("[ERROR: OTU " + otuLabels[index] + " contains " + toString(numSeqsRep) + " sequence, but the rep and taxonomy files indicated this OTU should have " + toString(classifyOtuSizes[index]) + ". Make sure you are using files for the same distance.\n"); m->setControl_pressed(true);   break;
                    }
                }
                
                //output abundances
                if (groupfile != "") {
                    string groupAbunds = "";
                    map<string, int> counts;
                    //initialize counts to 0
                    for (int j = 0; j < groupmap->getNamesOfGroups().size(); j++) { counts[(groupmap->getNamesOfGroups())[j]] = 0; }
                    
                    //find abundances by group
                    bool error = false;
                    for (int j = 0; j < binNames.size(); j++) {
                        string group = groupmap->getGroup(binNames[j]);
                        if (group == "not found") {
                            m->mothurOut("[ERROR]: " + binNames[j] + " is not in your groupfile, please correct.\n");
                            error = true;
                        }else { counts[group]++; }
                    }
                    
                    //output counts
                    for (int j = 0; j < groupmap->getNamesOfGroups().size(); j++) { out << '\t' << counts[(groupmap->getNamesOfGroups())[j]];  }
                    
                    if (error) { m->setControl_pressed(true); }
                }else if ((countfile != "") && (repfastafile != "")) {
                    if (ct.hasGroupInfo()) {
                        vector<int> groupCounts = ct.getGroupCounts(seqRepName);
                        for (int j = 0; j < groupCounts.size(); j++) { out << '\t' << groupCounts[j];  }
                    }else { out << '\t' << numSeqsRep; }
                }else if ((countfile != "") && (repfastafile == "")) {
                    if (ct.hasGroupInfo()) {
                        vector<int> groupTotals; groupTotals.resize(ct.getNumGroups(), 0);
                        for (int j = 0; j < binNames.size(); j++) {
                            vector<int> groupCounts = ct.getGroupCounts(binNames[j]);
                            for (int k = 0; k < groupCounts.size(); k++) { groupTotals[k] += groupCounts[k]; }
                        }
                        for (int j = 0; j < groupTotals.size(); j++) { out << '\t' << groupTotals[j];  }
                    }else { out << '\t' << numSeqsRep; }
                }else { out << '\t' << numSeqsRep; }
                
                //output repSeq
                if (repfastafile != "") { out << '\t' << seqRepName << '\t' << seqs[index].getAligned() << '\t' << taxonomies[index] << endl; }
                else { out << '\t' << taxonomies[index] << endl; }
            }
            
            
            delete list;
            if (groupfile != "") { delete groupmap; }
           
        }else if (sharedfile != "") {
            SharedRAbundVectors* lookup = getShared();
            vector<string> namesOfGroups = lookup->getNamesGroups();
            
            header = "OTUNumber";
            for (int i = 0; i < namesOfGroups.size(); i++) { header += '\t' + namesOfGroups[i]; }
            if (repfastafile != "") {  header += "\trepSeqName\trepSeq";  }
            header += "\tOTUConTaxonomy";
            out << header << endl;
            
            vector<string> currentLabels = lookup->getOTUNames();
            for (int h = 0; h < lookup->getNumBins(); h++) {
                
                if (m->getControl_pressed()) { break; }
                
                int index = findIndex(otuLabels, currentLabels[h]);
                if (index == -1) {  m->mothurOut("[ERROR]: " + currentLabels[h] + " is not in your constaxonomy file, aborting.\n"); m->setControl_pressed(true); }
                
                if (m->getControl_pressed()) { break; }
                
                out << otuLabels[index];
                
                int totalAbund = 0;
                for (int i = 0; i < lookup->size(); i++) {
                    int abund = lookup->get(h, namesOfGroups[i]);
                    totalAbund += abund; 
                    out  << '\t' << abund;
                }
                
                //output repSeq
                if (repfastafile != "") { out << '\t' << seqs[index].getName() << '\t' << seqs[index].getAligned() << '\t' << taxonomies[index] << endl; }
                else { out << '\t' << taxonomies[index] << endl; }
            }
        }else { //relabund
            SharedRAbundFloatVectors* lookup = getRelabund();
            vector<string> namesOfGroups = lookup->getNamesGroups();
            
            header = "OTUNumber";
            for (int i = 0; i < namesOfGroups.size(); i++) { header += '\t' + namesOfGroups[i]; }
            if (repfastafile != "") {  header += "\trepSeqName\trepSeq";  }
            header += "\tOTUConTaxonomy";
            out << header << endl;
            
            vector<string> currentLabels = lookup->getOTUNames();
            for (int h = 0; h < lookup->getNumBins(); h++) {
                
                if (m->getControl_pressed()) { break; }
                
                int index = findIndex(otuLabels, currentLabels[h]);
                if (index == -1) {  m->mothurOut("[ERROR]: " + currentLabels[h] + " is not in your constaxonomy file, aborting.\n"); m->setControl_pressed(true); }
                
                if (m->getControl_pressed()) { break; }
                
                out << otuLabels[index];
                
                float totalAbund = 0;
                for (int i = 0; i < lookup->size(); i++) {
                    float abund = lookup->get(h, namesOfGroups[i]);
                    totalAbund += abund;
                    out  << '\t' << abund;
                }
                
                //output repSeq
                if (repfastafile != "") { out << '\t' << seqs[index].getName() << '\t' << seqs[index].getAligned() << '\t' << taxonomies[index] << endl; }
                else { out << '\t' << taxonomies[index] << endl; }
            }

        }
        out.close();
        if (m->getControl_pressed()) { util.mothurRemove(outputFileName); return 0; }
        
        m->mothurOut("\nOutput File Names: \n"); 
		m->mothurOut(outputFileName); m->mothurOutEndLine();	
		m->mothurOutEndLine();
        
        return 0;
        
    }
	catch(exception& e) {
		m->errorOut(e, "CreateDatabaseCommand", "execute");
		exit(1);
	}
}
//**********************************************************************************************************************
int CreateDatabaseCommand::findIndex(vector<string>& otuLabels, string label){
	try {
        int index = -1;
        for (int i = 0; i < otuLabels.size(); i++) {
            if (util.isLabelEquivalent(otuLabels[i],label)) { index = i; break; }
        }
		return index;
    }
	catch(exception& e) {
		m->errorOut(e, "CreateDatabaseCommand", "findIndex");
		exit(1);
	}
}
//**********************************************************************************************************************
vector<int> CreateDatabaseCommand::readTax(vector<string>& taxonomies, vector<string>& otuLabels){
	try {
		
        vector<int> sizes; 
        
        ifstream in;
        util.openInputFile(contaxonomyfile, in);
        
        //read headers
        util.getline(in);
        
        while (!in.eof()) {
            
            if (m->getControl_pressed()) { break; }
            
            string otu = ""; string tax = "unknown";
            int size = 0;
            
            in >> otu >> size; util.gobble(in);
            tax = util.getline(in); util.gobble(in);
            
            sizes.push_back(size);
            taxonomies.push_back(tax);
            otuLabels.push_back(otu);
        }
        in.close();
        
        return sizes;
    }
	catch(exception& e) {
		m->errorOut(e, "CreateDatabaseCommand", "readTax");
		exit(1);
	}
}
//**********************************************************************************************************************
vector<int> CreateDatabaseCommand::readFasta(vector<Sequence>& seqs){
	try {
		
        vector<int> sizes; 
        
        ifstream in;
        util.openInputFile(repfastafile, in);
        
        set<int> sanity;
        while (!in.eof()) {
            
            if (m->getControl_pressed()) { break; }
            
            string binInfo;
            Sequence seq(in, binInfo, true);  util.gobble(in);
            
            //the binInfo should look like - binNumber|size ie. 1|200 if it is binNumber|size|group then the user gave us the wrong repfasta file
            vector<string> info;
            util.splitAtChar(binInfo, info, '|');
            //if (info.size() != 2) { m->mothurOut("[ERROR]: your repfasta file is not the right format.  The create database command is designed to be used with the output from get.oturep.  When running get.oturep you can not use a group file, because mothur is only expecting one representative sequence per OTU and when you use a group file with get.oturep a representative is found for each group.\n");  m->setControl_pressed(true); break;}
            
            int size = 0;
            util.mothurConvert(info[1], size);
            
            int binNumber = 0;
            string temp = "";
            for (int i = 0; i < info[0].size(); i++) { if (isspace(info[0][i])) {;}else{temp +=info[0][i]; } }
            util.mothurConvert(util.getSimpleLabel(temp), binNumber);
            set<int>::iterator it = sanity.find(binNumber);
            if (it != sanity.end()) {
                m->mothurOut("[ERROR]: your repfasta file is not the right format.  The create database command is designed to be used with the output from get.oturep.  When running get.oturep you can not use a group file, because mothur is only expecting one representative sequence per OTU and when you use a group file with get.oturep a representative is found for each group.\n");  m->setControl_pressed(true); break;
            }else { sanity.insert(binNumber); }
            
            sizes.push_back(size);
            seqs.push_back(seq);
        }
        in.close();
        
        return sizes;
    }
	catch(exception& e) {
		m->errorOut(e, "CreateDatabaseCommand", "readFasta");
		exit(1);
	}
}
//**********************************************************************************************************************
ListVector* CreateDatabaseCommand::getList(){
	try {
		InputData* input = new InputData(listfile, "list", nullVector);
		ListVector* list = input->getListVector();
		string lastLabel = list->getLabel();
		
		if (label == "") { label = lastLabel; delete input; return list; }
		
		//if the users enters label "0.06" and there is no "0.06" in their file use the next lowest label.
		set<string> labels; labels.insert(label);
		set<string> processedLabels;
		set<string> userLabels = labels;
		
		//as long as you are not at the end of the file or done wih the lines you want
		while((list != NULL) && (userLabels.size() != 0)) {
			if (m->getControl_pressed()) {  delete input; return list;  }
			
			if(labels.count(list->getLabel()) == 1){
				processedLabels.insert(list->getLabel());
				userLabels.erase(list->getLabel());
				break;
			}
			
			if ((util.anyLabelsToProcess(list->getLabel(), userLabels, "") ) && (processedLabels.count(lastLabel) != 1)) {
				string saveLabel = list->getLabel();
				
				delete list;
				list = input->getListVector(lastLabel);
				
				processedLabels.insert(list->getLabel());
				userLabels.erase(list->getLabel());
				
				//restore real lastlabel to save below
				list->setLabel(saveLabel);
				break;
			}
			
			lastLabel = list->getLabel();			
			
			//get next line to process
			//prevent memory leak
			delete list; 
			list = input->getListVector();
		}
		
		
		if (m->getControl_pressed()) { delete input; return list;  }
		
		//output error messages about any remaining user labels
		bool needToRun = false;
		for (set<string>::iterator it = userLabels.begin(); it != userLabels.end(); it++) {
			m->mothurOut("Your file does not include the label " + *it); 
            if (processedLabels.count(lastLabel) != 1)  { m->mothurOut(". I will use " + lastLabel + ".\n"); needToRun = true;  }
			else                                        { m->mothurOut(". Please refer to " + lastLabel + ".\n");               }
		}
		
		//run last label if you need to
		if (needToRun )  {
			delete list;
			list = input->getListVector(lastLabel);
		}	
		
		delete input;

        return list;
    }
	catch(exception& e) {
		m->errorOut(e, "CreateDatabaseCommand", "getList");
		exit(1);
	}
}
//**********************************************************************************************************************
SharedRAbundVectors* CreateDatabaseCommand::getShared(){
	try {
		InputData input(sharedfile, "sharedfile", nullVector);
		SharedRAbundVectors* lookup = input.getSharedRAbundVectors();
		string lastLabel = lookup->getLabel();
		
		if (label == "") { label = lastLabel; return lookup; }
		
		//if the users enters label "0.06" and there is no "0.06" in their file use the next lowest label.
		set<string> labels; labels.insert(label);
		set<string> processedLabels;
		set<string> userLabels = labels;
		
		//as long as you are not at the end of the file or done wih the lines you want
		while((lookup != NULL) && (userLabels.size() != 0)) {
			if (m->getControl_pressed()) {  return lookup;  }
			
			if(labels.count(lookup->getLabel()) == 1){
				processedLabels.insert(lookup->getLabel()); userLabels.erase(lookup->getLabel());
				break;
			}
			
			if ((util.anyLabelsToProcess(lookup->getLabel(), userLabels, "") ) && (processedLabels.count(lastLabel) != 1)) {
				string saveLabel = lookup->getLabel();
				
                delete lookup;
				lookup = input.getSharedRAbundVectors(lastLabel);
				
				processedLabels.insert(lookup->getLabel()); userLabels.erase(lookup->getLabel());
				
				//restore real lastlabel to save below
				lookup->setLabels(saveLabel);
				break;
			}
			
			lastLabel = lookup->getLabel();
			
			//get next line to process
			//prevent memory leak
			delete lookup;
			lookup = input.getSharedRAbundVectors();
		}
		
		
		if (m->getControl_pressed()) { return lookup;  }
		
		//output error messages about any remaining user labels
		bool needToRun = false;
		for (set<string>::iterator it = userLabels.begin(); it != userLabels.end(); it++) {
			m->mothurOut("Your file does not include the label " + *it); 
            if (processedLabels.count(lastLabel) != 1)  { m->mothurOut(". I will use " + lastLabel + ".\n"); needToRun = true;  }
			else                                        { m->mothurOut(". Please refer to " + lastLabel + ".\n");               }
		}
		
		//run last label if you need to
		if (needToRun )  {
			delete lookup;
			lookup = input.getSharedRAbundVectors(lastLabel);
		}	
        
        return lookup;
    }
	catch(exception& e) {
		m->errorOut(e, "CreateDatabaseCommand", "getShared");
		exit(1);
	}
}
//**********************************************************************************************************************
SharedRAbundFloatVectors* CreateDatabaseCommand::getRelabund(){
    try {
        InputData input(relabundfile, "relabund", nullVector);
        SharedRAbundFloatVectors* lookupFloat = input.getSharedRAbundFloatVectors();
        string lastLabel = lookupFloat->getLabel();
        
        if (label == "") { label = lastLabel;  return lookupFloat; }
        
        //if the users enters label "0.06" and there is no "0.06" in their file use the next lowest label.
        set<string> labels; labels.insert(label);
        set<string> processedLabels;
        set<string> userLabels = labels;
        
        //as long as you are not at the end of the file or done wih the lines you want
        while((lookupFloat != NULL) && (userLabels.size() != 0)) {
            
            if (m->getControl_pressed()) {  return 0;  }
            
            if(labels.count(lookupFloat->getLabel()) == 1){
                processedLabels.insert(lookupFloat->getLabel());
                userLabels.erase(lookupFloat->getLabel());
                break;
            }
            
            if ((util.anyLabelsToProcess(lookupFloat->getLabel(), userLabels, "") ) && (processedLabels.count(lastLabel) != 1)) {
                string saveLabel = lookupFloat->getLabel();
                
                delete lookupFloat;
                lookupFloat = input.getSharedRAbundFloatVectors(lastLabel);
                
                processedLabels.insert(lookupFloat->getLabel());
                userLabels.erase(lookupFloat->getLabel());
                
                //restore real lastlabel to save below
                lookupFloat->setLabels(saveLabel);
                break;
            }
            
            lastLabel = lookupFloat->getLabel();
            
            //get next line to process
            //prevent memory leak
            delete lookupFloat;
            lookupFloat = input.getSharedRAbundFloatVectors();
        }
        
        
        if (m->getControl_pressed()) { return 0;  }
        
        //output error messages about any remaining user labels
        bool needToRun = false;
        for (set<string>::iterator it = userLabels.begin(); it != userLabels.end(); it++) {
            m->mothurOut("Your file does not include the label " + *it);
            if (processedLabels.count(lastLabel) != 1)  { m->mothurOut(". I will use " + lastLabel + ".\n"); needToRun = true;  }
            else                                        { m->mothurOut(". Please refer to " + lastLabel + ".\n");               }
        }
        
        //run last label if you need to
        if (needToRun )  {
            delete lookupFloat;
            lookupFloat = input.getSharedRAbundFloatVectors();
        }	
        
        return lookupFloat;
    }
    catch(exception& e) {
        m->errorOut(e, "CreateDatabaseCommand", "getRelabund");
        exit(1);
    }
}


//**********************************************************************************************************************


