#include "roundrobin"

unsigned Roundrobin::target(struct in_addr clientip,
			    BackendVector &targetlist) {
    // Regardless of a pre-existent targetlist, we rebuild it here.
    // We do that to take weights into accounts. 
    static bool building;
    mutex_lock(&building);
    targetlist.reset();
    for (unsigned int i = 0; i < balancer.nbackends(); i++)
	for (unsigned int j = 0; j < balancer.backend(i).weight(); j++)
	    targetlist.add(i);
    mutex_unlock(&building);
    
    if (config.debug()) {
	ostringstream o;
	o << "Round robin target list: ";
	for (unsigned i = 0; i < targetlist.size(); i++)
	    o << targetlist[i] << ' ';
	o << '\n';
	debugmsg(o.str());
    }
    
    if (targetlist.size() == 1)
	return (targetlist[0]);
    
    static int prev_run_index = -1;

    unsigned first_try_val = 0;
    bool first_try_set = false;
    while (true) {
	// See where we will start
	unsigned cur_val;
	
	if (prev_run_index == -1) {
	    cur_val = 0;
	} else {
	    if (! first_try_set) {
		first_try_set = true;
		first_try_val = prev_run_index;
	    }
	    cur_val = prev_run_index + 1;
	    cur_val %= targetlist.size();
	    if (cur_val == first_try_val)
		throw Error("Round robin dispatcher: no backends\n");
	}
	
	// Store for next time 'round
	mutex_lock(&prev_run_index);
	prev_run_index = cur_val;
	mutex_unlock(&prev_run_index);

	if (! balancer.backend(targetlist[cur_val]).available())
	    continue;

	// Done.
	return (targetlist[cur_val]);
    }
}
