import java.util.*;
 
/************************************************************************ 
 * Voters are the foundation of our model.  Each Voter has a utility function, 
 * used to determine the candidate that best matches their ideological  
 * viewpoints.  Voters also adapt their tag to match the candidate they  
 * choose. 
 ************************************************************************/ 
public class Voter extends Individual { 
    public double ambition;      // the Voter's ambition to run for office 
    public Candidate myCandidate;      // the Candidate's choice for Congress 
    public boolean isCandidate = false; 
    public boolean inCongress = false; 
    public boolean isCoalition = false; 
    public double laziness = -1; 
 
    // Voters are created with random vectors and a random ambition 
    public Voter(int policies, int positions, int tagLength, int center, 
		 int numberOfBills, String name) { 
	ideology = Utilities.vectorRand(policies, positions, center); 
	strengths = Utilities.vectorRand(policies); 
	votingRecord = new int[numberOfBills]; 
	partyTag = Utilities.vectorRand(tagLength, 2); 
	this.name = name; 
	ambition = Utilities.rand.nextDouble(); 
    } 
 
    // Computes the euclidean distance from a voter to a Candidate.
    // Since the further away they are, the less utility they give to a
    // voter, this distance is negative.
    public double findUtility(Candidate tempCand) { 
	double Utility = 0; 
	int[] tempIdeo = new int[ideology.length]; 
 
	System.arraycopy(tempCand.ideology, 0, tempIdeo, 0, ideology.length); 
	 
	for (int i=0; i<ideology.length; i++) 
	    Utility -= Math.pow((ideology[i] - tempIdeo[i]),2) * strengths[i]; 
 
  	return Utility; 
    } 
 
    // Same as above except for ideologies
    public double findUtility(int[] tempIdeo) { 
	double Utility = 0; 
	for (int i=0; i<ideology.length; i++) 
	    Utility -= Math.pow((ideology[i] - tempIdeo[i]),2) * strengths[i]; 
  	return Utility; 
    } 
 
    // Voters determine the utility of a Candidate depending on the similarity 
    // of their voting records and the weights applied to each issue, or the 
    // tag of the Candidate. 
    public int vote(Vector CandidatePool, boolean election) { 
	int bestCandidate = 0; 
	int bestTag = 0; 
        Vector Pool = CandidatePool; 
	 
	// Choose whether to be lazy or not based on random number 
	if (Utilities.rand.nextDouble() > Utilities.Sigmoid(laziness)) { 
 
	    // Find the first candidate's utility
	    Candidate firstCand = (Candidate)Pool.elementAt(0);
	    double bestUtility = findUtility(firstCand);

	    // elementAt(0) known to be incumbent if incumbent exists 
	    // Factor in the relative gain or loss of congress' actions
	    // and determine incumbent's responsibility for the change
	    if (firstCand.incumbent) {
		double lastTime = findSeparation(parent.Government.statusQuo);
		double today = findSeparation(parent.Government.newPolicy);
		double reagan = lastTime - today;
		double weight = firstCand.majority * reagan;
		bestUtility += weight;
	    }

	    // Compare with utility of all other candidates,
	    // choosing the candidate with the best utility
	    for (int i=1; i<Pool.size(); i++) { 
		double tempUtility = findUtility((Candidate)Pool.elementAt(i));
		if (tempUtility > bestUtility) { 
		    bestUtility = tempUtility; 
		    bestCandidate = i; 
		} 
	    } 
 
	    // Find the closest candidate based on tags 
	    Candidate tempCand = (Candidate)Pool.elementAt(0);
	    double bestTagSim = findSimilarity(tempCand.partyTag); 
	    for (int i=1; i<Pool.size(); i++) { 
		tempCand = (Candidate)Pool.elementAt(i);
		double tempTagSim = findSimilarity(tempCand.partyTag); 
		if (tempTagSim > bestTagSim) { 
		    bestTagSim = tempTagSim; 
		    bestTag = i; 
		} 
	    } 
 
	    // If the results were the same for both,  
	    // bump up the chances of being lazy 
	    if (election) 
		if (bestTag == bestCandidate) 
		    laziness += .1; 
		else 
		    laziness -= .1; 
	} 
 
	// When lazy, just compare tags. 
	else {
	    Candidate tempCand = (Candidate)Pool.elementAt(0);
	    double bestTagSim = findSimilarity(tempCand.partyTag); 
	    for (int i=1; i<Pool.size(); i++) { 
		tempCand = (Candidate)Pool.elementAt(i);
		double tempTagSim = findSimilarity(tempCand.partyTag); 
		if (tempTagSim > bestTagSim) { 
		    bestTagSim = tempTagSim; 
		    bestCandidate = i; 
		} 
	    } 
	} 
	 
	// assign their candidate selection
	myCandidate = (Candidate)Pool.elementAt(bestCandidate); 
 
	// adapt tag to match the candidate's tag 
	if (election) 
	    if (!isCandidate) 
		tagAdapt(); 
 
	return bestCandidate; 
    } 
     
    // Here, voters adapt their own tag to agree more closely with the 
    // candidate they chose in the election process 
    public void tagAdapt() { 
	double agreement = findSimilarity(myCandidate.partyTag); 
	if (agreement != 1) { 
	    for (int i=0; i<(partyTag.length/5); i++) { 
		int bitChange = Math.abs(Utilities.rand.nextInt()  
					 % partyTag.length); 
		 
		if (partyTag[bitChange] != myCandidate.partyTag[bitChange]) 
		    partyTag[bitChange] = myCandidate.partyTag[bitChange]; 
	    } 
	} 
    } 
} 

