/*
 * YOUR INFO HERE!
 */

// FINAL VERSION:

struct Seive_Array{
    bool *is_composite;
    int size;
};

struct Primes{
    int *primes;
    int count, max;
};

void extend_sieve(Primes ps, Seive_Array seive, int start){
    int q,p,j,n,m;
    for (q = 1; q < ps.count; ++q){
        p = ps.primes[q];
        j = start;
        n = 2*j + 3;
        m = (n/p)*p;
        if (n != m){
            n = m+p;
            if (n % 2 == 0){
                n += p;
            }
            j = (n-3)/2;
        }
        
        for (; j < seive.size; j += p){
            seive.is_composite[j] = 1;
        }
    }
}

int seive_partial(Primes *ps_, Seive_Array seive, int start){
    Primes ps = *ps_;
    int i=start,n,j;
    for (; i < seive.size; ++i){
        if (!seive.is_composite[i]){
            n = i*2 + 3;
            ps.primes[ps.count++] = n;
            if (ps.count == ps.max){
                break;
            }
            for (j = i + n; j < seive.size; j += n){
                seive.is_composite[j] = 1;
            }
        }
    }
    ps_->count = ps.count;
    return i;
}

// TODO(allen): This is for an incrementally extended seive
struct Seive{
    Seive_Array seive;
    Primes ps;
    int i;
    int w;
};

// size of primes >= which_prime
// size of seive >= size > 0
Seive begin_seive(int *primes, int which_prime, bool *seive, int size){
    Seive result;
    
    result.seive.size = size;
    result.seive.is_composite = seive;
    
    result.ps.primes = primes;
    result.ps.count = 1;
    result.ps.max = which_prime;
    primes[0] = 2;
    
    result.i = 0;
    result.w = which_prime;
    
    return result;
}

inline bool seive_step(Seive *s){
    s->i = seive_partial(&s->ps, s->seive, s->i);
    return (s->ps.count != s->w);
}

inline void seive_grow(Seive *s, Seive_Array new_seive){
    extend_seive(s->ps, new_seive, s->seive.size);
    s->seive = new_seive;
}

inline int seive_init_size(int which_prime){
    return which_prime*5;
}

inline int seive_new_size(Seive s){
    return s.seive.size + s.w * (1 + ((s.w - s.ps.count) / 1000));
}

#ifdef EULER_PROBLEM
// BUILDING AREA:
struct Euler_In{};

struct Euler_Result{
    int prime;
};

static const int WHICH_PRIME = 10001;

Euler_Result euler_main(Euler_In in){
    char *chunk = (char*)malloc(1024*1024);
    
    int primes_[WHICH_PRIME];
    int size_ = seive_init_size(WHICH_PRIME);
    bool *seive_ = (bool*)chunk;
    memset(seive_, 0, size_);
    
    Seive s;
    s = begin_seive(primes_, WHICH_PRIME, seive_, size_);
    
    while (seive_step(&s)){
        Seive_Array new_seive;
        new_seive.size = seive_new_size(s);
        new_seive.is_composite = (bool*)chunk;
        memset(chunk + s.seive.size, 0, new_seive.size - s.seive.size);
        
        // free s.seive.is_composite, do not touch s.seive.size
        seive_grow(&s, new_seive);
    }
    
    free(chunk);
    
    Euler_Result result;
    result.prime = s.ps.primes[WHICH_PRIME - 1];
    
    return result;
}

void euler_print(Euler_Result answer, Euler_In in){
    printf("%d\n", answer.prime);
}

#if 0
#define EULER_CHECK

bool euler_check(Euler_Result answer, Euler_In in){
    bool result = 1;
    
    return result;
}
#endif

#endif
