package home.mb0198.progetto.servizi;

import java.net.*;
import java.io.*;
import home.mb0198.progetto.utility.*;
import home.mb0198.progetto.servizi.*;
import home.mb0198.progetto.messaggi.*;
/**
 * Classe che viene creata da un cliente e che mette a disposizione
 * un insieme di servizi svolti in maniera trasparente da un sistema
 * di server replicati.
 * 
 * @author Mauro Begatti
 */
public final class ServiziReplicati {
  private boolean esisteUaLocale=false;
  private InetAddress myaddr=null;
  /**
   * Costruisce l'oggetto che mette a disposizione del cliente un insieme
   * di servizi svolti in maniera trasparente da un sistema di server
   * replicati.
   * 
   */
  public ServiziReplicati() {
    try{ myaddr=InetAddress.getLocalHost();
         Thread tprobe=new Thread(new Probe());
         tprobe.start();
         tprobe.join();
         if(!esisteUaLocale){ Esci.print("ServiziReplicati- UserAgent non attivato su questo host.");}
    } catch (Exception e) { Esci.print("ServiziReplicati-"+e);}
  }
  /**
   * Classe privata usata da questo oggetto per verificare la presenza
   * di un UserAgent locale.
   * 
   */
  private class Probe implements Runnable {
    public void run() {
      try { DatagramSocket ds=new DatagramSocket(50000,myaddr);
      } catch (Exception e) { ServiziReplicati.this.esisteUaLocale=true; }
    }
  }
  /**
   * Inverte la stringa passata come parametro. Occorre specificare un timeout
   * sul tempo massimo di attesa.
   * 
   * @param s la stringa da invertire.
   * @param timeout il tempo massimo di attesa.
   * @return la stringa inversa.
   * @see java.lang.String
   */ 
  public synchronized String invertiStringa (String s,int timeout) {
    String out=null;
    DatagramSocket ds=null;
    Datagrammi d=new Datagrammi();
    
     try{    ds=new DatagramSocket();
         InetAddress dsaddr=ds.getLocalAddress();
         InvertiStringa is=new InvertiStringa();
         is.setInput(s);
         MsgClientRequest mr=new MsgClientRequest(is,ds.getLocalPort(),myaddr);
         DatagramPacket dpout=d.creaDatagramma(myaddr,50000,mr);
         int cont=0;
         boolean ricevuto=false;
         ds.setSoTimeout(timeout*1000);
         ds.send(dpout);
         do{ byte [] inBuffer=new byte[64000];
             DatagramPacket dpin=new DatagramPacket(inBuffer,inBuffer.length);
             ds.receive(dpin);
             System.out.println("ServiziReplicati invString() sbloccato");
             if(d.estraiMessaggio(dpin) instanceof MsgClientReply){
               ricevuto=true;
               MsgClientReply mrep=(MsgClientReply)d.estraiMessaggio(dpin);
               if(!(mrep.isFailed())){ 
                 InvertiStringa isris=(InvertiStringa)mrep.getServizio();
                 if (isris.isReply()) { out=isris.getOutput();}
               }
             }
             else {cont++;}
         } while ((!ricevuto)&&(cont<,5));
    }catch (Exception e) { 
          if(ds!=null){ds.close();}
          Esci.print("ServiziReplicati-invertiStringa()-"+e); }
    return out;
  }
  /**
    * Conta i caratteri della stringa passata come parametro. Occorre 
    * specificare un timeout sul tempo massimo di attesa.
    * 
    * @param s la stringa di cui  contare i caratteri.
    * @param timeout il tempo massimo di attesa.
    * @return il numero di caratteri della stringa passata come parametro.
    * @see java.lang.String
    */ 
  public synchronized int contaCaratteri (String s,int timeout) {
    int out=-1;
    DatagramSocket ds=null;
    try{ Datagrammi d=new Datagrammi();
         ds=new DatagramSocket();
         InetAddress dsaddr=ds.getLocalAddress();
         ContaCaratteri cc=new ContaCaratteri();
         cc.setInput(s);
         MsgClientRequest mr=new MsgClientRequest(cc,ds.getLocalPort(),myaddr);
         DatagramPacket dpout=d.creaDatagramma(myaddr,50000,mr);
         ds.send(dpout);
         int cont=0;
         boolean ricevuto=false;
         ds.setSoTimeout(timeout*1000);
         do{ byte [] inBuffer=new byte[64000];
             DatagramPacket dpin=new DatagramPacket(inBuffer,inBuffer.length);
             ds.receive(dpin);
             System.out.println("ServiziReplicati contaCaratteri() sbloccato");
             if(d.estraiMessaggio(dpin) instanceof MsgClientReply){
               ricevuto=true;
               MsgClientReply mrep=(MsgClientReply)d.estraiMessaggio(dpin);
               if(!(mrep.isFailed())){ 
                 ContaCaratteri ccris=(ContaCaratteri)mrep.getServizio();
                 if (ccris.isReply()) { out=ccris.getOutput();}
               }
             }
             else {cont++;}
         } while ((!ricevuto)&&(cont<5));
    }catch (InterruptedIOException io) { ds.close(); Esci.print("ServiziReplicati-contaCaratteri()-TIMEOUT"); }
     catch (Exception e) { 
        if(ds!=null) {ds.close();}
        Esci.print("ServiziReplicati-contaCaratteri()-"+e); }
     return out;
  }
  /**
    * Restituisce il valore di un contatore globale. Occorre 
    * specificare un timeout sul tempo massimo di attesa.
    * 
    * @param timeout il tempo massimo di attesa.
    * @return il valore del contatore globale.
    */
  public synchronized long contatoreCondiviso (int timeout) {
    long out=0;
    DatagramSocket ds=null;
    try{ Datagrammi d=new Datagrammi();
         ds=new DatagramSocket();
         InetAddress dsaddr=ds.getLocalAddress();
         ContatoreCondiviso ccond=new ContatoreCondiviso();
         MsgClientRequest mr=new MsgClientRequest(ccond,ds.getLocalPort(),dsaddr);
         DatagramPacket dpout=d.creaDatagramma(myaddr,50000,mr);
         ds.send(dpout);
         int cont=0;
         boolean ricevuto=false;
         ds.setSoTimeout(timeout*1000);
         do{ byte [] inBuffer=new byte[64000];
             DatagramPacket dpin=new DatagramPacket(inBuffer,inBuffer.length);
             ds.receive(dpin);
             System.out.println("ServiziReplicati contCondiviso() sbloccato");
             if(d.estraiMessaggio(dpin) instanceof MsgClientReply){
               ricevuto=true;
               MsgClientReply mrep=(MsgClientReply)d.estraiMessaggio(dpin);
               if(!(mrep.isFailed())){ 
                 ContatoreCondiviso ccondris=(ContatoreCondiviso)mrep.getServizio();
                 if (ccondris.isReply()) { out=ccondris.getOutput();}
               }
             }
             else {cont++;}
         } while ((!ricevuto)&&(cont<5));
    }catch (InterruptedIOException io) { ds.close(); Esci.print("ServiziReplicati-contatoreCondiviso()-TIMEOUT"); }
     catch (Exception e) { 
        if(ds!=null){ds.close();}
        Esci.print("ServiziReplicati-contatoreCondiviso()-"+e); }
    return out;
  } 
}