import java.util.ArrayList;
import java.util.Random;

public class CrossoverHW {

	public static ArrayList<ChromozomeHW> onePointCrossover(ChromozomeHW parent1, ChromozomeHW parent2, double mutationProbability, int mutateType){
		
		Random random = new Random();
		ArrayList<ChromozomeHW> offsprings = new ArrayList<ChromozomeHW>();
		char[] off1 = new char[parent1.getSize()];
		char[] off2 = new char[parent2.getSize()];
		int breakpoint = random.nextInt(parent1.getSize());
		double mutationchance = 0;
		
		for(int i=0;i<breakpoint;i++){
			off1[i]=parent2.getSingleGene(i);
			off2[i]=parent1.getSingleGene(i);
		}
		
		for(int j=breakpoint;j<parent1.getSize();j++){
			off1[j]=parent1.getSingleGene(j);
			off2[j]=parent2.getSingleGene(j);
		}
		
		ChromozomeHW offspring1 = new ChromozomeHW(off1, parent1.getSize());
		ChromozomeHW offspring2 = new ChromozomeHW(off2, parent2.getSize());
		
		mutationchance = random.nextDouble();
		if(mutationchance > 0 && mutationchance <= mutationProbability){
			
			switch(mutateType){
			
			case 1:
				offspring1 = randomMutation(offspring1);
				break;
			
			case 2:
				offspring1 = swapMutation(offspring1);
				break;
				
			default:
				offspring1 = randomMutation(offspring1);
			}
		}
		
		mutationchance = random.nextDouble();
		if(mutationchance > 0 && mutationchance <= mutationProbability){

			switch(mutateType){
			
			case 1:
				offspring2 = randomMutation(offspring2);
				break;
			
			case 2:
				offspring2 = swapMutation(offspring2);
				break;
				
			default:
				offspring2 = randomMutation(offspring2);
			}
		}
		
		offsprings.add(offspring1);
		offsprings.add(offspring2);
		
		
		return offsprings;
	}
	
	public static ArrayList<ChromozomeHW> twoPointCrossover(ChromozomeHW parent1, ChromozomeHW parent2, double mutationProbability, int mutateType){
		
		Random random = new Random();
		ArrayList<ChromozomeHW> offsprings = new ArrayList<ChromozomeHW>();
		char[] off1 = new char[parent1.getSize()];
		char[] off2 = new char[parent2.getSize()];
		double mutationchance = 0;
		
		int breakpoint1 = random.nextInt(parent1.getSize());
		int breakpoint2 = random.nextInt(parent2.getSize() - breakpoint1) + breakpoint1;
		
		for(int i=0; i<breakpoint1;i++){
			off1[i]=parent2.getSingleGene(i);
			off2[i]=parent1.getSingleGene(i);
		}
		
		for(int j=breakpoint1; j<breakpoint2;j++){
			off1[j]=parent1.getSingleGene(j);
			off2[j]=parent2.getSingleGene(j);
		}
		
		for(int k=breakpoint2; k<parent1.getSize();k++){
			off1[k]=parent2.getSingleGene(k);
			off2[k]=parent1.getSingleGene(k);
		}
		
		ChromozomeHW offspring1 = new ChromozomeHW(off1, parent1.getSize());
		ChromozomeHW offspring2 = new ChromozomeHW(off2, parent2.getSize());
		
		mutationchance = random.nextDouble();
		if(mutationchance > 0 && mutationchance <= mutationProbability){
			
			switch(mutateType){
			
			case 1:
				offspring1 = randomMutation(offspring1);
				break;
			
			case 2:
				offspring1 = swapMutation(offspring1);
				break;
				
			default:
				offspring1 = randomMutation(offspring1);
			}
		}
		
		mutationchance = random.nextDouble();
		if(mutationchance > 0 && mutationchance <= mutationProbability){

			switch(mutateType){
			
			case 1:
				offspring2 = randomMutation(offspring2);
				break;
			
			case 2:
				offspring2 = swapMutation(offspring2);
				break;
				
			default:
				offspring2 = randomMutation(offspring2);
			}
		}
		
		offsprings.add(offspring1);
		offsprings.add(offspring2);
		
		return offsprings;
	}
	
	public static ArrayList<ChromozomeHW> uniPointCrossover(ChromozomeHW parent1, ChromozomeHW parent2, double mutationProbability, int mutateType){
		
		Random random = new Random();
		ArrayList<ChromozomeHW> offsprings = new ArrayList<ChromozomeHW>();
		char[] off1 = new char[parent1.getSize()];
		char[] off2 = new char[parent2.getSize()];
		double mutationchance = 0;
		
		for(int i=0, j=1;i<parent1.getSize();i+=2,j+=2){
			if(i < parent1.getSize() && j <= parent1.getSize()){
				off1[i] = parent2.getSingleGene(i);
				off1[j] = parent1.getSingleGene(j);
				off2[i] = parent1.getSingleGene(i);
				off2[j] = parent2.getSingleGene(j);
				System.out.println("i=" + i);
				System.out.println("j=" + j);
				}
		}
		
		ChromozomeHW offspring1 = new ChromozomeHW(off1, parent1.getSize());
		ChromozomeHW offspring2 = new ChromozomeHW(off2, parent2.getSize());
		
		mutationchance = random.nextDouble();
		if(mutationchance > 0 && mutationchance <= mutationProbability){
			
			switch(mutateType){
			
			case 1:
				offspring1 = randomMutation(offspring1);
				break;
			
			case 2:
				offspring1 = swapMutation(offspring1);
				break;
				
			default:
				offspring1 = randomMutation(offspring1);
			}
		}
		
		mutationchance = random.nextDouble();
		if(mutationchance > 0 && mutationchance <= mutationProbability){

			switch(mutateType){
			
			case 1:
				offspring2 = randomMutation(offspring2);
				break;
			
			case 2:
				offspring2 = swapMutation(offspring2);
				break;
				
			default:
				offspring2 = randomMutation(offspring2);
			}
		}
		
		offsprings.add(offspring1);
		offsprings.add(offspring2);
		
		return offsprings;
	}
	
	private static ChromozomeHW swapMutation(ChromozomeHW mutate){
		
		Random random = new Random();
		char temp;
		
		int point1 = random.nextInt(mutate.getSize());
		int point2 = random.nextInt(mutate.getSize() - point1) + point1;
		
		temp = mutate.getSingleGene(point1);
		mutate.setSingleGene(point1, mutate.getSingleGene(point2));
		mutate.setSingleGene(point2, temp);
		
		return mutate;
	}
	
	private static ChromozomeHW randomMutation(ChromozomeHW mutate){
		
		Random random = new Random();
		int point = random.nextInt(mutate.getSize());
		char gene = (char) (random.nextInt(90) + 32);
		
		mutate.setSingleGene(point, gene);
		
		return mutate;
	}
	
}
