#include "infrastructure_client.h"
#include <assert.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>

infrastructure_client::infrastructure_client()
  : network_client()
{
  srand(time(NULL));
}

void 
infrastructure_client::message_handler(node_id sender, network_protocol::message_header *h, 
                                            char *msg, int len)
{
  if (DEBUG) 
    printf("DEBUG: (infrastructure message handler) Received from %u: %s\n", sender, msg);
  
  switch (h->type) {
  case network_protocol::join:
    //send back list of nodes in the system with some probability
    //need to marshall the list
    //add to list
    if (!known_node(h->source)) {
      peer_list.push_back(h->source);
      if (DEBUG)
        printf("DEBUG: (infrastructure message handler) new node: %u\n",h->source);
    }
    if (1){ //(peer_list.empty())||(rand() % 100 < 100*RESPOND_PROBABILITY)) {
      //respond
      if (DEBUG)
        printf("DEBUG: (infrastructure message handler) respond to join request\n");
      network_protocol::message_header hr;
      hr.source = client_id;
      hr.dest = h->source;
      hr.id = get_msg_id();
      hr.type = network_protocol::join_ack;
      hr.args = h->id;
      marshall m;
      m << peer_list;
      char list[(sizeof(unsigned int)+1)*peer_list.size()m.c_str();
      char buf[sizeof(network_protocol::message_header) + sizeof(list)];
      network_client::attach_header(&hr, list, sizeof(list), buf);
      network_client::basic_send(h->source, buf, sizeof(network_protocol::message_header));
    }
    break;
  case network_protocol::join_ack:
    //the signal to the waiting join call is in network_client
    unmarshall u(msg);
    if (peer_list.empty()){
      //int i;
      u >> peer_list;
      if (DEBUG)
        printf("DEBUG: (Infrastructure message handler) got peer list with %d peers\n", peer_list.size());
      
    }
  }
  network_client::message_handler(sender, h, msg, len);
}

//send a message to some number of other nodes dictated by hops
//for a wired infrastructure, we have a fixed number of "neighbors" -- send 
//the message to a random subset of MAX_NEIGHBORS * hops clients
// int 
// infrastructure_client::broadcast(int hops, char* message, int message_length) 
// {
//   if (peer_list.empty())
//     return network_protocol::NO_PEERS;

//   unsigned int num_clients = MAX_NEIGHBORS * hops;

//   //create a target list of clients to send our message to
//   std::vector<node_id> target_list = std::vector<node_id>(peer_list);
  
//   //use a Knuth random shuffle to pick a random subset
//   if(peer_list.size() > num_clients) {
//     for (unsigned int i = 0; i < num_clients; i++) {
//       int swap_target = rand() % (num_clients-i) + i;
//       node_id temp = target_list[i];
//       target_list[i] = target_list[swap_target];
//       target_list[swap_target] = temp;
//     }
//     target_list.resize(num_clients);
//   } else { //or just send it to everyone if appropriate
//     num_clients = peer_list.size();
//   }
  
//   //send message to peers
//   std::vector<node_id>::iterator i;
//   for(i = target_list.begin(); i != target_list.end(); i++) {
//     network_client::send(*i, message, message_length);
//   }
  
//   return 0;
// }
