#include <iostream>
#include "mayer_primes.h"
#include <vector>
#include <algorithm>
#include "timing.h"
using namespace std;

unsigned int single_goldbach(unsigned int k)
{
    unsigned int decomp = 0;
    unsigned int p,q;
    vector<unsigned int> primes = get_primes(k);
    for(unsigned i=0; i< primes.size(); i++)
    {
        p = primes.at(i);
        if(p > k/2)
        {
            break;
        }
        
        q = k-p;
        vector<unsigned int>::iterator it = lower_bound(primes.begin(), primes.end(), q);
        if (it != primes.end() && *it == q)
        {
            decomp++;
        }

    }

    return decomp;
}

//one can call single_goldbach but this way it is faster cause you dont have to regenerate primes and search in list
vector<unsigned int> count_goldbach(unsigned int n)
{
     vector<unsigned int> counts(n+1,0); 
     unsigned int p,q;
     vector<unsigned int> primes = get_primes(n);
     for(unsigned int j=0; j<primes.size(); j++)
     {
         for(unsigned i=j; i< primes.size(); i++) //start a j elsewise double counting of pairs
        {
           p = primes.at(j);
           q = primes.at(i);

           if(p+q > n)
           {
            continue;
           }
           counts[p+q] += 1;

        }
     }
     return counts;
}

vector<vector<vector<unsigned int>>> count_goldbach_all(unsigned int n)
{
     vector<vector<vector<unsigned int>>> counts(n+1,{{0,0}}); 
     unsigned int p,q;
     vector<unsigned int> primes = get_primes(n);
     for(unsigned int j=0; j<primes.size(); j++)
     {
         for(unsigned i=j; i< primes.size(); i++)
        {
           p = primes.at(j);
           q = primes.at(i);

           if(p+q > n)
           {
            continue;
           }
           if (counts[p+q].at(0).at(0) == 0) //first pair found
           {
            counts[p+q]={{p,q}};
           }
           else{
            counts[p+q].push_back({p,q});
           }

        }
     }
     return counts;
}

int main()
{   

    //2
    cout << single_goldbach(694) << endl;

    //3
    vector<unsigned int> counts = count_goldbach(100000);
    cout << (max_element(counts.begin(), counts.end()) - counts.begin()) << endl; 

    //4
    vector<unsigned int> nvalues = {10000, 100000, 400000, 1000000, 2000000, 10000000};
    double time;
    unsigned int n;
    for(unsigned int i = 0; i< nvalues.size(); i++)
    {
        n = nvalues.at(i);
        tic();
        count_goldbach(n);
        time = toc();
        cout << "Time for n=" << n << ": " << time << endl;
    }
    /*Time for n=10000: 0.0006853
    Time for n=100000: 0.0371858
    Time for n=400000: 0.505129
    Time for n=1000000: 2.85873
    Time for n=2000000: 15.0026
    Time for n=10000000: 549.658*/


    //*)
    unsigned int n2 = 694;
    vector<vector<vector<unsigned int>>> counts2 = count_goldbach_all(n2);
    for(unsigned int i=4; i<n2; i+=2)
    {
        cout << "Decomp for " << i << ":"<<endl;
        for(unsigned int j=0; j<counts2.at(i).size(); j++)
        {
            //cout << counts2.at(i).at(j).at(0) << "+" << counts2.at(i).at(j).at(1) << "=" << i << endl;
        }
    }


    return 0;
}