<commit_before>#include "ResultData.h"

using namespace std;

void json(ostream& out, Results& results, AlleleParser* parser) {
    out << "{";
    for (Results::iterator r = results.begin(); r != results.end(); ++r) {
        ResultData& sample = r->second;
        if (r != results.begin()) out << ",";
        out << "\"" << sample.name << "\":{"
            << "\"coverage\":" << sample.observations->observationCount() << ","
            << "\"genotypes\":[";
        for (map<Genotype*, long double>::iterator g = sample.marginals.begin();
                g != sample.marginals.end(); ++g) {
            if (g != sample.marginals.begin()) cout << ",";
            out << "[\"" << *(g->first) << "\"," << safe_exp(g->second) << "]";
        }
        out << "]";
        if (parser->parameters.outputAlleles)
            out << ",\"alleles\":" << sample.observations->json();
        out << "}";

    }
    out << "}";
}

// current date string in YYYYMMDD format
string dateStr(void) {

    time_t rawtime;
    struct tm* timeinfo;
    char buffer[80];

    time(&rawtime);
    timeinfo = localtime(&rawtime);

    strftime(buffer, 80, "%Y%m%d", timeinfo);

    return string(buffer);

}

void vcfHeader(ostream& out,
        string referenceName,
        vector<string>& samples,
        Parameters& parameters) {

    out << "##fileformat=VCFv4.0" << endl
        << "##fileDate=" << dateStr() << endl
        << "##source=freeBayes version " << FREEBAYES_VERSION << endl
        << "##reference=" << referenceName << endl
        << "##phasing=none" << endl
        << "##commandline=\"" << parameters.commandline << "\"" << endl
        << "##INFO=<ID=NS,Number=1,Type=Integer,Description=\"Number of samples with data\">" << endl
        << "##INFO=<ID=DP,Number=1,Type=Integer,Description=\"Total read depth at the locus\">" << endl
        << "##INFO=<ID=AC,Number=1,Type=Integer,Description=\"Total number of alternate alleles in called genotypes\">" << endl
        << "##INFO=<ID=AN,Number=1,Type=Integer,Description=\"Total number of alleles in called genotypes\">" << endl
        //<< "##INFO=<ID=AF,Number=1,Type=Float,Description=\"Estimated allele frequency in the range (0,1]\">" << endl
        << "##INFO=<ID=BCF,Number=2,Type=Integer,Description=\"Forward-strand base count: the number of observations on the forward strand for, the reference, the first alternate, the second alternate, and so on for each alternate\">" << endl
        << "##INFO=<ID=BCR,Number=2,Type=Integer,Description=\"Reverse-strand base count: the number of observations on the reverse strand for, the reference, the first alternate, the second alternate, and so on for each alternate\">" << endl
        << "##INFO=<ID=SB,Number=1,Type=Float,Description=\"Strand bias for the alternate allele: a number between 0 and 1 representing the ratio of forward strand sequence reads showing the alternate allele to all reads, considering only reads from individuals called as heterozygous\">" << endl
        << "##INFO=<ID=AB,Number=1,Type=Integer,Description=\"Allele balance at heterozygous sites: a number beween 0 and 1 representing the ratio of reads showing the reference allele to all reads, considering only reads from individuals called as heterozygous\">" << endl
        << "##INFO=<ID=ABB,Number=2,Type=Integer,Description=\"Allele balance counts: two numbers giving the numbers of sequence reads from apparent heterozygotes which show reference and alternate alleles for the site\">" << endl
        << "##INFO=<ID=RUN,Number=1,Type=Integer,Description=\"Homopolymer run length: the number of consecutive nucleotides in the reference genome matching the alternate allele prior to the current position\">" << endl
        << "##INFO=<ID=SNP,Number=0,Type=Flag,Description=\"SNP allele\">" << endl
        << "##INFO=<ID=TS,Number=0,Type=Flag,Description=\"transition SNP\">" << endl
        << "##INFO=<ID=TV,Number=0,Type=Flag,Description=\"transversion SNP\">" << endl
        << "##INFO=<ID=CpG,Number=0,Type=Flag,Description=\"CpG site (either CpG, TpG or CpA)\">" << endl
        << "##INFO=<ID=MNP,Number=0,Type=Integer,Description=\"Lengeth of MNP allele, if present\">" << endl
        << "##INFO=<ID=INS,Number=1,Type=Integer,Description=\"Length of insertion allele, if present\">" << endl
        << "##INFO=<ID=DEL,Number=1,Type=Integer,Description=\"Length of deletion allele, if present\">" << endl
        << "##FORMAT=<ID=GT,Number=1,Type=String,\"Genotype\">" << endl
        << "##FORMAT=<ID=GQ,Number=1,Type=Integer,\"Genotype Quality\">" << endl
        << "##FORMAT=<ID=DP,Number=1,Type=Integer,\"Read Depth\">" << endl
        << "##FORMAT=<ID=RA,Number=1,Type=Integer,\"Reference allele observations\">" << endl
        << "##FORMAT=<ID=AA,Number=1,Type=Integer,\"Alternate allele observations\">" << endl
        << "##FORMAT=<ID=BCF,Number=2,Type=Integer,\"Number of forward-strand reference and alternate allele observations\">" << endl
        << "##FORMAT=<ID=BCR,Number=2,Type=Integer,\"Number of reverse-strand reference and alternate allele observations\">" << endl
        << "#CHROM\tPOS\tID\tREF\tALT\tQUAL\tFILTER\tINFO\tFORMAT";
    for (vector<string>::iterator s = samples.begin(); s != samples.end(); ++s) {
        out << "\t" << *s;
    }
    out << endl;

}

string vcf(
        long double comboProb,
        //long double alleleSamplingProb,
        Samples& samples,
        string refbase,
        string altbase,
        Allele& altAllele,
        vector<string>& sampleNames,
        int coverage,
        GenotypeCombo& genotypeCombo,
        Results& results,
        AlleleParser* parser) {

    stringstream out;

    // TODO make it so you use the genotypeCombo...

    GenotypeComboMap comboMap;
    genotypeCombo2Map(genotypeCombo, comboMap);

    int samplesWithData = 0;
    // count alternate alleles in the best genotyping
    int alternateCount = 0;
    int alleleCount = 0;
    // reference / alternate base counts by strand
    map<string, pair<int, int> > altAndRefCountsBySample;
    int alternateObsCount = 0;
    int referenceObsCount = 0;
    // het counts
    int hetReferenceObsCount = 0;
    int hetAlternateObsCount = 0;
    int hetAllObsCount = 0;
    pair<int, int> baseCountsForwardTotal = make_pair(0, 0);
    pair<int, int> baseCountsReverseTotal = make_pair(0, 0);
    map<string, pair<int, int> > baseCountsForwardBySample;
    map<string, pair<int, int> > baseCountsReverseBySample;
    for (vector<string>::iterator sampleName = sampleNames.begin(); sampleName != sampleNames.end(); ++sampleName) {
        GenotypeComboMap::iterator gc = comboMap.find(*sampleName);
        //cerr << "alternate count for " << altbase << " and " << *genotype << " is " << genotype->alleleCount(altbase) << endl;
        if (gc != comboMap.end()) {
            Genotype* genotype = gc->second.first;

            Sample& sample = samples[*sampleName];

            // check that we actually have observations for this sample
            int observationCount = sample.observationCount();
            if (observationCount == 0) {
                continue;
            } else {
                ++samplesWithData;
            }

            alternateCount += genotype->alleleFrequency(altbase);
            alleleCount += genotype->ploidy;

            if (!genotype->homozygous) {
                hetAllObsCount += observationCount;
                hetReferenceObsCount += sample[refbase].size();
                hetAlternateObsCount += sample[altbase].size();
            }

            pair<int, int> altAndRefCounts = make_pair(sample.observationCount(altbase), sample.observationCount(refbase));
            altAndRefCountsBySample[*sampleName] = altAndRefCounts;
            alternateObsCount += altAndRefCounts.first;
            referenceObsCount += altAndRefCounts.second;

            pair<pair<int,int>, pair<int,int> > baseCounts = sample.baseCount(refbase, altbase);
            baseCountsForwardBySample[*sampleName] = baseCounts.first;
            baseCountsReverseBySample[*sampleName] = baseCounts.second;
            baseCountsForwardTotal.first += baseCounts.first.first;
            baseCountsForwardTotal.second += baseCounts.first.second;
            baseCountsReverseTotal.first += baseCounts.second.first;
            baseCountsReverseTotal.second += baseCounts.second.second;
        }
    }

    int allObsCount = alternateObsCount + referenceObsCount;

    // 0-based variant position
    long unsigned int variantPosition = (long unsigned int) parser->currentPosition;

    string referenceSequence;
    string alternateSequence;
    switch (altAllele.type) {
        case ALLELE_SNP:
            referenceSequence = refbase;
            alternateSequence = altAllele.alternateSequence;
            break;
        case ALLELE_MNP:
            referenceSequence = parser->referenceSubstr(variantPosition, altAllele.length);
            alternateSequence = altAllele.alternateSequence;
            break;
        case ALLELE_DELETION:
            referenceSequence = parser->referenceSubstr(variantPosition - 1, altAllele.length + 1);
            // this decrement fixes deletion position reporting to match VCF
            // spec, in which we are reporting the position of the base prior
            // to the deletion
            --variantPosition;
            alternateSequence = referenceSequence.at(0);
            break;
        case ALLELE_INSERTION:
            referenceSequence = refbase;
            alternateSequence = refbase + altAllele.alternateSequence.substr(1); // strip leading "I"
            break;
        default:
            cerr << "Unhandled allele type: " << altAllele.typeStr() << endl;
            break;
    }

    //string refbase = parser->currentReferenceBase();
    // positional information
    // CHROM  POS  ID  REF  ALT  QUAL  FILTER  INFO  FORMAT
    out << parser->currentTarget->seq << "\t"
        << variantPosition + 1 << "\t"
        << "." << "\t"
        << referenceSequence << "\t"
        << alternateSequence << "\t"
        << float2phred(1 - comboProb) << "\t"
        << "." << "\t" // filter, no filter applied
        << "NS=" << samplesWithData << ";"
        << "DP=" << coverage << ";"
        << "AC=" << alternateCount << ";"
        << "AN=" << alleleCount << ";"
        //<< "AF=" << (double) alternateCount / (double) alleleCount << ";" // estimated alternate allele frequency in the range (0,1]
        // strand specific base counts, forward strand, reference and alternate, colon separated, comma separated for each alternate
        << "BCF=" << baseCountsForwardTotal.first << "," << baseCountsForwardTotal.second << ";"
        // strand specific base counts, reverse strand, reference and alternate, colon separated, comma separated for each alternate
        << "BCR=" << baseCountsReverseTotal.first << "," << baseCountsReverseTotal.second << ";"
        // strand bias for the alternate allele, a number between 0 and 1 representing the (weighted) ratio
        // of forward strand sequence reads showing the alternate
        // allele to all sequence reads showing the alternate allele
        << "SB=" << (double) baseCountsForwardTotal.second / (double) alternateObsCount << ";"
        // allele balance at heterozygous sites, a number between 0 and 1 representing the weighted ratio of
        // reads showing the reference allele to all reads,
        // restricted to sequence data from individuals who appear
        // to be heterozygous at this site.
        << "AB=" << ((hetAllObsCount == 0) ? 0 : (double) hetReferenceObsCount / (double) hetAllObsCount ) << ";"
        // allele balance counts, two numbers, comma separated, giving the numbers of sequence reads
        // from apparent heterozygotes which show the reference and
        // alternate alleles for this site.  ignores mapping strand
        // information.  these could be totals of numbers from the
        // bc fields for individual genotypes, counting only
        // individuals who are heterozygous.
        << "ABB=" << hetReferenceObsCount << "," << hetAlternateObsCount <<  ";"
        //<< "PRSQ=;" // TODO predicted R-squared number between 0 and 1 which estimates the correlation at
                    // each site between imputed genotypes and the actual
                    // alternate allele counts that would be found if
                    // experimental genotyping were done on this panel of
                    // individuals
        //<< "AVPR=;" // TODO average posterior probability for genotype calls,
                    // average across all individuals of the posterior probability for the
                    // most probable discrete genotype call
        // homopolymer run length.  number of consecutive nucleotides (prior to this position?) in the genome
        // reference sequence matching the alternate allele, after substituting the
        // alternate in place of the reference sequence allele
        << "RUN=" << parser->homopolymerRunLeft(altbase) + 1 + parser->homopolymerRunRight(altbase) << ";";

    // allele class
    if (altAllele.type == ALLELE_DELETION) {
        out << "DEL=" << altAllele.length;
    } else if (altAllele.type == ALLELE_INSERTION) {
        out << "INS=" << altAllele.length;
    } else if (altAllele.type == ALLELE_SNP) {
        out << "SNP";
        // ts/tv
        if (isTransition(refbase, altbase)) {
            out << ";TS";
        } else {
            out << ";TV";
        }

        // CpG
        if (parser->isCpG(altbase)) {
            out << ";CpG";
        }
    } else if (altAllele.type == ALLELE_MNP) {
        out << "MNP=" << altAllele.length;
    }

    out << "\t" << "GT:GQ:DP:RA:AA:BCF:BCR";
    // TODO GL, un-normalized data likelihoods for genotypes

    // samples
    for (vector<string>::iterator sampleName = sampleNames.begin(); sampleName != sampleNames.end(); ++sampleName) {
        GenotypeComboMap::iterator gc = comboMap.find(*sampleName);
        Results::iterator s = results.find(*sampleName);
        if (gc != comboMap.end() && s != results.end()) {
            ResultData& sample = s->second;
            Genotype* genotype = gc->second.first;
            pair<int, int> altAndRefCounts = altAndRefCountsBySample[*sampleName]; // alternateAndReferenceCount(sample.observations, refbase, altbase);
            out << "\t"
                << genotype->relativeGenotype(refbase, altbase)
                << ":" << float2phred(1 - safe_exp(sample.marginals[genotype]))
                << ":" << sample.observations->observationCount()
                << ":" << altAndRefCounts.second
                << ":" << altAndRefCounts.first
                << ":" << sample.observations->baseCount(refbase, STRAND_FORWARD) << "," << sample.observations->baseCount(altbase, STRAND_FORWARD) // TODO
                << ":" << sample.observations->baseCount(refbase, STRAND_REVERSE) << "," << sample.observations->baseCount(altbase, STRAND_REVERSE) // TODO
                ;
                //<< ":" << "GL"  // TODO
        } else {
            out << "\t.";
        }
    }

    return out.str();
}

pair<Genotype*, long double> ResultData::bestMarginalGenotype(void) {
    map<Genotype*, long double>::iterator g = marginals.begin();
    pair<Genotype*, long double> best = make_pair(g->first, g->second); ++g;
    for ( ; g != marginals.end() ; ++g) {
        if (g->second > best.second) {
            best = make_pair(g->first, g->second);
        }
    }
    return best;
}

// TODO vcf output

<commit_msg>more vcf cleanup<commit_after>#include "ResultData.h"

using namespace std;

void json(ostream& out, Results& results, AlleleParser* parser) {
    out << "{";
    for (Results::iterator r = results.begin(); r != results.end(); ++r) {
        ResultData& sample = r->second;
        if (r != results.begin()) out << ",";
        out << "\"" << sample.name << "\":{"
            << "\"coverage\":" << sample.observations->observationCount() << ","
            << "\"genotypes\":[";
        for (map<Genotype*, long double>::iterator g = sample.marginals.begin();
                g != sample.marginals.end(); ++g) {
            if (g != sample.marginals.begin()) cout << ",";
            out << "[\"" << *(g->first) << "\"," << safe_exp(g->second) << "]";
        }
        out << "]";
        if (parser->parameters.outputAlleles)
            out << ",\"alleles\":" << sample.observations->json();
        out << "}";

    }
    out << "}";
}

// current date string in YYYYMMDD format
string dateStr(void) {

    time_t rawtime;
    struct tm* timeinfo;
    char buffer[80];

    time(&rawtime);
    timeinfo = localtime(&rawtime);

    strftime(buffer, 80, "%Y%m%d", timeinfo);

    return string(buffer);

}

void vcfHeader(ostream& out,
        string referenceName,
        vector<string>& samples,
        Parameters& parameters) {

    out << "##fileformat=VCFv4.0" << endl
        << "##fileDate=" << dateStr() << endl
        << "##source=freeBayes version " << FREEBAYES_VERSION << endl
        << "##reference=" << referenceName << endl
        << "##phasing=none" << endl
        << "##commandline=\"" << parameters.commandline << "\"" << endl
        << "##INFO=<ID=NS,Number=1,Type=Integer,Description=\"Number of samples with data\">" << endl
        << "##INFO=<ID=DP,Number=1,Type=Integer,Description=\"Total read depth at the locus\">" << endl
        << "##INFO=<ID=AC,Number=1,Type=Integer,Description=\"Total number of alternate alleles in called genotypes\">" << endl
        << "##INFO=<ID=AN,Number=1,Type=Integer,Description=\"Total number of alleles in called genotypes\">" << endl
        //<< "##INFO=<ID=AF,Number=1,Type=Float,Description=\"Estimated allele frequency in the range (0,1]\">" << endl
        << "##INFO=<ID=BCF,Number=2,Type=Integer,Description=\"Forward-strand base count: the number of observations on the forward strand for, the reference, the first alternate, the second alternate, and so on for each alternate\">" << endl
        << "##INFO=<ID=BCR,Number=2,Type=Integer,Description=\"Reverse-strand base count: the number of observations on the reverse strand for, the reference, the first alternate, the second alternate, and so on for each alternate\">" << endl
        << "##INFO=<ID=SB,Number=1,Type=Float,Description=\"Strand bias for the alternate allele: a number between 0 and 1 representing the ratio of forward strand sequence reads showing the alternate allele to all reads, considering only reads from individuals called as heterozygous\">" << endl
        << "##INFO=<ID=AB,Number=1,Type=Integer,Description=\"Allele balance at heterozygous sites: a number beween 0 and 1 representing the ratio of reads showing the reference allele to all reads, considering only reads from individuals called as heterozygous\">" << endl
        << "##INFO=<ID=ABB,Number=2,Type=Integer,Description=\"Allele balance counts: two numbers giving the numbers of sequence reads from apparent heterozygotes which show reference and alternate alleles for the site\">" << endl
        << "##INFO=<ID=RUN,Number=1,Type=Integer,Description=\"Homopolymer run length: the number of consecutive nucleotides in the reference genome matching the alternate allele prior to the current position\">" << endl
        << "##INFO=<ID=SNP,Number=0,Type=Flag,Description=\"SNP allele\">" << endl
        << "##INFO=<ID=TS,Number=0,Type=Flag,Description=\"transition SNP\">" << endl
        << "##INFO=<ID=TV,Number=0,Type=Flag,Description=\"transversion SNP\">" << endl
        << "##INFO=<ID=CpG,Number=0,Type=Flag,Description=\"CpG site (either CpG, TpG or CpA)\">" << endl
        << "##INFO=<ID=MNP,Number=0,Type=Integer,Description=\"Lengeth of MNP allele, if present\">" << endl
        << "##INFO=<ID=INS,Number=1,Type=Integer,Description=\"Length of insertion allele, if present\">" << endl
        << "##INFO=<ID=DEL,Number=1,Type=Integer,Description=\"Length of deletion allele, if present\">" << endl
        << "##FORMAT=<ID=GT,Number=1,Type=String,Description=\"Genotype\">" << endl
        << "##FORMAT=<ID=GQ,Number=1,Type=Integer,Description=\"Genotype Quality\">" << endl
        << "##FORMAT=<ID=DP,Number=1,Type=Integer,Description=\"Read Depth\">" << endl
        << "##FORMAT=<ID=RA,Number=1,Type=Integer,Description=\"Reference allele observations\">" << endl
        << "##FORMAT=<ID=AA,Number=1,Type=Integer,Description=\"Alternate allele observations\">" << endl
        << "##FORMAT=<ID=BCF,Number=2,Type=Integer,Description=\"Number of forward-strand reference and alternate allele observations\">" << endl
        << "##FORMAT=<ID=BCR,Number=2,Type=Integer,Description=\"Number of reverse-strand reference and alternate allele observations\">" << endl
        << "#CHROM\tPOS\tID\tREF\tALT\tQUAL\tFILTER\tINFO\tFORMAT";
    for (vector<string>::iterator s = samples.begin(); s != samples.end(); ++s) {
        out << "\t" << *s;
    }
    out << endl;

}

string vcf(
        long double comboProb,
        //long double alleleSamplingProb,
        Samples& samples,
        string refbase,
        string altbase,
        Allele& altAllele,
        vector<string>& sampleNames,
        int coverage,
        GenotypeCombo& genotypeCombo,
        Results& results,
        AlleleParser* parser) {

    stringstream out;

    // TODO make it so you use the genotypeCombo...

    GenotypeComboMap comboMap;
    genotypeCombo2Map(genotypeCombo, comboMap);

    int samplesWithData = 0;
    // count alternate alleles in the best genotyping
    int alternateCount = 0;
    int alleleCount = 0;
    // reference / alternate base counts by strand
    map<string, pair<int, int> > altAndRefCountsBySample;
    int alternateObsCount = 0;
    int referenceObsCount = 0;
    // het counts
    int hetReferenceObsCount = 0;
    int hetAlternateObsCount = 0;
    int hetAllObsCount = 0;
    pair<int, int> baseCountsForwardTotal = make_pair(0, 0);
    pair<int, int> baseCountsReverseTotal = make_pair(0, 0);
    map<string, pair<int, int> > baseCountsForwardBySample;
    map<string, pair<int, int> > baseCountsReverseBySample;
    for (vector<string>::iterator sampleName = sampleNames.begin(); sampleName != sampleNames.end(); ++sampleName) {
        GenotypeComboMap::iterator gc = comboMap.find(*sampleName);
        //cerr << "alternate count for " << altbase << " and " << *genotype << " is " << genotype->alleleCount(altbase) << endl;
        if (gc != comboMap.end()) {
            Genotype* genotype = gc->second.first;

            Sample& sample = samples[*sampleName];

            // check that we actually have observations for this sample
            int observationCount = sample.observationCount();
            if (observationCount == 0) {
                continue;
            } else {
                ++samplesWithData;
            }

            alternateCount += genotype->alleleFrequency(altbase);
            alleleCount += genotype->ploidy;

            if (!genotype->homozygous) {
                hetAllObsCount += observationCount;
                hetReferenceObsCount += sample[refbase].size();
                hetAlternateObsCount += sample[altbase].size();
            }

            pair<int, int> altAndRefCounts = make_pair(sample.observationCount(altbase), sample.observationCount(refbase));
            altAndRefCountsBySample[*sampleName] = altAndRefCounts;
            alternateObsCount += altAndRefCounts.first;
            referenceObsCount += altAndRefCounts.second;

            pair<pair<int,int>, pair<int,int> > baseCounts = sample.baseCount(refbase, altbase);
            baseCountsForwardBySample[*sampleName] = baseCounts.first;
            baseCountsReverseBySample[*sampleName] = baseCounts.second;
            baseCountsForwardTotal.first += baseCounts.first.first;
            baseCountsForwardTotal.second += baseCounts.first.second;
            baseCountsReverseTotal.first += baseCounts.second.first;
            baseCountsReverseTotal.second += baseCounts.second.second;
        }
    }

    int allObsCount = alternateObsCount + referenceObsCount;

    // 0-based variant position
    long unsigned int variantPosition = (long unsigned int) parser->currentPosition;

    string referenceSequence;
    string alternateSequence;
    switch (altAllele.type) {
        case ALLELE_SNP:
            referenceSequence = refbase;
            alternateSequence = altAllele.alternateSequence;
            break;
        case ALLELE_MNP:
            referenceSequence = parser->referenceSubstr(variantPosition, altAllele.length);
            alternateSequence = altAllele.alternateSequence;
            break;
        case ALLELE_DELETION:
            referenceSequence = parser->referenceSubstr(variantPosition - 1, altAllele.length + 1);
            // this decrement fixes deletion position reporting to match VCF
            // spec, in which we are reporting the position of the base prior
            // to the deletion
            --variantPosition;
            alternateSequence = referenceSequence.at(0);
            break;
        case ALLELE_INSERTION:
            referenceSequence = refbase;
            alternateSequence = refbase + altAllele.alternateSequence.substr(1); // strip leading "I"
            break;
        default:
            cerr << "Unhandled allele type: " << altAllele.typeStr() << endl;
            break;
    }

    //string refbase = parser->currentReferenceBase();
    // positional information
    // CHROM  POS  ID  REF  ALT  QUAL  FILTER  INFO  FORMAT
    out << parser->currentTarget->seq << "\t"
        << variantPosition + 1 << "\t"
        << "." << "\t"
        << referenceSequence << "\t"
        << alternateSequence << "\t"
        << float2phred(1 - comboProb) << "\t"
        << "." << "\t" // filter, no filter applied
        << "NS=" << samplesWithData << ";"
        << "DP=" << coverage << ";"
        << "AC=" << alternateCount << ";"
        << "AN=" << alleleCount << ";"
        //<< "AF=" << (double) alternateCount / (double) alleleCount << ";" // estimated alternate allele frequency in the range (0,1]
        // strand specific base counts, forward strand, reference and alternate, colon separated, comma separated for each alternate
        << "BCF=" << baseCountsForwardTotal.first << "," << baseCountsForwardTotal.second << ";"
        // strand specific base counts, reverse strand, reference and alternate, colon separated, comma separated for each alternate
        << "BCR=" << baseCountsReverseTotal.first << "," << baseCountsReverseTotal.second << ";"
        // strand bias for the alternate allele, a number between 0 and 1 representing the (weighted) ratio
        // of forward strand sequence reads showing the alternate
        // allele to all sequence reads showing the alternate allele
        << "SB=" << (double) baseCountsForwardTotal.second / (double) alternateObsCount << ";"
        // allele balance at heterozygous sites, a number between 0 and 1 representing the weighted ratio of
        // reads showing the reference allele to all reads,
        // restricted to sequence data from individuals who appear
        // to be heterozygous at this site.
        << "AB=" << ((hetAllObsCount == 0) ? 0 : (double) hetReferenceObsCount / (double) hetAllObsCount ) << ";"
        // allele balance counts, two numbers, comma separated, giving the numbers of sequence reads
        // from apparent heterozygotes which show the reference and
        // alternate alleles for this site.  ignores mapping strand
        // information.  these could be totals of numbers from the
        // bc fields for individual genotypes, counting only
        // individuals who are heterozygous.
        << "ABB=" << hetReferenceObsCount << "," << hetAlternateObsCount <<  ";"
        //<< "PRSQ=;" // TODO predicted R-squared number between 0 and 1 which estimates the correlation at
                    // each site between imputed genotypes and the actual
                    // alternate allele counts that would be found if
                    // experimental genotyping were done on this panel of
                    // individuals
        //<< "AVPR=;" // TODO average posterior probability for genotype calls,
                    // average across all individuals of the posterior probability for the
                    // most probable discrete genotype call
        // homopolymer run length.  number of consecutive nucleotides (prior to this position?) in the genome
        // reference sequence matching the alternate allele, after substituting the
        // alternate in place of the reference sequence allele
        << "RUN=" << parser->homopolymerRunLeft(altbase) + 1 + parser->homopolymerRunRight(altbase) << ";";

    // allele class
    if (altAllele.type == ALLELE_DELETION) {
        out << "DEL=" << altAllele.length;
    } else if (altAllele.type == ALLELE_INSERTION) {
        out << "INS=" << altAllele.length;
    } else if (altAllele.type == ALLELE_SNP) {
        out << "SNP";
        // ts/tv
        if (isTransition(refbase, altbase)) {
            out << ";TS";
        } else {
            out << ";TV";
        }

        // CpG
        if (parser->isCpG(altbase)) {
            out << ";CpG";
        }
    } else if (altAllele.type == ALLELE_MNP) {
        out << "MNP=" << altAllele.length;
    }

    out << "\t" << "GT:GQ:DP:RA:AA:BCF:BCR";
    // TODO GL, un-normalized data likelihoods for genotypes

    // samples
    for (vector<string>::iterator sampleName = sampleNames.begin(); sampleName != sampleNames.end(); ++sampleName) {
        GenotypeComboMap::iterator gc = comboMap.find(*sampleName);
        Results::iterator s = results.find(*sampleName);
        if (gc != comboMap.end() && s != results.end()) {
            ResultData& sample = s->second;
            Genotype* genotype = gc->second.first;
            pair<int, int> altAndRefCounts = altAndRefCountsBySample[*sampleName]; // alternateAndReferenceCount(sample.observations, refbase, altbase);
            out << "\t"
                << genotype->relativeGenotype(refbase, altbase)
                << ":" << float2phred(1 - safe_exp(sample.marginals[genotype]))
                << ":" << sample.observations->observationCount()
                << ":" << altAndRefCounts.second
                << ":" << altAndRefCounts.first
                << ":" << sample.observations->baseCount(refbase, STRAND_FORWARD) << "," << sample.observations->baseCount(altbase, STRAND_FORWARD) // TODO
                << ":" << sample.observations->baseCount(refbase, STRAND_REVERSE) << "," << sample.observations->baseCount(altbase, STRAND_REVERSE) // TODO
                ;
                //<< ":" << "GL"  // TODO
        } else {
            out << "\t.";
        }
    }

    return out.str();
}

pair<Genotype*, long double> ResultData::bestMarginalGenotype(void) {
    map<Genotype*, long double>::iterator g = marginals.begin();
    pair<Genotype*, long double> best = make_pair(g->first, g->second); ++g;
    for ( ; g != marginals.end() ; ++g) {
        if (g->second > best.second) {
            best = make_pair(g->first, g->second);
        }
    }
    return best;
}

// TODO vcf output

<|endoftext|>


<commit_before>
#include "SimpleJSON.h"
#include "logger.h"

#include <sstream>

using namespace std;

/*****************************************************************************
 *                          Writers
 *****************************************************************************/
SimpleJSONBuilderCompactWriter::SimpleJSONBuilderCompactWriter()
    : rapidjson::Writer<rapidjson::StringBuffer>(
          static_cast<rapidjson::StringBuffer&>(*this))
{
}

void SimpleJSONBuilderCompactWriter::ResetAndClear() {
    rapidjson::StringBuffer::Clear();
    rapidjson::Writer<rapidjson::StringBuffer>::Reset(
        static_cast<rapidjson::StringBuffer&>(*this));
}

SimpleJSONBuilderPrettyWriter::SimpleJSONBuilderPrettyWriter()
    : rapidjson::PrettyWriter<rapidjson::StringBuffer>(
          static_cast<rapidjson::StringBuffer&>(*this))
{
}

void SimpleJSONBuilderPrettyWriter::ResetAndClear() {
    rapidjson::StringBuffer::Clear();
    rapidjson::PrettyWriter<rapidjson::StringBuffer>::Reset(
        static_cast<rapidjson::StringBuffer&>(*this));
}

/*****************************************************************************
 *                          Base Scalar Field
 *****************************************************************************/
FieldBase::FieldBase()
    : supplied(false)
{
}

void FieldBase::Clear() {
    supplied = false;
}

bool FieldBase::StartObject() {
   throw spJSON::WrongTypeError{Name()};
}

bool FieldBase::EndObject(rapidjson::SizeType memberCount) {
   throw spJSON::WrongTypeError{Name()};
}

bool FieldBase::String(const char* str, rapidjson::SizeType length, bool copy) {
   throw spJSON::WrongTypeError{Name()};
}

bool FieldBase::Key(const char* str, rapidjson::SizeType length, bool copy) {
   throw spJSON::WrongTypeError{Name()};
}

bool FieldBase::Int(int i) {
   throw spJSON::WrongTypeError{Name()};
}

bool FieldBase::Int64(int64_t i) {
   throw spJSON::WrongTypeError{Name()};
}

bool FieldBase::Uint(unsigned u) {
   throw spJSON::WrongTypeError{Name()};
}

bool FieldBase::Uint64(uint64_t u) {
   throw spJSON::WrongTypeError{Name()};
}

bool FieldBase::Double(double d) {
   throw spJSON::WrongTypeError{Name()};
}

bool FieldBase::Bool(bool b) {
   throw spJSON::WrongTypeError{Name()};
}

bool FieldBase::StartArray() {
   throw spJSON::WrongTypeError{Name()};
}

bool FieldBase::EndArray(rapidjson::SizeType elementCount) {
   throw spJSON::WrongTypeError{Name()};
}

bool FieldBase::Null() {
   supplied = false;
   return true;
}

/*****************************************************************************
 *                          SimpleParsedJSON - Auto-generate
 *****************************************************************************/

class SimpleParsedJSON_Generator {
public:
    SimpleParsedJSON_Generator(
        const std::string _namespaceName = "",
        const std::string _indent = "    ")
            : started(false),
              isArray(false),
              arrayTyped(false),
              childObject(nullptr),
              indent(_indent),
              namespaceName(_namespaceName)
    {
        int nsIndentSize = indent.length() -4;
        if (nsIndentSize < 0 ) {
            nsIndentSize = 0;
        }
        nsIndent = indent.substr(0,nsIndentSize);
    }

    SimpleParsedJSON_Generator& ActiveObject() {
        SimpleParsedJSON_Generator* obj = childObject.get();

        if (obj) {
            return obj->ActiveObject();
        } else {
            return *this;
        }
    }

    bool IgnoreField() {
        return (isArray && arrayTyped);
    }

    bool Key(const char* str, rapidjson::SizeType length, bool copy) {
        auto& active = ActiveObject();
        if ( !active.IgnoreField() ) {
            string field = str;
            active.keys[field] = "";
            active.current = active.keys.find(field);
        }

        return true;
    }

    bool String(const char* str, rapidjson::SizeType length, bool copy) {
        auto& active = ActiveObject();
        if ( active.isArray ) {
            if (!active.arrayTyped) {
                SLOG_FROM(
                    LOG_VERY_VERBOSE,
                    "SimpleParsedJSON_Generator::String",
                    "Array " << active.namespaceName << "::" << active.current->first << " is a String.");

                active.current->second =   active.indent + "NewStringArrayField("
                                         + active.current->first + ");";
                active.arrayTyped = true;
            }
        } else {
            SLOG_FROM(
                LOG_VERY_VERBOSE,
                "SimpleParsedJSON_Generator::String",
                "Field " << active.namespaceName << "::" << active.current->first << " is a String.");
            active.current->second =   active.indent + "NewStringField("
                                     + active.current->first + ");";
        }
        return true;
    }

    bool Double(double d) {
        auto& active = ActiveObject();
        if ( active.isArray ) {
            if (!active.arrayTyped) {
                SLOG_FROM(
                    LOG_VERY_VERBOSE,
                    "SimpleParsedJSON_Generator::Double",
                    "Array " << active.namespaceName << "::" << active.current->first << " is a Double.");

                active.current->second =
                      active.indent + "NewDoubleArrayField("
                    + active.current->first + ");";
                active.arrayTyped = true;
            }
        } else {
            SLOG_FROM(
                LOG_VERY_VERBOSE,
                "SimpleParsedJSON_Generator::Double",
                "Field " << active.namespaceName << "::" << active.current->first << " is a Double.");

            active.current->second =   active.indent + "NewDoubleField("
                                     + active.current->first + ");";
        }
        return true;
    }

    bool Int(int i) {
        auto& active = ActiveObject();
        if ( active.isArray ) {
            if (!active.arrayTyped) {
                SLOG_FROM(
                    LOG_VERY_VERBOSE,
                    "SimpleParsedJSON_Generator::Int",
                    "Array " << active.namespaceName << "::" << active.current->first << " is a Int.");

                active.current->second =   active.indent + "NewIntArrayField("
                                         + active.current->first + ");";
                active.arrayTyped = true;
            }
        } else {
            SLOG_FROM(
                LOG_VERY_VERBOSE,
                "SimpleParsedJSON_Generator::Int",
                "Field " << active.namespaceName << "::" << active.current->first << " is a Int.");
            active.current->second =   active.indent + "NewIntField("
                                     + active.current->first + ");";
        }
        return true;
    }

    bool Int64(int64_t i) {
        auto& active = ActiveObject();
        if ( active.isArray ) {
            if (!active.arrayTyped) {
                SLOG_FROM(
                    LOG_VERY_VERBOSE,
                    "SimpleParsedJSON_Generator::Int64",
                    "Array " << active.namespaceName << "::" << active.current->first << " is a Int64.");

                active.current->second =   active.indent + "NewI64ArrayField("
                                         + active.current->first + ");";
                active.arrayTyped = true;
            }
        } else {
            SLOG_FROM(
                LOG_VERY_VERBOSE,
                "SimpleParsedJSON_Generator::Int64",
                "Field " << active.namespaceName << "::" << active.current->first << " is a Int64.");
            active.current->second =   active.indent + "NewI64Field("
                                     + active.current->first + ");";
        }
        return true;
    }

    bool Uint(unsigned u) {
        auto& active = ActiveObject();
        if ( active.isArray ) {
            if (!active.arrayTyped) {
                SLOG_FROM(
                    LOG_VERY_VERBOSE,
                    "SimpleParsedJSON_Generator::Uint",
                    "Array " << active.namespaceName << "::" << active.current->first << " is a Uint.");

                active.current->second =
                    active.indent + "NewUIntArrayField("
                  + active.current->first + ");";

                active.arrayTyped = true;
            }
        } else {
            SLOG_FROM(
                LOG_VERY_VERBOSE,
                "SimpleParsedJSON_Generator::Uint",
                "Field " << active.namespaceName << "::" << active.current->first << " is a Uint.");
            active.current->second =   active.indent + "NewUIntField("
                                     + active.current->first + ");";
        }
        return true;
    }

    bool Uint64(uint64_t u) {
        auto& active = ActiveObject();
        if ( active.isArray ) {
            if (!active.arrayTyped) {
                SLOG_FROM(
                    LOG_VERY_VERBOSE,
                    "SimpleParsedJSON_Generator::Uint64",
                    "Array " << active.namespaceName << "::" << active.current->first << " is a Uint64.");

                active.current->second =
                    active.indent + "NewUI64ArrayField("
                    + active.current->first + ");";
                active.arrayTyped = true;
            }
        } else {
            SLOG_FROM(
                LOG_VERY_VERBOSE,
                "SimpleParsedJSON_Generator::Uint64",
                "Field " << active.namespaceName << "::" << active.current->first << " is a Uint64.");
            active.current->second =   active.indent + "NewUI64Field("
                                     + active.current->first + ");";
        }
        return true;
    }

    bool Bool(bool b) {
        auto& active = ActiveObject();
        if ( active.isArray ) {
            if (!active.arrayTyped) {
                SLOG_FROM(
                    LOG_VERY_VERBOSE,
                    "SimpleParsedJSON_Generator::Bool",
                    "Array " << active.namespaceName << "::" << active.current->first << " is a bool.");

                active.current->second =   active.indent + "NewBoolArrayField("
                                         + active.current->first + ");";
                active.arrayTyped = true;

            }
        } else {
            SLOG_FROM(
                LOG_VERY_VERBOSE,
                "SimpleParsedJSON_Generator::Bool",
                "Field " << active.namespaceName << "::" << active.current->first << " is a bool.");

            active.current->second =   active.indent + "NewBoolField("
                                     + active.current->first + ");";
        }
        return true;
    }

    virtual bool StartArray() {
        auto& active = ActiveObject();

        if ( !active.IgnoreField() ) {
            active.isArray = true;
            active.arrayTyped = false;

            SLOG_FROM(
                LOG_VERY_VERBOSE,
                "SimpleParsedJSON_Generator::StartArray",
                "Starting new array " << active.namespaceName << "::" << active.current->first);
        } else {
            SLOG_FROM(
                LOG_VERY_VERBOSE,
                "SimpleParsedJSON_Generator::StartArray",
                "Ignoring new array " << active.namespaceName << "::" << active.current->first);
        }

        return true;
    }

    virtual bool EndArray(rapidjson::SizeType elementCount) {
        auto& active = ActiveObject();

        if (!active.arrayTyped) {
            SLOG_FROM(
                LOG_WARNING,
                "SimpleParsedJSON_Generator::EndArray",
                "Array " << active.namespaceName << "::" << active.current->first <<
                " finished, was NOT typed successfuly");
        } else {
            SLOG_FROM(
                LOG_VERY_VERBOSE,
                "SimpleParsedJSON_Generator::EndArray",
                "Array " << active.namespaceName << "::" << active.current->first <<
                " finished, was typed successfuly");
        }

        active.isArray = false;
        active.arrayTyped = false;

        return true;
    }

    bool StartObject() {
        if (started) {
            if ( !IgnoreField() ) {
                if(childObject.get()) {
                    LOG_FROM(
                        LOG_VERY_VERBOSE,
                        "SimpleParsedJSON_Generator::StartObject",
                        "forwarding to existing child object...");
                    childObject->StartObject();
                } else {
                    string childNamespace = current->first + "_fields";
                    SLOG_FROM(
                        LOG_VERY_VERBOSE,
                        "SimpleParsedJSON_Generator::StartObject",
                        "Starting a new child object: " << childNamespace);

                    childObject.reset(new SimpleParsedJSON_Generator(childNamespace, indent + "    "));
                    childObject->StartObject();
                }
            } else {
                SLOG_FROM(
                    LOG_VERY_VERBOSE,
                    "SimpleParsedJSON_Generator::StartObject",
                    "Skipping non first item for array "
                    << namespaceName << "::" << current->first)
            }
        } else {
            LOG_FROM(
                LOG_VERY_VERBOSE,
                "SimpleParsedJSON_Generator::StartObject",
                "Starting initial object");
            started = true;
        }
        return true;
    }

    bool EndObject(rapidjson::SizeType memberCount) {
        if (childObject.get()) {
            if ( !IgnoreField() ) {
                if (childObject->childObject.get()) {
                    LOG_FROM(
                        LOG_VERY_VERBOSE,
                        "SimpleParsedJSON_Generator::EndObject",
                        "Forwarding to child object...");
                    childObject->EndObject(memberCount);
                } else if (!childObject->IgnoreField()) {
                    const string& objName = current->first;
                    string jsonName =  current->first + "_fields::JSON";

                    SLOG_FROM(
                        LOG_VERY_VERBOSE,
                        "SimpleParsedJSON_Generator::EndObject",
                        "Completed object " << jsonName);

                    stringstream buf;
                    buf << endl;
                    buf << childObject->GetCode("JSON");

                    if (isArray) {
                        buf << indent << "NewObjectArray(";
                    } else {
                        buf << indent << "NewEmbededObject(";
                    }
                    buf << objName << ", " << jsonName << ");";

                    current->second = buf.str();
                    childObject.reset(nullptr);

                    if (isArray) {
                        SLOG_FROM(
                            LOG_VERY_VERBOSE,
                            "SimpleParsedJSON_Generator::EndObject",
                            "Terminated array "
                            << namespaceName << "::" << current->first
                            << " having completed the first item");
                        arrayTyped = true;
                    }
                } else {
                    SLOG_FROM(
                        LOG_VERY_VERBOSE,
                        "SimpleParsedJSON_Generator::EndObject",
                        "Ignored end of child object, whilst processing" << current->first);
                }
            } else {
                SLOG_FROM(
                    LOG_VERY_VERBOSE,
                    "SimpleParsedJSON_Generator::EndObject",
                    "Skipping non first item for array "
                    << namespaceName << "::" << current->first)
            }
        } else if (started) {
            LOG_FROM(
                LOG_VERY_VERBOSE,
                "SimpleParsedJSON_Generator::EndObject",
                "Terminated the object itself");
            started = false;
        } else {
            SLOG_FROM(
                LOG_WARNING,
                "SimpleParsedJSON_Generator::EndObject",
                "End of non-existent object!");
        }
        return true;
    }

    bool Null() {
        throw "TODO!";
    }

    string GetCode(const std::string& jsonName) {
        stringstream result;
        stringstream fields;
        if ( namespaceName != "" ) {
            result << nsIndent << "namespace " << namespaceName << " {" << endl;
        }
        const auto first = keys.begin();
        const auto last = --(keys.end());
        for (Keys::iterator it = first; it != keys.end(); ++it) {
            result << it->second << endl;
            fields << indent << "    " << it->first
                   << (it == last ? "": ",")
                   << endl;
        }
        result << endl;
        result << indent << "typedef SimpleParsedJSON<" << endl;
        result << fields.str();
        result << indent << "> " << jsonName << ";" << endl;
        if ( namespaceName != "" ) {
            result << nsIndent << "}" << endl;
        }
        return result.str();
    }

private:
    bool started; // Indicates if we have found the start of the outer object yet
    bool isArray; // Indicates if the field currently being scanned is an array
    bool arrayTyped; // Indicates if we've already found the first item in the array

    unique_ptr<SimpleParsedJSON_Generator> childObject;
    typedef std::map<std::string,std::string> Keys;
    Keys keys;
    Keys::iterator current;
    std::string indent;
    std::string nsIndent;
    std::string namespaceName;
};

std::string spJSON::Gen(const string& className, const string& exampleJson) {
    SimpleParsedJSON_Generator gen;

    rapidjson::StringStream ss(exampleJson.c_str());
    rapidjson::Reader reader;

    reader.Parse(ss,gen);

    return gen.GetCode(className);
}
<commit_msg>Suppress warnings about end of repeated objects / arrays.<commit_after>
#include "SimpleJSON.h"
#include "logger.h"

#include <sstream>

using namespace std;

/*****************************************************************************
 *                          Writers
 *****************************************************************************/
SimpleJSONBuilderCompactWriter::SimpleJSONBuilderCompactWriter()
    : rapidjson::Writer<rapidjson::StringBuffer>(
          static_cast<rapidjson::StringBuffer&>(*this))
{
}

void SimpleJSONBuilderCompactWriter::ResetAndClear() {
    rapidjson::StringBuffer::Clear();
    rapidjson::Writer<rapidjson::StringBuffer>::Reset(
        static_cast<rapidjson::StringBuffer&>(*this));
}

SimpleJSONBuilderPrettyWriter::SimpleJSONBuilderPrettyWriter()
    : rapidjson::PrettyWriter<rapidjson::StringBuffer>(
          static_cast<rapidjson::StringBuffer&>(*this))
{
}

void SimpleJSONBuilderPrettyWriter::ResetAndClear() {
    rapidjson::StringBuffer::Clear();
    rapidjson::PrettyWriter<rapidjson::StringBuffer>::Reset(
        static_cast<rapidjson::StringBuffer&>(*this));
}

/*****************************************************************************
 *                          Base Scalar Field
 *****************************************************************************/
FieldBase::FieldBase()
    : supplied(false)
{
}

void FieldBase::Clear() {
    supplied = false;
}

bool FieldBase::StartObject() {
   throw spJSON::WrongTypeError{Name()};
}

bool FieldBase::EndObject(rapidjson::SizeType memberCount) {
   throw spJSON::WrongTypeError{Name()};
}

bool FieldBase::String(const char* str, rapidjson::SizeType length, bool copy) {
   throw spJSON::WrongTypeError{Name()};
}

bool FieldBase::Key(const char* str, rapidjson::SizeType length, bool copy) {
   throw spJSON::WrongTypeError{Name()};
}

bool FieldBase::Int(int i) {
   throw spJSON::WrongTypeError{Name()};
}

bool FieldBase::Int64(int64_t i) {
   throw spJSON::WrongTypeError{Name()};
}

bool FieldBase::Uint(unsigned u) {
   throw spJSON::WrongTypeError{Name()};
}

bool FieldBase::Uint64(uint64_t u) {
   throw spJSON::WrongTypeError{Name()};
}

bool FieldBase::Double(double d) {
   throw spJSON::WrongTypeError{Name()};
}

bool FieldBase::Bool(bool b) {
   throw spJSON::WrongTypeError{Name()};
}

bool FieldBase::StartArray() {
   throw spJSON::WrongTypeError{Name()};
}

bool FieldBase::EndArray(rapidjson::SizeType elementCount) {
   throw spJSON::WrongTypeError{Name()};
}

bool FieldBase::Null() {
   supplied = false;
   return true;
}

/*****************************************************************************
 *                          SimpleParsedJSON - Auto-generate
 *****************************************************************************/

class SimpleParsedJSON_Generator {
public:
    SimpleParsedJSON_Generator(
        const std::string _namespaceName = "",
        const std::string _indent = "    ")
            : started(false),
              isArray(false),
              arrayTyped(false),
              childObject(nullptr),
              indent(_indent),
              namespaceName(_namespaceName)
    {
        int nsIndentSize = indent.length() -4;
        if (nsIndentSize < 0 ) {
            nsIndentSize = 0;
        }
        nsIndent = indent.substr(0,nsIndentSize);
    }

    SimpleParsedJSON_Generator& ActiveObject() {
        SimpleParsedJSON_Generator* obj = childObject.get();

        if (obj) {
            return obj->ActiveObject();
        } else {
            return *this;
        }
    }

    bool IgnoreField() {
        return (isArray && arrayTyped);
    }

    bool Key(const char* str, rapidjson::SizeType length, bool copy) {
        auto& active = ActiveObject();
        if ( !active.IgnoreField() ) {
            string field = str;
            active.keys[field] = "";
            active.current = active.keys.find(field);
        }

        return true;
    }

    bool String(const char* str, rapidjson::SizeType length, bool copy) {
        auto& active = ActiveObject();
        if ( active.isArray ) {
            if (!active.arrayTyped) {
                SLOG_FROM(
                    LOG_VERY_VERBOSE,
                    "SimpleParsedJSON_Generator::String",
                    "Array " << active.namespaceName << "::" << active.current->first << " is a String.");

                active.current->second =   active.indent + "NewStringArrayField("
                                         + active.current->first + ");";
                active.arrayTyped = true;
            }
        } else {
            SLOG_FROM(
                LOG_VERY_VERBOSE,
                "SimpleParsedJSON_Generator::String",
                "Field " << active.namespaceName << "::" << active.current->first << " is a String.");
            active.current->second =   active.indent + "NewStringField("
                                     + active.current->first + ");";
        }
        return true;
    }

    bool Double(double d) {
        auto& active = ActiveObject();
        if ( active.isArray ) {
            if (!active.arrayTyped) {
                SLOG_FROM(
                    LOG_VERY_VERBOSE,
                    "SimpleParsedJSON_Generator::Double",
                    "Array " << active.namespaceName << "::" << active.current->first << " is a Double.");

                active.current->second =
                      active.indent + "NewDoubleArrayField("
                    + active.current->first + ");";
                active.arrayTyped = true;
            }
        } else {
            SLOG_FROM(
                LOG_VERY_VERBOSE,
                "SimpleParsedJSON_Generator::Double",
                "Field " << active.namespaceName << "::" << active.current->first << " is a Double.");

            active.current->second =   active.indent + "NewDoubleField("
                                     + active.current->first + ");";
        }
        return true;
    }

    bool Int(int i) {
        auto& active = ActiveObject();
        if ( active.isArray ) {
            if (!active.arrayTyped) {
                SLOG_FROM(
                    LOG_VERY_VERBOSE,
                    "SimpleParsedJSON_Generator::Int",
                    "Array " << active.namespaceName << "::" << active.current->first << " is a Int.");

                active.current->second =   active.indent + "NewIntArrayField("
                                         + active.current->first + ");";
                active.arrayTyped = true;
            }
        } else {
            SLOG_FROM(
                LOG_VERY_VERBOSE,
                "SimpleParsedJSON_Generator::Int",
                "Field " << active.namespaceName << "::" << active.current->first << " is a Int.");
            active.current->second =   active.indent + "NewIntField("
                                     + active.current->first + ");";
        }
        return true;
    }

    bool Int64(int64_t i) {
        auto& active = ActiveObject();
        if ( active.isArray ) {
            if (!active.arrayTyped) {
                SLOG_FROM(
                    LOG_VERY_VERBOSE,
                    "SimpleParsedJSON_Generator::Int64",
                    "Array " << active.namespaceName << "::" << active.current->first << " is a Int64.");

                active.current->second =   active.indent + "NewI64ArrayField("
                                         + active.current->first + ");";
                active.arrayTyped = true;
            }
        } else {
            SLOG_FROM(
                LOG_VERY_VERBOSE,
                "SimpleParsedJSON_Generator::Int64",
                "Field " << active.namespaceName << "::" << active.current->first << " is a Int64.");
            active.current->second =   active.indent + "NewI64Field("
                                     + active.current->first + ");";
        }
        return true;
    }

    bool Uint(unsigned u) {
        auto& active = ActiveObject();
        if ( active.isArray ) {
            if (!active.arrayTyped) {
                SLOG_FROM(
                    LOG_VERY_VERBOSE,
                    "SimpleParsedJSON_Generator::Uint",
                    "Array " << active.namespaceName << "::" << active.current->first << " is a Uint.");

                active.current->second =
                    active.indent + "NewUIntArrayField("
                  + active.current->first + ");";

                active.arrayTyped = true;
            }
        } else {
            SLOG_FROM(
                LOG_VERY_VERBOSE,
                "SimpleParsedJSON_Generator::Uint",
                "Field " << active.namespaceName << "::" << active.current->first << " is a Uint.");
            active.current->second =   active.indent + "NewUIntField("
                                     + active.current->first + ");";
        }
        return true;
    }

    bool Uint64(uint64_t u) {
        auto& active = ActiveObject();
        if ( active.isArray ) {
            if (!active.arrayTyped) {
                SLOG_FROM(
                    LOG_VERY_VERBOSE,
                    "SimpleParsedJSON_Generator::Uint64",
                    "Array " << active.namespaceName << "::" << active.current->first << " is a Uint64.");

                active.current->second =
                    active.indent + "NewUI64ArrayField("
                    + active.current->first + ");";
                active.arrayTyped = true;
            }
        } else {
            SLOG_FROM(
                LOG_VERY_VERBOSE,
                "SimpleParsedJSON_Generator::Uint64",
                "Field " << active.namespaceName << "::" << active.current->first << " is a Uint64.");
            active.current->second =   active.indent + "NewUI64Field("
                                     + active.current->first + ");";
        }
        return true;
    }

    bool Bool(bool b) {
        auto& active = ActiveObject();
        if ( active.isArray ) {
            if (!active.arrayTyped) {
                SLOG_FROM(
                    LOG_VERY_VERBOSE,
                    "SimpleParsedJSON_Generator::Bool",
                    "Array " << active.namespaceName << "::" << active.current->first << " is a bool.");

                active.current->second =   active.indent + "NewBoolArrayField("
                                         + active.current->first + ");";
                active.arrayTyped = true;

            }
        } else {
            SLOG_FROM(
                LOG_VERY_VERBOSE,
                "SimpleParsedJSON_Generator::Bool",
                "Field " << active.namespaceName << "::" << active.current->first << " is a bool.");

            active.current->second =   active.indent + "NewBoolField("
                                     + active.current->first + ");";
        }
        return true;
    }

    virtual bool StartArray() {
        auto& active = ActiveObject();

        if ( !active.IgnoreField() ) {
            active.isArray = true;
            active.arrayTyped = false;

            SLOG_FROM(
                LOG_VERY_VERBOSE,
                "SimpleParsedJSON_Generator::StartArray",
                "Starting new array " << active.namespaceName << "::" << active.current->first);
        } else {
            SLOG_FROM(
                LOG_VERY_VERBOSE,
                "SimpleParsedJSON_Generator::StartArray",
                "Ignoring new array " << active.namespaceName << "::" << active.current->first);
        }

        return true;
    }

    virtual bool EndArray(rapidjson::SizeType elementCount) {
        auto& active = ActiveObject();

        if (!active.arrayTyped) {
            SLOG_FROM(
                LOG_VERBOSE,
                "SimpleParsedJSON_Generator::EndArray",
                "Array " << active.namespaceName << "::" << active.current->first <<
                " finished, was NOT typed successfuly");
        } else {
            SLOG_FROM(
                LOG_VERY_VERBOSE,
                "SimpleParsedJSON_Generator::EndArray",
                "Array " << active.namespaceName << "::" << active.current->first <<
                " finished, was typed successfuly");
        }

        active.isArray = false;
        active.arrayTyped = false;

        return true;
    }

    bool StartObject() {
        if (started) {
            if ( !IgnoreField() ) {
                if(childObject.get()) {
                    LOG_FROM(
                        LOG_VERY_VERBOSE,
                        "SimpleParsedJSON_Generator::StartObject",
                        "forwarding to existing child object...");
                    childObject->StartObject();
                } else {
                    string childNamespace = current->first + "_fields";
                    SLOG_FROM(
                        LOG_VERY_VERBOSE,
                        "SimpleParsedJSON_Generator::StartObject",
                        "Starting a new child object: " << childNamespace);

                    childObject.reset(new SimpleParsedJSON_Generator(childNamespace, indent + "    "));
                    childObject->StartObject();
                }
            } else {
                SLOG_FROM(
                    LOG_VERY_VERBOSE,
                    "SimpleParsedJSON_Generator::StartObject",
                    "Skipping non first item for array "
                    << namespaceName << "::" << current->first)
            }
        } else {
            LOG_FROM(
                LOG_VERY_VERBOSE,
                "SimpleParsedJSON_Generator::StartObject",
                "Starting initial object");
            started = true;
        }
        return true;
    }

    bool EndObject(rapidjson::SizeType memberCount) {
        if (childObject.get()) {
            if ( !IgnoreField() ) {
                if (childObject->childObject.get()) {
                    LOG_FROM(
                        LOG_VERY_VERBOSE,
                        "SimpleParsedJSON_Generator::EndObject",
                        "Forwarding to child object...");
                    childObject->EndObject(memberCount);
                } else if (!childObject->IgnoreField()) {
                    const string& objName = current->first;
                    string jsonName =  current->first + "_fields::JSON";

                    SLOG_FROM(
                        LOG_VERY_VERBOSE,
                        "SimpleParsedJSON_Generator::EndObject",
                        "Completed object " << jsonName);

                    stringstream buf;
                    buf << endl;
                    buf << childObject->GetCode("JSON");

                    if (isArray) {
                        buf << indent << "NewObjectArray(";
                    } else {
                        buf << indent << "NewEmbededObject(";
                    }
                    buf << objName << ", " << jsonName << ");";

                    current->second = buf.str();
                    childObject.reset(nullptr);

                    if (isArray) {
                        SLOG_FROM(
                            LOG_VERY_VERBOSE,
                            "SimpleParsedJSON_Generator::EndObject",
                            "Terminated array "
                            << namespaceName << "::" << current->first
                            << " having completed the first item");
                        arrayTyped = true;
                    }
                } else {
                    SLOG_FROM(
                        LOG_VERY_VERBOSE,
                        "SimpleParsedJSON_Generator::EndObject",
                        "Ignored end of child object, whilst processing" << current->first);
                }
            } else {
                SLOG_FROM(
                    LOG_VERY_VERBOSE,
                    "SimpleParsedJSON_Generator::EndObject",
                    "Skipping non first item for array "
                    << namespaceName << "::" << current->first)
            }
        } else if (started) {
            LOG_FROM(
                LOG_VERY_VERBOSE,
                "SimpleParsedJSON_Generator::EndObject",
                "Terminated the object itself");
            started = false;
        } else {
            SLOG_FROM(
                LOG_VERBOSE,
                "SimpleParsedJSON_Generator::EndObject",
                "End of non-existent object!");
        }
        return true;
    }

    bool Null() {
        throw "TODO!";
    }

    string GetCode(const std::string& jsonName) {
        stringstream result;
        stringstream fields;
        if ( namespaceName != "" ) {
            result << nsIndent << "namespace " << namespaceName << " {" << endl;
        }
        const auto first = keys.begin();
        const auto last = --(keys.end());
        for (Keys::iterator it = first; it != keys.end(); ++it) {
            result << it->second << endl;
            fields << indent << "    " << it->first
                   << (it == last ? "": ",")
                   << endl;
        }
        result << endl;
        result << indent << "typedef SimpleParsedJSON<" << endl;
        result << fields.str();
        result << indent << "> " << jsonName << ";" << endl;
        if ( namespaceName != "" ) {
            result << nsIndent << "}" << endl;
        }
        return result.str();
    }

private:
    bool started; // Indicates if we have found the start of the outer object yet
    bool isArray; // Indicates if the field currently being scanned is an array
    bool arrayTyped; // Indicates if we've already found the first item in the array

    unique_ptr<SimpleParsedJSON_Generator> childObject;
    typedef std::map<std::string,std::string> Keys;
    Keys keys;
    Keys::iterator current;
    std::string indent;
    std::string nsIndent;
    std::string namespaceName;
};

std::string spJSON::Gen(const string& className, const string& exampleJson) {
    SimpleParsedJSON_Generator gen;

    rapidjson::StringStream ss(exampleJson.c_str());
    rapidjson::Reader reader;

    reader.Parse(ss,gen);

    return gen.GetCode(className);
}
<|endoftext|>


<commit_before>/*
 * File:   SpriteNode.cpp
 * Author: iMer
 *
 * Created on 3. Juli 2014, 01:51
 */
#include <iostream>
#include <string.h>
#include "SpriteNode.hpp"
#include "ResourceManager.hpp"
#include "SFML/Graphics.hpp"
#include "Factory.hpp"
#include "Game.hpp"
#include "util/json.hpp"

namespace engine {

	Animation::Animation() : m_looping(false), m_speed(0), m_currentTime(0), m_currentFrame(0), OnOver([] {
	}) {

	}

	void Animation::SetLooping(bool looping) {
		m_looping = looping;
	}

	bool Animation::IsLooping() const {
		return m_looping;
	}

	std::vector<sf::IntRect>& Animation::GetFrames() {
		return m_frames;
	}

	void Animation::SetSpeed(float speed) {
		m_speed = speed;
	}

	float Animation::GetSpeed() const {
		return m_speed;
	}

	void Animation::Reset() {
		m_currentFrame = 0;
		m_currentTime = 0;
	}

	void Animation::AddFrame(const sf::IntRect& frame) {
		m_frames.push_back(frame);
	}

	void Animation::Update(float delta) {
		m_currentTime += delta;
		if (m_currentTime > m_speed) {

			m_currentFrame++;
			if (m_currentFrame >= m_frames.size()) {
				if (m_looping) {
					m_currentFrame = 0;
					m_currentTime = 0;
				} else {
					m_currentFrame--;
					OnOver();
				}
			} else {
				m_currentTime = 0;
			}
		}
	}

	const sf::IntRect& Animation::GetCurrentTexture() {
		return m_frames[m_currentFrame];
	}

	bool Animation::IsOver() {
		return m_currentTime > m_speed;
	}

	SpriteNode::SpriteNode(Scene* scene) : Node(scene), m_texture(0),
			m_currentAnimation("default"), m_animated(false), m_vFlipped(false) {
	}

	SpriteNode::~SpriteNode() {
		for (auto it = m_animations.begin(); it != m_animations.end();) {
			Animation* a = it->second;
			delete a;
			m_animations.erase(it++);
		}
	}

	void SpriteNode::OnDraw(sf::RenderTarget& target, sf::RenderStates states, float delta) {
		if (m_animated) {
			std::lock_guard<std::recursive_mutex> lg(m_mutex);
			auto it = m_animations.find(m_currentAnimation);
			if (it != m_animations.end()) {
				it->second->Update(delta);
				if (it->second->IsOver() && m_animationWhenDone != "") {
					PlayAnimation(m_animationWhenDone);
				} else {
					m_textureRect = it->second->GetCurrentTexture();
					UpdateTexCoords();
				}
			}
		}
		states.texture = m_texture;
		target.draw(m_vertices, 4, sf::TrianglesStrip, states);

	}

	void SpriteNode::UpdatePosition() {
		m_vertices[0].position = sf::Vector2f(0, 0);
		m_vertices[1].position = sf::Vector2f(0, m_size.y);
		m_vertices[2].position = sf::Vector2f(m_size.x, 0);
		m_vertices[3].position = sf::Vector2f(m_size.x, m_size.y);
	}

	void SpriteNode::UpdateTexCoords() {
		float left = static_cast<float> (m_textureRect.left);
		float right = left + m_textureRect.width;
		float top = static_cast<float> (m_textureRect.top);
		float bottom = top + m_textureRect.height;
		m_vertices[0].texCoords = sf::Vector2f(m_flipped?right:left , m_vFlipped?bottom:top   );
		m_vertices[1].texCoords = sf::Vector2f(m_flipped?right:left , m_vFlipped?top   :bottom);
		m_vertices[2].texCoords = sf::Vector2f(m_flipped?left :right, m_vFlipped?bottom:top   );
		m_vertices[3].texCoords = sf::Vector2f(m_flipped?left :right, m_vFlipped?top   :bottom);

	}

	void SpriteNode::SetTexture(std::string path, const sf::IntRect* rect) {
		sf::Texture* t = engine::ResourceManager::instance()->GetTexture(path);
		t->setRepeated(true);
		SetTexture(t, rect);
	}

	void SpriteNode::SetTexture(sf::Texture* texture, const sf::IntRect* rect) {
		m_texture = texture;
		if (rect) {
			m_textureRect.left = rect->left;
			m_textureRect.width = rect->width;
			m_textureRect.top = rect->top;
			m_textureRect.height = rect->height;
		} else {
			m_textureRect.left = 0;
			m_textureRect.width = m_texture->getSize().x;
			m_textureRect.top = 0;
			m_textureRect.height = m_texture->getSize().y;
		}
		if (!m_size.x && !m_size.y) {
			m_size.x = static_cast<float>(m_textureRect.width);
			m_size.y = static_cast<float>(m_textureRect.height);
		}
		UpdatePosition();
		UpdateTexCoords();
	}

	bool SpriteNode::initialize(Json::Value& root) {
		if (!Node::initialize(root)) {
			return false;
		}
		if (root.isMember("sprite")) {
			auto sprite = root["sprite"];
			if (sprite.isMember("texture")) {
				if (sprite.isMember("rect")) {
					sf::IntRect rect = rectFromJson<int>(sprite["rect"]);
					SetTexture(sprite["texture"].asString(), &rect);
				} else {
					SetTexture(sprite["texture"].asString());
				}
			} else if (sprite.isMember("sheet")) {
				Json::Value sheet;
				if (sprite["sheet"].isString() && !Factory::LoadJson(sprite["sheet"].asString(), sheet)) {
					std::cerr << "Loading spritesheet json failed." << std::endl;
				} else if (sprite["sheet"].isObject()) {
					sheet = sprite["sheet"];
				}
				if (!sheet.isNull() && !sheet.empty()) {
					auto tex = sheet["sprites"][sprite.get("index", 0).asInt()];
					if (tex.empty() || tex.isNull()) {
						std::cerr << "Empty/Nonexistant sprite index " << sprite.get("index", 0) << std::endl;
					} else {
						sf::IntRect rect = rectFromJson<int>(tex);
						SetTexture(sheet["texture"].asString(), &rect);
					}
					if (sprite["animations"].isObject()) {
						auto m = sprite["animations"].getMemberNames();
						for (size_t i = 0; i < m.size(); i++) {
							std::string aname = m[i];
							auto anim = sprite["animations"][aname];
							if (!anim["frames"].isArray()) {
								std::cerr << "Couldnt load animation, no frames" << std::endl;
								continue;
							}
							Animation* a = new Animation();
							a->SetSpeed(anim.get("speed", 1).asFloat());
							a->SetLooping(anim.get("loop", true).asBool());
							for (size_t o = 0; o < anim["frames"].size(); o++) {
								auto text = sheet["sprites"][anim["frames"][o].asInt()];
								if (text.isNull()) {
									std::cerr << "Frame " << o << "is invalid. Frame " << anim["frames"][o].asInt() << " doesnt exist." << std::endl;
									continue;
								}
								sf::IntRect rect = rectFromJson<int>(text);
								a->AddFrame(rect);
							}
							m_animations.insert(std::make_pair(aname, a));
							m_animated = true;
						}
					}
					if (sprite["animation"].isString()) {
						PlayAnimation(sprite["animation"].asString());
					}
				}
			}
		}
		return true;
	}

	uint8_t SpriteNode::GetType() const {
		return NT_SPRITE;
	}

	void SpriteNode::PlayAnimation(std::string name, std::string after) {
		std::lock_guard<std::recursive_mutex> lg(m_mutex);
		auto it = m_animations.find(name);
		if (it == m_animations.end()) {
			std::cerr << "Animation '" << name << "'could not be found";
			return;
		}
		m_animationWhenDone = after;
		it->second->Reset();
		m_currentAnimation = name;
	}

	Animation* SpriteNode::GetAnimation() {
		if (m_animations.find(m_currentAnimation) != m_animations.end()) {
			return m_animations[m_currentAnimation];
		} else {
			return nullptr;
		}
	}

	void SpriteNode::SetFlipped(bool flipped) {
		m_flipped = flipped;
		UpdateTexCoords();
	}
	void SpriteNode::SetVFlipped(bool flipped) {
		m_vFlipped = flipped;
		UpdateTexCoords();
	}
	void SpriteNode::SetSize(sf::Vector2f size) {
		Node::SetSize(size);
		UpdatePosition();
	}
}
<commit_msg>Add random texture option to sheet<commit_after>/*
 * File:   SpriteNode.cpp
 * Author: iMer
 *
 * Created on 3. Juli 2014, 01:51
 */
#include <iostream>
#include <string.h>
#include <Engine/util/Random.hpp>
#include "SpriteNode.hpp"
#include "ResourceManager.hpp"
#include "SFML/Graphics.hpp"
#include "Factory.hpp"
#include "Game.hpp"
#include "util/json.hpp"

namespace engine {

	Animation::Animation() : m_looping(false), m_speed(0), m_currentTime(0), m_currentFrame(0), OnOver([] {
	}) {

	}

	void Animation::SetLooping(bool looping) {
		m_looping = looping;
	}

	bool Animation::IsLooping() const {
		return m_looping;
	}

	std::vector<sf::IntRect>& Animation::GetFrames() {
		return m_frames;
	}

	void Animation::SetSpeed(float speed) {
		m_speed = speed;
	}

	float Animation::GetSpeed() const {
		return m_speed;
	}

	void Animation::Reset() {
		m_currentFrame = 0;
		m_currentTime = 0;
	}

	void Animation::AddFrame(const sf::IntRect& frame) {
		m_frames.push_back(frame);
	}

	void Animation::Update(float delta) {
		m_currentTime += delta;
		if (m_currentTime > m_speed) {

			m_currentFrame++;
			if (m_currentFrame >= m_frames.size()) {
				if (m_looping) {
					m_currentFrame = 0;
					m_currentTime = 0;
				} else {
					m_currentFrame--;
					OnOver();
				}
			} else {
				m_currentTime = 0;
			}
		}
	}

	const sf::IntRect& Animation::GetCurrentTexture() {
		return m_frames[m_currentFrame];
	}

	bool Animation::IsOver() {
		return m_currentTime > m_speed;
	}

	SpriteNode::SpriteNode(Scene* scene) : Node(scene), m_texture(0),
			m_currentAnimation("default"), m_animated(false), m_vFlipped(false) {
	}

	SpriteNode::~SpriteNode() {
		for (auto it = m_animations.begin(); it != m_animations.end();) {
			Animation* a = it->second;
			delete a;
			m_animations.erase(it++);
		}
	}

	void SpriteNode::OnDraw(sf::RenderTarget& target, sf::RenderStates states, float delta) {
		if (m_animated) {
			std::lock_guard<std::recursive_mutex> lg(m_mutex);
			auto it = m_animations.find(m_currentAnimation);
			if (it != m_animations.end()) {
				it->second->Update(delta);
				if (it->second->IsOver() && m_animationWhenDone != "") {
					PlayAnimation(m_animationWhenDone);
				} else {
					m_textureRect = it->second->GetCurrentTexture();
					UpdateTexCoords();
				}
			}
		}
		states.texture = m_texture;
		target.draw(m_vertices, 4, sf::TrianglesStrip, states);

	}

	void SpriteNode::UpdatePosition() {
		m_vertices[0].position = sf::Vector2f(0, 0);
		m_vertices[1].position = sf::Vector2f(0, m_size.y);
		m_vertices[2].position = sf::Vector2f(m_size.x, 0);
		m_vertices[3].position = sf::Vector2f(m_size.x, m_size.y);
	}

	void SpriteNode::UpdateTexCoords() {
		float left = static_cast<float> (m_textureRect.left);
		float right = left + m_textureRect.width;
		float top = static_cast<float> (m_textureRect.top);
		float bottom = top + m_textureRect.height;
		m_vertices[0].texCoords = sf::Vector2f(m_flipped?right:left , m_vFlipped?bottom:top   );
		m_vertices[1].texCoords = sf::Vector2f(m_flipped?right:left , m_vFlipped?top   :bottom);
		m_vertices[2].texCoords = sf::Vector2f(m_flipped?left :right, m_vFlipped?bottom:top   );
		m_vertices[3].texCoords = sf::Vector2f(m_flipped?left :right, m_vFlipped?top   :bottom);

	}

	void SpriteNode::SetTexture(std::string path, const sf::IntRect* rect) {
		sf::Texture* t = engine::ResourceManager::instance()->GetTexture(path);
		t->setRepeated(true);
		SetTexture(t, rect);
	}

	void SpriteNode::SetTexture(sf::Texture* texture, const sf::IntRect* rect) {
		m_texture = texture;
		if (rect) {
			m_textureRect.left = rect->left;
			m_textureRect.width = rect->width;
			m_textureRect.top = rect->top;
			m_textureRect.height = rect->height;
		} else {
			m_textureRect.left = 0;
			m_textureRect.width = m_texture->getSize().x;
			m_textureRect.top = 0;
			m_textureRect.height = m_texture->getSize().y;
		}
		if (!m_size.x && !m_size.y) {
			m_size.x = static_cast<float>(m_textureRect.width);
			m_size.y = static_cast<float>(m_textureRect.height);
		}
		UpdatePosition();
		UpdateTexCoords();
	}

	bool SpriteNode::initialize(Json::Value& root) {
		if (!Node::initialize(root)) {
			return false;
		}
		if (root.isMember("sprite")) {
			auto sprite = root["sprite"];
			if (sprite.isMember("texture")) {
				if (sprite.isMember("rect")) {
					sf::IntRect rect = rectFromJson<int>(sprite["rect"]);
					SetTexture(sprite["texture"].asString(), &rect);
				} else {
					SetTexture(sprite["texture"].asString());
				}
			} else if (sprite.isMember("sheet")) {
				Json::Value sheet;
				if (sprite["sheet"].isString() && !Factory::LoadJson(sprite["sheet"].asString(), sheet)) {
					std::cerr << "Loading spritesheet json failed." << std::endl;
				} else if (sprite["sheet"].isObject()) {
					sheet = sprite["sheet"];
				}
				if (!sheet.isNull() && !sheet.empty()) {
					int index = sprite.get("index", 0).asInt();
					if (sprite.get("randomIndex", false).asBool()) {
						util::RandomInt<int> r(0, sheet["sprites"].size() - 1);
						index = r();
					}
					auto tex = sheet["sprites"][index];
					if (tex.empty() || tex.isNull()) {
						std::cerr << "Empty/Nonexistant sprite index " << index << std::endl;
					} else {
						sf::IntRect rect = rectFromJson<int>(tex);
						SetTexture(sheet["texture"].asString(), &rect);
					}
					if (sprite["animations"].isObject()) {
						auto m = sprite["animations"].getMemberNames();
						for (size_t i = 0; i < m.size(); i++) {
							std::string aname = m[i];
							auto anim = sprite["animations"][aname];
							if (!anim["frames"].isArray()) {
								std::cerr << "Couldnt load animation, no frames" << std::endl;
								continue;
							}
							Animation* a = new Animation();
							a->SetSpeed(anim.get("speed", 1).asFloat());
							a->SetLooping(anim.get("loop", true).asBool());
							for (size_t o = 0; o < anim["frames"].size(); o++) {
								auto text = sheet["sprites"][anim["frames"][o].asInt()];
								if (text.isNull()) {
									std::cerr << "Frame " << o << "is invalid. Frame " << anim["frames"][o].asInt() << " doesnt exist." << std::endl;
									continue;
								}
								sf::IntRect rect = rectFromJson<int>(text);
								a->AddFrame(rect);
							}
							m_animations.insert(std::make_pair(aname, a));
							m_animated = true;
						}
					}
					if (sprite["animation"].isString()) {
						PlayAnimation(sprite["animation"].asString());
					}
				}
			}
		}
		return true;
	}

	uint8_t SpriteNode::GetType() const {
		return NT_SPRITE;
	}

	void SpriteNode::PlayAnimation(std::string name, std::string after) {
		std::lock_guard<std::recursive_mutex> lg(m_mutex);
		auto it = m_animations.find(name);
		if (it == m_animations.end()) {
			std::cerr << "Animation '" << name << "'could not be found";
			return;
		}
		m_animationWhenDone = after;
		it->second->Reset();
		m_currentAnimation = name;
	}

	Animation* SpriteNode::GetAnimation() {
		if (m_animations.find(m_currentAnimation) != m_animations.end()) {
			return m_animations[m_currentAnimation];
		} else {
			return nullptr;
		}
	}

	void SpriteNode::SetFlipped(bool flipped) {
		m_flipped = flipped;
		UpdateTexCoords();
	}
	void SpriteNode::SetVFlipped(bool flipped) {
		m_vFlipped = flipped;
		UpdateTexCoords();
	}
	void SpriteNode::SetSize(sf::Vector2f size) {
		Node::SetSize(size);
		UpdatePosition();
	}
}
<|endoftext|>


<commit_before>#include <iostream>
#include <memory>

#include <cstring>

#include <pthread.h>

#include "gestion-fichiers.hpp"
#include "semaphore.hpp"

constexpr size_t const TAILLEBUF = 2048;

struct ReadingThreadData {
	std::string filename;
	std::shared_ptr<char> data;
	std::shared_ptr<Semaphore> readingLock;
	std::shared_ptr<Semaphore> writingLock;
	Semaphore* ready;
};

void readAndStore(IFile& source, char* data) {
	char line[TAILLEBUF];
	source >> line;
	std::cout << "[Reading]: Line read." << std::endl;

	std::strncpy(data, line, TAILLEBUF);
}

void* readingThreadMain(void* voidThreadData) {
	std::cout << "[Reading]: Thread spawned." << std::endl;

	struct ReadingThreadData* threadData =
	  reinterpret_cast<struct ReadingThreadData*>(voidThreadData);

	std::shared_ptr<Semaphore> readingLock = threadData->readingLock;
	std::shared_ptr<Semaphore> writingLock = threadData->writingLock;
	std::shared_ptr<char> data             = threadData->data;

	IFile source(threadData->filename.c_str(), TAILLEBUF);

	std::cout << "[Reading]: Ready!" << std::endl;
	threadData->ready->post();

	while(!source.hasEnded()) {
		readingLock->wait();
		readAndStore(source, data.get());
		writingLock->post();
	}

	std::cout << "[Reading]: Sending End-of-Transmission" << std::endl;
	data.get()[0] = 0x04;
	writingLock->post();

	std::cout << "[Reading]: Goodbye!" << std::endl;
	pthread_exit(NULL);
}

struct TransmittingThreadData {
	std::string filename;
	std::shared_ptr<char> data;
	std::shared_ptr<Semaphore> readingLock;
	std::shared_ptr<Semaphore> writingLock;
	Semaphore* ready;
};

void getAndTransmit(OFile& destination, char* data) {
	destination << data;
}

void* transmittingThreadMain(void* voidThreadData) {
	std::cout << "[Transmission]: Thread spawned." << std::endl;

	struct TransmittingThreadData* threadData =
	  reinterpret_cast<struct TransmittingThreadData*>(voidThreadData);

	std::shared_ptr<Semaphore> readingLock = threadData->readingLock;
	std::shared_ptr<Semaphore> writingLock = threadData->writingLock;
	std::shared_ptr<char> data             = threadData->data;

	OFile destination(threadData->filename.c_str(), TAILLEBUF);

	std::cout << "[Transmission]: Ready!" << std::endl;
	threadData->ready->post();

	writingLock->wait();

	while(data.get()[0] != 0x04) {
		destination << data.get();
		readingLock->post();
		std::cout << "[Transmission]: Line transmitted." << std::endl;

		writingLock->wait();
	}
	std::cout << "[Transmission]: Received End-of-Transmission" << std::endl;

	std::cout << "[Transmission]: Goodbye!" << std::endl;
	pthread_exit(NULL);
}

int main(int argc, char* argv[]) {
	if(argc != 3) {
		std::cout << "Usage: " << argv[0] << " source destination" << std::endl;
		return EINVAL;
	}

	std::shared_ptr<Semaphore> readingLock(new Semaphore(1));
	std::shared_ptr<Semaphore> writingLock(new Semaphore(0));
	std::unique_ptr<Semaphore> readingReady(new Semaphore(0));
	std::unique_ptr<Semaphore> transmissionReady(new Semaphore(0));

	pthread_t transmittingThread, readingThread;

	std::shared_ptr<char> c(new char[TAILLEBUF], std::default_delete<char[]>());
	c.get()[0] = '\0';

	std::unique_ptr<struct TransmittingThreadData> transmittingThreadData(
	  new struct TransmittingThreadData);
	transmittingThreadData->filename    = argv[2];
	transmittingThreadData->data        = c;
	transmittingThreadData->readingLock = readingLock;
	transmittingThreadData->writingLock = writingLock;
	transmittingThreadData->ready       = readingReady.get();

	std::unique_ptr<struct ReadingThreadData> readingThreadData(new struct ReadingThreadData);
	readingThreadData->filename    = argv[1];
	readingThreadData->data        = std::move(c);
	readingThreadData->readingLock = readingLock;
	readingThreadData->writingLock = writingLock;
	readingThreadData->ready       = transmissionReady.get();

	pthread_create(&transmittingThread, NULL, transmittingThreadMain,
	               reinterpret_cast<void*>(transmittingThreadData.get()));
	pthread_create(&readingThread, NULL, readingThreadMain,
	               reinterpret_cast<void*>(readingThreadData.get()));

	pthread_detach(transmittingThread);
	pthread_detach(readingThread);

	std::cout << "[Main]: Waiting for Reading and Transmission to be Ready" << std::endl;
	readingReady->wait();
	transmissionReady->wait();

	std::cout << "[Main]: Goodbye!" << std::endl;
	pthread_exit(NULL);
}
<commit_msg>Using move some more in testIA of TD4<commit_after>#include <iostream>
#include <memory>

#include <cstring>

#include <pthread.h>

#include "gestion-fichiers.hpp"
#include "semaphore.hpp"

constexpr size_t const TAILLEBUF = 2048;

struct ReadingThreadData {
	std::string filename;
	std::shared_ptr<char> data;
	std::shared_ptr<Semaphore> readingLock;
	std::shared_ptr<Semaphore> writingLock;
	Semaphore* ready;
};

void readAndStore(IFile& source, char* data) {
	char line[TAILLEBUF];
	source >> line;
	std::cout << "[Reading]: Line read." << std::endl;

	std::strncpy(data, line, TAILLEBUF);
}

void* readingThreadMain(void* voidThreadData) {
	std::cout << "[Reading]: Thread spawned." << std::endl;

	struct ReadingThreadData* threadData =
	  reinterpret_cast<struct ReadingThreadData*>(voidThreadData);

	std::shared_ptr<Semaphore> readingLock = threadData->readingLock;
	std::shared_ptr<Semaphore> writingLock = threadData->writingLock;
	std::shared_ptr<char> data             = threadData->data;

	IFile source(threadData->filename.c_str(), TAILLEBUF);

	std::cout << "[Reading]: Ready!" << std::endl;
	threadData->ready->post();

	while(!source.hasEnded()) {
		readingLock->wait();
		readAndStore(source, data.get());
		writingLock->post();
	}

	std::cout << "[Reading]: Sending End-of-Transmission" << std::endl;
	data.get()[0] = 0x04;
	writingLock->post();

	std::cout << "[Reading]: Goodbye!" << std::endl;
	pthread_exit(NULL);
}

struct TransmittingThreadData {
	std::string filename;
	std::shared_ptr<char> data;
	std::shared_ptr<Semaphore> readingLock;
	std::shared_ptr<Semaphore> writingLock;
	Semaphore* ready;
};

void getAndTransmit(OFile& destination, char* data) {
	destination << data;
}

void* transmittingThreadMain(void* voidThreadData) {
	std::cout << "[Transmission]: Thread spawned." << std::endl;

	struct TransmittingThreadData* threadData =
	  reinterpret_cast<struct TransmittingThreadData*>(voidThreadData);

	std::shared_ptr<Semaphore> readingLock = threadData->readingLock;
	std::shared_ptr<Semaphore> writingLock = threadData->writingLock;
	std::shared_ptr<char> data             = threadData->data;

	OFile destination(threadData->filename.c_str(), TAILLEBUF);

	std::cout << "[Transmission]: Ready!" << std::endl;
	threadData->ready->post();

	writingLock->wait();

	while(data.get()[0] != 0x04) {
		destination << data.get();
		readingLock->post();
		std::cout << "[Transmission]: Line transmitted." << std::endl;

		writingLock->wait();
	}
	std::cout << "[Transmission]: Received End-of-Transmission" << std::endl;

	std::cout << "[Transmission]: Goodbye!" << std::endl;
	pthread_exit(NULL);
}

int main(int argc, char* argv[]) {
	if(argc != 3) {
		std::cout << "Usage: " << argv[0] << " source destination" << std::endl;
		return EINVAL;
	}

	std::shared_ptr<Semaphore> readingLock(new Semaphore(1));
	std::shared_ptr<Semaphore> writingLock(new Semaphore(0));
	std::unique_ptr<Semaphore> readingReady(new Semaphore(0));
	std::unique_ptr<Semaphore> transmissionReady(new Semaphore(0));

	pthread_t transmittingThread, readingThread;

	std::shared_ptr<char> c(new char[TAILLEBUF], std::default_delete<char[]>());
	c.get()[0] = '\0';

	std::unique_ptr<struct TransmittingThreadData> transmittingThreadData(
	  new struct TransmittingThreadData);
	transmittingThreadData->filename    = std::move(argv[2]);
	transmittingThreadData->data        = c;
	transmittingThreadData->readingLock = readingLock;
	transmittingThreadData->writingLock = writingLock;
	transmittingThreadData->ready       = readingReady.get();

	std::unique_ptr<struct ReadingThreadData> readingThreadData(new struct ReadingThreadData);
	readingThreadData->filename    = std::move(argv[1]);
	readingThreadData->data        = std::move(c);
	readingThreadData->readingLock = std::move(readingLock);
	readingThreadData->writingLock = std::move(writingLock);
	readingThreadData->ready       = transmissionReady.get();

	pthread_create(&transmittingThread, NULL, transmittingThreadMain,
	               reinterpret_cast<void*>(transmittingThreadData.get()));
	pthread_create(&readingThread, NULL, readingThreadMain,
	               reinterpret_cast<void*>(readingThreadData.get()));

	pthread_detach(transmittingThread);
	pthread_detach(readingThread);

	std::cout << "[Main]: Waiting for Reading and Transmission to be Ready" << std::endl;
	readingReady->wait();
	transmissionReady->wait();

	std::cout << "[Main]: Goodbye!" << std::endl;
	pthread_exit(NULL);
}
<|endoftext|>


<commit_before>#include <SFML/Graphics.hpp>
#include <SFML/OpenGL.hpp>

#include "Test3DView.hpp"
#include "Main.hpp"

Test3DView::Test3DView(){}

void Test3DView::draw(sf::RenderTarget*rt){
    static sf::Clock clock;

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glTranslatef(0.f, 0.f, -200.f);
    glRotatef(clock.getElapsedTime().asSeconds()*50, 1, 0, 0);
    glRotatef(clock.getElapsedTime().asSeconds()*30, 0, 1, 0);
    glRotatef(clock.getElapsedTime().asSeconds()*90, 0, 0, 1);

    glColor3f(0,0,1);
    glBegin(GL_QUADS);
    {
	glVertex3f(-50,-50,-50);
	glVertex3f(-50, 50,-50);
	glVertex3f( 50, 50,-50);
	glVertex3f( 50,-50,-50);

	glVertex3f(-50,-50, 50);
	glVertex3f(-50, 50, 50);
	glVertex3f( 50, 50, 50);
	glVertex3f( 50,-50, 50);

	glVertex3f(-50,-50,-50);
	glVertex3f(-50, 50,-50);
	glVertex3f(-50, 50, 50);
	glVertex3f(-50,-50, 50);

	glVertex3f( 50,-50,-50);
	glVertex3f( 50, 50,-50);
	glVertex3f( 50, 50, 50);
	glVertex3f( 50,-50, 50);

	glVertex3f(-50,-50, 50);
	glVertex3f(-50,-50,-50);
	glVertex3f( 50,-50,-50);
	glVertex3f( 50,-50, 50);

	glVertex3f(-50, 50, 50);
	glVertex3f(-50, 50,-50);
	glVertex3f( 50, 50,-50);
	glVertex3f( 50, 50, 50);
    }
    glEnd();
}

void Test3DView::pause(){}
void Test3DView::unpause(){}
<commit_msg>I tried adding colors and OpenGL is hard and I'm not doing as well as I thought<commit_after>#include <SFML/Graphics.hpp>
#include <SFML/OpenGL.hpp>

#include "Test3DView.hpp"
#include "Main.hpp"

Test3DView::Test3DView(){}

void Test3DView::draw(sf::RenderTarget*rt){
    static sf::Clock clock;

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glTranslatef(0.f, 0.f, -200.f);
    glRotatef(clock.getElapsedTime().asSeconds()*50, 1, 0, 0);
    glRotatef(clock.getElapsedTime().asSeconds()*30, 0, 1, 0);
    glRotatef(clock.getElapsedTime().asSeconds()*90, 0, 0, 1);

    glBegin(GL_QUADS);
    {
	float size = 50;

	glColor3f(0,0,1);
	glVertex3f(-size,-size,-size);
	glVertex3f(-size, size,-size);
	glVertex3f( size, size,-size);
	glVertex3f( size,-size,-size);

	glColor3f(0,1,0);
	glVertex3f(-size,-size, size);
	glVertex3f(-size, size, size);
	glVertex3f( size, size, size);
	glVertex3f( size,-size, size);

	glColor3f(0,1,1);
	glVertex3f(-size,-size,-size);
	glVertex3f(-size, size,-size);
	glVertex3f(-size, size, size);
	glVertex3f(-size,-size, size);

	glColor3f(1,0,0);
	glVertex3f( size,-size,-size);
	glVertex3f( size, size,-size);
	glVertex3f( size, size, size);
	glVertex3f( size,-size, size);

	glColor3f(1,0,1);
	glVertex3f(-size,-size, size);
	glVertex3f(-size,-size,-size);
	glVertex3f( size,-size,-size);
	glVertex3f( size,-size, size);

	glColor3f(1,1,0);
	glVertex3f(-size, size, size);
	glVertex3f(-size, size,-size);
	glVertex3f( size, size,-size);
	glVertex3f( size, size, size);
    }
    glEnd();
}

void Test3DView::pause(){}
void Test3DView::unpause(){}
<|endoftext|>