package hussam.math;
import java.util.*;
interface PrimeGenerator{
	/*This should return to us the list of prime numbers
	 *at least up to the (limit)
	 */
	public List<Integer>getPrimeList(int limit);
	public boolean isPrime(int number);
	/*This should return the list of prime dividers for a given number.
	 *for example, the dividers for 180 is (2*2*3*3*5)
	 */
	public List<Integer> getDividers(int number);
	public int getIndexOf(int prime);
	public int getPrimeAtIndex(int index);
}

class HussamPrimeMachine implements PrimeGenerator{
	List<Integer>primes;
	public HussamPrimeMachine(){
		this(2);
	}
	public HussamPrimeMachine(int initLimit){
		primes=new Vector<Integer>();
		setup();
		increasePrimeListLimit(initLimit);
	}
	private void setup(){
		if(primes.size()==0){
			primes.add(2);
			primes.add(3);
		}
	}
	public List<Integer>getPrimeList(int limit){
		increasePrimeListLimit(limit);
		return getCurrentPrimeList();
	}
	public List<Integer> getCurrentPrimeList(){
		return new Vector<Integer>(primes);
	}
	public boolean isPrime(int x){
		return !isDivider(x);
	}
	public List<Integer> getDividers(int x){
		List<Integer>l=new Vector<Integer>();
		int root=(int)Math.sqrt(x)+1;
		prepareList(x);
		int reminder=x;
		for(int p:primes){ 
			while(reminder%p==0&root>p){
				l.add(p);
				reminder/=p;
			}
		}
		if(reminder!=1)l.add(reminder);
		return l;
	}
	public int getIndexOf(int prime){
		isPrime((int)Math.pow(prime, 2));
		return primes.indexOf(prime);
	}
	public int getPrimeAtIndex(int index){
		increasePrimeListSize(index+1);
		return primes.get(index);
	}
	protected void prepareList(int x){
		int root=(int)Math.sqrt(x+1);
		int biggestPrime=primes.get(primes.size()-1);
		if(biggestPrime<root){
			increasePrimeListLimit(root);
		}
	}
	public boolean isDivider(int x){
		int root=(int)Math.sqrt(x)+1;
		prepareList(x);
		for(int currentPrime:primes){
			if(currentPrime>root)return false;
			if(x%currentPrime==0)return true;
		}
		return false;
	}
	protected void increasePrimeListLimit(int limit){
		int start=primes.get(primes.size()-1);
		for (int i = start+2; i<limit; i+=2) {
			if(!isDivider(i)){
				primes.add(i);
			}
	    }
	}
	protected void increasePrimeListSize(int size){
		int start=primes.get(primes.size()-1);
		while(primes.size()<size){
			start+=2;
			if(!isDivider(start)){
				primes.add(start);
			}
	    }
	}
	public static void main(String[]args){
		PrimeGenerator m=new HussamPrimeMachine(10);
		System.out.println ("Prime at index: "+m.getPrimeAtIndex(400));
		System.out.println ("dividers: "+m.getDividers(170));
		System.out.println ("is prime: "+m.isPrime(157));
		System.out.println ("prime list: "+m.getPrimeList(1000));
	}

}