/**
 *
 * <p>Titulo: Servidor de respuestas a preguntas</p>
 * <p>Descripcion: Este codigo administra las busquedas de dispositivos y servicios de preguntas.
 * </p>
 * @author Diego Gonzalez Barrientos
 * @version 1.0
 */
import java.util.*;
import javax.bluetooth.*;
import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;
/**La clase administrador permite gestionar la busqueda de dispositivos y servicios de preguntas
*/
public class AdministradorBluetooth  implements CommandListener
{


  /**
   * Creae a new AdministradorBluetooth.
   * @param host MIDlet
   * @param listener CommandListener
   */
  public AdministradorBluetooth(MIDlet host, CommandListener listener)
  {
    this.host = host;
    this.callback = listener;
    instance = this;
  }

  /**
   * Espejo de MIDlet.startApp(), deberia ser llamada por MIDlet startApp().
   */
  public void startApp() {
    display = Display.getDisplay(host);
    remotedeviceui = new DispositivoRemotoUI();
    remotedeviceui.showui();
	 remoteserviceui = new ServicioRemotoUI();
	 remotealternativeui = new AlternativaRemotaUI();
  }
  
  /**
   * Espejo de MIDlet.startApp(), deberia ser llamada por MIDlet startApp().
   */
  public void pauseApp()
  {
    // do nothing
  }

  /**
   * Espejo de MIDlet.startApp(), deberia ser llamada por MIDlet startApp().
   */
  public void destroyApp(boolean unconditional)
  {
  }

  /**Metodo que retorna el objeto que muestra la lista de alternativas para la pregunta
  *@return retorna remotealternativeui
  */
  public AlternativaRemotaUI getRemoteAlternativeUI(){
     return remotealternativeui;
  }

  /**
   * Funcion que imprime mensaje de debugeo.
   * @param s String
   */
  public static void log(String s)
  {
    System.out.println(s);
  }

  /**
   * Obtiene referencia a la componente de seleccion de dispositivos por pantalla.
   * Deberias mostrar esta pantalla cuando el usuario invoca la busqueda de dispositivos.
   * @return Screen
   */
  public Screen getUI()
  {
    return remotedeviceui;
  }
    /**
   * Obtiene referencia a la componente de seleccion de servicios por pantalla.
   * Deberias mostrar esta pantalla cuando el usuario invoca la busqueda de servicios.
   * @return Screen
   */
  public Screen getServiceUI(){
    return remoteserviceui;
  }
    /**
   * Muestra la componente de seleccion de servicios por pantalla.
   * @return Screen
   */
  public void showUI(){
  	remoteserviceui.showui();
  }
  /**
   * Obtiene todos los servicios descubiertos por el dispositivo remoto.
   * @return ServiceRecord[]
   */
  public ServiceRecord[] getDiscoveredServices()
  {
    ServiceRecord[] r = new ServiceRecord[ services.size() ];
    services.copyInto( r );
    return r;
  }

  /**
   * Obtiene el servicio descubierto.
   * @return ServiceRecord null if no service discovered
   */
  public ServiceRecord getSelectedService()
  {
    if ( services.size() > 0 )
      return (ServiceRecord) services.elementAt(selectedService);
    else
      return null;
  }
  /**Obtiene la alternativa seleccionada
  *@return retorna la alternativa seleccionada
  */
  public int getSelectedAlternative() {
     return selectedAlternative;
  }

  /**
   * Retorna el codigo de Bluetooth de resultado desde el dispositivo encontrado
   * @return int
   */
  public int getDeviceDiscoveryReturnCode()
  {
    return deviceReturnCode;
  }


  /**
   * Retorna el codigo de Bluetooth de resultado desde el servicio encontrado
   * @return int
   */  
  public int getServiceDiscoveryReturnCode()
  {
    return serviceReturnCode;
  }
  

  /**
   * Retorna el dispositivo remoto seleccionado por el usuario.
   * @return RemoteDevice nulo si no seleccionaste nada.
   */
  public RemoteDevice getSelectedDevice()
  {
    if ( selectedDevice != -1 )
      return (RemoteDevice) devices.elementAt(selectedDevice);
    else
      return null;
  }

  /**
   * Inicia la busqueda de dispositivos.
   * @param mode int DiscoveryAgent.GIAC o DiscoveryAgent.LIAC
   * @param serviceUUIDs UUID[]
   */
  public void startInquiry( int mode, UUID[] serviceUUIDs )
  {
    try
    {
      this.discoveryMode = mode;
      this.serviceUUIDs = serviceUUIDs;
      devices.removeAllElements();
      deviceClasses.removeAllElements();
      device = LocalDevice.getLocalDevice(); // obtain reference to singleton
      device.setDiscoverable(DiscoveryAgent.GIAC); // set Discover Mode
      agent = device.getDiscoveryAgent(); // obtain reference to singleton
      boolean result = agent.startInquiry( mode, new Listener() );
      remotedeviceui.setMsg("[Por favor espere...]");
    } catch ( BluetoothStateException e )
    {
      e.printStackTrace();
    }
  }

  /**
   *Manejador de eventos
   * @param c Command
   * @param d Displayable
   */
  public void commandAction(Command c, Displayable d)
  {
    if ( d == remotedeviceui && c.getLabel().equals("Buscar") )
    {
      startInquiry( discoveryMode, serviceUUIDs );
    } 
	 else if ( d == remotedeviceui && c.getLabel().equals("Salir") )
    {
      callback.commandAction( BACK, remotedeviceui);
    }
	 else if ( d == remotedeviceui && c.getLabel().equals("Seleccionar") )
    {
      selectedDevice = remotedeviceui.getSelectedIndex();
      RemoteDevice remoteDevice = (RemoteDevice) devices.elementAt( selectedDevice );
      services.removeAllElements();
      int[] attrSet;
		attrSet = new int[2];
      attrSet[0] = 0x4444;
		attrSet[1] = 0x4321;
      try
      {
        agent.searchServices(attrSet,
                             new UUID[]{serviceUUIDs[0]},
                             remoteDevice,
                             new Listener() );
        display.callSerially(new Worker(ID_DEVICE_SELECTED));
      } catch (BluetoothStateException ex)
      {
        ex.printStackTrace();
      }
    }

	 else if (d == remotealternativeui && c.getLabel().equals("Seleccionar")) {
		   selectedAlternative = remotealternativeui.getSelectedIndex();	 
	      display.callSerially( new Worker( ID_ALTERNATIVE_SELECTED));	   	
	 }
	 else if (d == remotealternativeui && c.getLabel().equals("Volver")) {
      callback.commandAction( BACK, remotedeviceui);
	 }
	 else if (d == remotealternativeui && c.getLabel().equals("Salir")) {
			SPP_MIDlet.quitApp();
	 }
    else if ( d == remoteserviceui && c.getLabel().equals("Seleccionar") )
    {
		selectedService = remoteserviceui.getSelectedIndex();
		display.callSerially( new Worker( ID_SERVICE_SELECTED));
    } else if ( d == remoteserviceui && c.getLabel().equals("Salir") )
    {
			SPP_MIDlet.quitApp();
    }
	   else if ( d == remoteserviceui && c.getLabel().equals("Volver") )
    {
      callback.commandAction( BACK, remotedeviceui);
    } else if ( d == remoteserviceui && c.getLabel().equals("Salir") )
    {
			SPP_MIDlet.quitApp();
    }
  }
  // Commands used in callback to idenfity AdministradorBluetooth events.
  // COMPLETED - When both device and service discovery are completed.
  public static Command COMPLETED =  new Command( "COMPLETED", Command.SCREEN, 1 );
  // SELECTED - When user has selected a Bluetooth device for service search
  public static Command SELECTED =  new Command( "SELECTED", Command.SCREEN, 1 );
  public static Command SELECTEDSERVICE =  new Command( "SELECTEDSERVICE", Command.SCREEN, 1 );
  public static Command SELECTEDALTERNATIVE =  new Command( "SELECTEDSERVICE", Command.SCREEN, 1 );
  // BACK - When user press Back button on Bluetooth Devices screen (DispositivoRemotoUI)
  public static Command BACK = new Command( "Back", Command.BACK, 1 );
  // your MIDlet reference
  public static MIDlet host;
  // your callback CommandListener
  public static CommandListener callback;
  // self instance of AdministradorBluetoothUI
  public static AdministradorBluetooth instance;
  // reference to GUI display
  public static Display display;

  public static Vector devices = new Vector();
  public static Vector deviceClasses = new Vector();
  public static Vector services = new Vector();
  /**Dispositivo seleccionado
  */
  public static int selectedDevice = -1;
  /**Servicio seleccionado
  */
  public static int selectedService = -1;
  /**Alternativa seleccionada
  */
  public static int selectedAlternative = -1;
/**Identificador de servicio de preguntas
*/
   public final static UUID uuid = new UUID("102030405060708090A0B0C0D0E0F012", false);
/** Modo de decubrimiento en busqueda de dispositivo
*/
  public int discoveryMode;
  /**Lista de servicios encontrados que corresponden con el UUID
  */
  public UUID[] serviceUUIDs = null;
/**Codigo de retorno de la busqueda de dispositivos
*/
  public int deviceReturnCode;
  // Bluetooth return code from service discovery operation
  // see DiscoveryListener
  public int serviceReturnCode;
  private DispositivoRemotoUI remotedeviceui = null;
  private ServicioRemotoUI remoteserviceui = null;
  private AlternativaRemotaUI remotealternativeui = null;
  private LocalDevice device;
  private DiscoveryAgent agent;

  /**
   * Bluetooth listener object.
   * Register this listener object to DiscoveryAgent in device inqury and service discovery.
   */
  class Listener implements DiscoveryListener
  {
/**Metodo que se invoca una vez se ha encontrado dispositivos
*/
    public void deviceDiscovered(RemoteDevice remoteDevice,
                                 DeviceClass deviceClass)
    {
      log("Se ha descubierto un dispositivo remoto:");
      devices.addElement( remoteDevice );
      deviceClasses.addElement( deviceClass );
    }
/**Metodo que se invoca una vez se ha finalizado la busqueda de dispositivos
*/
    public void inquiryCompleted(int complete)
    {
      log("El dispositivo descubierto se ha completado con codigo de retorno:"+complete);
      log(""+devices.size()+"dispositivos se han descubierto");
      deviceReturnCode = complete;
      if ( devices.size() == 0 )
      {
        Alert alert = new Alert( "Bluetooth", "No se ha encontrado dispositivo Bluetooth", null, AlertType.INFO );
        alert.setTimeout(3000);
        remotedeviceui.showui();
        display.setCurrent( alert, remotedeviceui );
      } else
      {
        remotedeviceui.showui();
        display.setCurrent( remotedeviceui );
      }
    }
/**Metodo que efectua acciones una vez se han descubierto servicios 
*/
    public void servicesDiscovered(int transId, ServiceRecord[] records)
    {
      log("Se ha descubierto servicios remotos Bluetooth:");
      for ( int i=0; i< records.length;  i ++ )
      {
        ServiceRecord record = records[i];
        services.addElement( record );
      }
    }
    /**Metodo que efectua acciones una vez la busqueda se ha completado
	 */
    public void serviceSearchCompleted(int transId, int complete)
    {
      log("Se ha completado la busqueda de servicios con codigo:"+complete);
      log(""+services.size()+" servicios se han descubierto");
      serviceReturnCode = complete;
      display.callSerially( new Worker( ID_SERVICE_COMPLETED ) );
    }
  }

  private final static int ID_SERVICE_COMPLETED = 1;
  private final static int ID_DEVICE_COMPLETED = 2;
  private final static int ID_DEVICE_SELECTED = 3;
  private final static int ID_SERVICE_SELECTED = 4;
  private final static int ID_ALTERNATIVE_SELECTED = 5;
  /**
   * Clase Worker que invoca callback CommandListener cuando ocurren eventos Bluetooth.
   */
  class Worker implements Runnable
  {
    int cmd = 0;

    public Worker( int cmd )
    {
      this.cmd = cmd;
    }
    public void run()
    {
      switch (cmd) {
        case ID_SERVICE_COMPLETED:
          callback.commandAction( COMPLETED, remotedeviceui);

          break;
        case ID_DEVICE_COMPLETED:
          callback.commandAction( COMPLETED, remotedeviceui);

          break;
        case ID_DEVICE_SELECTED:
          callback.commandAction( SELECTED, remotedeviceui);

          break;
		  case ID_SERVICE_SELECTED:
          callback.commandAction( SELECTEDSERVICE, remoteserviceui);

          break;
		  case ID_ALTERNATIVE_SELECTED:
          callback.commandAction( SELECTEDALTERNATIVE, remoteserviceui);

          break;
	 
        default:
          break;

      }
    }
  }

}
