// Thread per il protocollo di rielezione del master 

import java.net.*;
import java.io.IOException;
import java.util.Vector;

class MasterReelection extends Thread {
  private DatagramSocket soc;
  private Vector slaveLoadLst;   // lista con il carico degli slaves
    
  public MasterReelection() {
    super("MasterReelection");
    try { System.out.print("Init MasterReelection Thread ... ");
          soc=new DatagramSocket(ConstantsS.queryPort+3);
          slaveLoadLst=new Vector();
          System.out.println("fatto.");
            
    } catch(SocketException ex) {
   	    System.out.println("Slave$MasterReelection: "+ex.toString());
        System.exit(ConstantsS.queryPort+1);
   	  }
   	  catch(SecurityException ex) {
   	    System.out.println("Slave$MasterReelection: "+ex.toString());
   	    System.exit(ConstantsS.queryPort+1);
   	  }
  }
  
  // controlla se lo slave deve attivare il nuovo master
  private void chkLoad() {
    int minLoadPos=0;
    
    for (int i=1;i<slaveLoadLst.size();i++)
     { LoadLstElem cur=(LoadLstElem)slaveLoadLst.elementAt(i);
       LoadLstElem eletto=(LoadLstElem)slaveLoadLst.elementAt(minLoadPos);
       if (cur.load<eletto.load) minLoadPos=i;
     }	
    // controlla se lo slave e' l'eletto
    LoadLstElem eletto=(LoadLstElem)slaveLoadLst.elementAt(minLoadPos); 	
    if (eletto.slave.equals(ConstantsS.slaveIP+":"+String.valueOf(ConstantsS.queryPort+2)))
          { // essendo l'eletto, attiva il nuovo master
            System.out.println("Slave$MasterReelection.chkLoad: avvio InitMasterThread");
            (new InitMasterThread()).start();
          }
     else	System.out.println("Slave$MasterReelection.chkLoad: l'inizializzazione spetta a "+eletto.slave);
    // lo slave deve attendere l'attivazione del master
    ConstantsS.waitForNewMaster=true;  
  }	
      
  public void run() {
         
    while (true)
      try { byte[] inb=new byte[22];
            DatagramPacket inPac=new DatagramPacket(inb,inb.length);
            soc.receive(inPac);
            String msg=(new String(inPac.getData())).trim();
            System.out.println("Slave$MasterReelection: pacchetto da "+(inPac.getAddress()).getHostAddress()+":"+inPac.getPort()+", msg = "+msg);
            if (ConstantsS.waitForNewMaster)
                  { // si e' in attesa del msg da parte del nuovo master
                    // che indica la fine della rielezione.
                    if (msg.equals("nuovo master attivato"))
                     { ConstantsS.waitForNewMaster=false;
                       slaveLoadLst.clear();
                       // aggiorna l'indirizzo del nuovo master
                       ConstantsS.masterIP=(inPac.getAddress()).getHostAddress();
                       ConstantsS.masterPort=inPac.getPort();
                       ConstantsS.reelection=false;
                       System.out.println("Slave$MasterReelection: indirizzo nuovo master aggiornato");
                     }	
                  }
             else if (msg.equals("abort")) 
                          slaveLoadLst.clear(); // azzera la lista in caso di abort
                     else { LoadLstElem el=new LoadLstElem((inPac.getAddress()).getHostAddress(),inPac.getPort(),msg);
                            slaveLoadLst.addElement(el);
                            if ((ConstantsS.sv.getSlave()).length==slaveLoadLst.size())
                             { // tutti gli slaves hanno rilevato la
                               // morte del master.
                               chkLoad();
                             }	
                     	    }
      
      } catch(IOException ex) {
    	    System.out.println("Slave$MasterReelection: "+ex.toString());
    	  }
  }
  
  class LoadLstElem {
    public String slave; // slave_ip:porta
    public int load;     // carico dello slave
    
    public LoadLstElem(String sl_ip,int sl_port,String ld) {
      
      super();
      slave=sl_ip+":"+String.valueOf(sl_port);
      load=(new Integer(ld)).intValue();
    }
  } // fine LoadLstElem	  		
} // fine MasterReelection