package com.Series40Book;

import javax.microedition.lcdui.*;

import java.util.Enumeration;
import java.io.IOException;
import java.util.*;
import java.io.*;

import javax.bluetooth.*;

public class BTUtil {

  private static Form form;

  public BTUtil(Form form) {
    this.form = form;
  }


 /**
  * BTDisplayProperties
  *
  * Displays the current values of the known properties for the
  * LocalDevice.
  */
 public void BTDisplayLocalDeviceProperties(LocalDevice lDevice)
 {
   log ("");
   log ("--- properties ---");
  try {
    log("bt.api.version",lDevice.getProperty("bluetooth.api.version"));
  }
  catch (Exception ex) {
  }
   log ("bt.connected.inquiry.scan", lDevice.getProperty("bluetooth.connected.inquiry.scan"));
   log ("bt.connected.page.scan", lDevice.getProperty("bluetooth.connected.page.scan"));
   log ("bt.connected.inquiry", lDevice.getProperty("bluetooth.connected.inquiry"));
   log ("bt.connected.page",lDevice.getProperty("bluetooth.connected.page"));
   log ("bt.master.switch",lDevice.getProperty("bluetooth.master.switch"));
   log ("bt.connected.devices.max",lDevice.getProperty("bluetooth.connected.devices.max"));
   log ("bt.sd.attr.retrievable.max",lDevice.getProperty("bluetooth.sd.attr.retrievable.max"));
   log ("bt.l2cap.receiveMTU.max",lDevice.getProperty("bluetooth.l2cap.receiveMTU.max"));
   log ("bt.sd.trans.max",lDevice.getProperty("bluetooth.sd.trans.max"));
 }


 /**
   * BTDisplayLocalDevice
   *
   * Displays the Bluetooth specific details of the local decice. The connection to
   * the local device needs already be established.
   *
   * @param lDevice LocalDevice
   */
  public  void BTDisplayLocalDevice(LocalDevice lDevice)
  {
    log("Lcl DeviceAddress",lDevice.getBluetoothAddress());
    log("Lcl DeviceName", lDevice.getFriendlyName());
    log("Discover Mode", getDiscoverMode(lDevice.getDiscoverable()));

    DeviceClass devClass = lDevice.getDeviceClass();
    if ( devClass != null )
    {
      log("MajorDevice:", BTMajorDeviceName(devClass.getMajorDeviceClass()));
      log("MinorDevice:", BTMinorDeviceName(devClass.getMajorDeviceClass(),
                                            devClass.getMinorDeviceClass()));

      log("ServiceClass:","");
      String[] str = BTUtil.BTMajorServiceName(devClass.getServiceClasses());
      for (int i = 0; i < str.length; i++) {
        log(str[i]);
      }
    }
  }

  /**
   * getDiscoverMode
   *
   * Gets back a String which reflects the current discobery mode of the
   * LocalDevice.
   *
   * @param mode int
   * @return String
   */
  public String getDiscoverMode (int mode) {
    String result = "";

    switch (mode) {
      case DiscoveryAgent.NOT_DISCOVERABLE: result+= "Not discoverable "; break;
      //case DiscoveryAgent.CACHED: result += "Cached "; break;
      case DiscoveryAgent.GIAC: result += "GIAC "; break;
      case DiscoveryAgent.LIAC: result += "LIAC "; break;
      case DiscoveryAgent.PREKNOWN: result += "Preknown "; break;

     default:
         result += ("0x");
         result += Integer.toHexString(mode); break;
    }
    return result;
  }

  /**
   * BTDisplayRemoteDevice
   *
   * Displays details of a given RemoteDevice.
   *
   * @param dev RemoteDevice
   * @param devClass DeviceClass
   */
  public  void BTDisplayRemoteDevice( RemoteDevice dev, DeviceClass devClass )
  {
    cls();
    try
    {
    log("Remote Device",dev.getBluetoothAddress());
    log("Device Name",dev.getFriendlyName( false ) );
    log("AuthInfo",""+dev.isAuthenticated());
    log("Encrypted",""+dev.isEncrypted());
    log("Trusted",""+dev.isTrustedDevice() );

    if ( devClass != null )
    {
      log("MajorDevice", BTMajorDeviceName(devClass.getMajorDeviceClass()));
      log("MinorDevice", BTMinorDeviceName(devClass.getMajorDeviceClass(),
                                             devClass.getMinorDeviceClass()));

      log("ServiceClass:","");
      String[] str = BTUtil.BTMajorServiceName(devClass.getServiceClasses());
      for (int i = 0; i < str.length; i++) {
        log(str[i]);
      }
    }
    }catch (IOException e)
    {
      log ("Error displaying RemoteDevice detasils");
    }
  }


  /**
   * BTDisplayServiceRecord
   *
   * Displays the details in a given ServiceRecord.
   *
   * @param r ServiceRecord
   */
  public  void BTDisplayServiceRecord( ServiceRecord record )
  {
    int[] AttrIDs = record.getAttributeIDs();   // get all the AttributeIDs

    log("ServiceRecord Attributes",""+AttrIDs.length);
    log("ServiceRecord URL",record.getConnectionURL( ServiceRecord.NOAUTHENTICATE_NOENCRYPT, false ) );

    for ( int i=0; i < AttrIDs.length; i++ )
    {
      DataElement el = record.getAttributeValue( AttrIDs[i] );
      log ("DataElement Name", BTIDToName(AttrIDs[i]));
      BTDisplayDataElement( el, AttrIDs[i]);  // show mor details
    }
  }

  /**
   * BTDisplayDataElement
   *
   * Displays the readable details of a given DataElement in a single AttributeID.
   *
   * @param e DataElement
   * @param id int
   * @param indent String
   */
  public  void BTDisplayDataElement( DataElement e, int id)
  {
      int type = e.getDataType();

      if ( type == DataElement.DATALT ||
           type == DataElement.DATSEQ )
      {
        Enumeration enum = (Enumeration)e.getValue();
        log("DataElement", " " + type + " Elements: "+e.getSize());
        while ( enum.hasMoreElements() )
        {
          DataElement e2 = (DataElement)enum.nextElement();
          BTDisplayDataElement( e2, id);
        }
      }
      else if (type == DataElement.INT_1 ||
               type == DataElement.INT_2 ||
               type == DataElement.INT_4 ||
               type == DataElement.INT_8 ||
               type == DataElement.U_INT_1 ||
               type == DataElement.U_INT_2 ||
               type == DataElement.U_INT_4) {
        long v = e.getLong();
        log("DataElement",""+v);

      } else if ( type == DataElement.UUID )
      {
        UUID uuid = (UUID) e.getValue();
        log("DataElement", BTUUIDToName(uuid) );
      } else if ( type == DataElement.U_INT_8 ||
                  type == DataElement.U_INT_16 ||
                  type == DataElement.INT_16 )
      {
        byte[] v = (byte[]) e.getValue();
        String s = "";
        for ( int i=0; i< v.length; i++ )
        {
          s+= Integer.toHexString( (int) v[i] );
        }
        log("DataElement", s );
      } else if ( type == DataElement.STRING ||
                  type == DataElement.URL )
      {
        String v = (String) e.getValue();
        log("DataElement",v);
      } else if ( type == DataElement.BOOL )
      {
        boolean  v =  e.getBoolean();
        log("DataElement",String.valueOf( v));
      } else if ( type == DataElement.NULL )
      {
        log("DataElement", "--null--");
      }
  }

  /**
   * BTIDToName
   *
   * Gets back the readable name of a given AttributeID.
   *
   * @param id int
   * @return String
   */
  public static String BTIDToName( int id )
  {
    if ( id == 0x0000 )
    {
      return "ServiceRecordHandle";
    } else if ( id == 0x0001 )
    {
      return "ServiceClassIDList";

    } else if ( id == 0x0002 )
    {
      return "ServiceRecordState";
    } else if ( id == 0x0003 )
    {
      return "ServiceID";
    } else if ( id == 0x0004 )
    {
      return "ProtocolDescriptorList";
    } else if ( id == 0x0005 )
    {
      return "BrowseGroupList";
    } else if ( id == 0x0006 )
    {
      return "LanguageBasedAttributeIDList";
    } else if ( id == 0x0007 )
    {
      return "ServiceInfoTimeToLive";
    } else if ( id == 0x0008 )
    {
      return "ServiceAvailability";
    } else if ( id == 0x0009 )
    {
      return "BluetoothProfileDescriptorList";
    } else if ( id == 0x000A )
    {
      return "DocumentationURL";
    } else if ( id == 0x000B )
    {
      return "ClientExecutableURL";
    } else if ( id == 0x000C )
    {
      return "IconURL";
    } else
    {
      return "UnknownAttribute("+id+")";
    }
  }

  /**
   * BTUUIDToName
   *
   * Gets back the readable description of a UUID short value according to
   * the Bluetooth standard.
   *
   * @param uuidvalue UUID
   * @return String
   */
  public static String BTUUIDToName( UUID uuidvalue )
  {
    if ( uuidvalue.equals( new UUID( 0x0001 ) ))
      return "SDP";
    else if ( uuidvalue.equals( new UUID( 0x0003 ) ))
      return "RFCOMM";
    else if ( uuidvalue.equals( new UUID( 0x0008 ) ))
      return "OBEX";
    else if ( uuidvalue.equals( new UUID( 0x000C ) ))
      return "HTTP";
    else if ( uuidvalue.equals( new UUID( 0x0100 ) ))
      return "L2CAP";
    else if ( uuidvalue.equals( new UUID( 0x000F ) ))
      return "BNEP";
    else if ( uuidvalue.equals( new UUID( 0x1000 ) ))
      return "ServiceDiscoveryServerServiceClassID";
    else if ( uuidvalue.equals( new UUID( 0x1001 ) ))
      return "BrowseGroupDescriptorCerviceClassID";
    else if ( uuidvalue.equals( new UUID( 0x1002 ) ))
      return "PublicBrowseGroup";
    else if ( uuidvalue.equals( new UUID( 0x1101 ) ))
      return "SerialPort";
    else if ( uuidvalue.equals( new UUID( 0x1102 ) ))
      return "LANAccessUsingPPP";
    else if ( uuidvalue.equals( new UUID( 0x1103 ) ))
      return "DialupNetworking";
    else if ( uuidvalue.equals( new UUID( 0x1104 ) ))
      return "IrMCSync";
    else if ( uuidvalue.equals( new UUID( 0x1105 ) ))
      return "OBEX ObjectPush";
    else if ( uuidvalue.equals( new UUID( 0x1106 ) ))
      return "OBEX FileTransfer";
    else if ( uuidvalue.equals( new UUID( 0x1107 ) ))
      return "IrMCSyncCommand";
    else if ( uuidvalue.equals( new UUID( 0x1108 ) ))
      return "Headset";
    else if ( uuidvalue.equals( new UUID( 0x1109 ) ))
      return "CordlessTelephony";
    else if ( uuidvalue.equals( new UUID( 0x110A ) ))
      return "AudioSource";
    else if ( uuidvalue.equals( new UUID( 0x110B ) ))
      return "AudioSink";
    else if ( uuidvalue.equals( new UUID( 0x110C ) ))
      return "A/V RemoteControlTarget";
    else if ( uuidvalue.equals( new UUID( 0x1111 ) ))
      return "Fax";
    else if ( uuidvalue.equals( new UUID( 0x1112 ) ))
      return "HeadsetAudioGateway";
    else if ( uuidvalue.equals( new UUID( 0x1113 ) ))
      return "WAP";
    else if ( uuidvalue.equals( new UUID( 0x1115 ) ))
      return "PersonalAreaNetworking";
    else if ( uuidvalue.equals( new UUID( 0x1116 ) ))
      return "NetworkAccessPoint";
    else if ( uuidvalue.equals( new UUID( 0x1117 ) ))
      return "GroupNetwork";
    else if ( uuidvalue.equals( new UUID( 0x111E ) ))
      return "Handsfree";
    else if ( uuidvalue.equals( new UUID( 0x111F ) ))
      return "HandsfreeAudioGateway";
    else if ( uuidvalue.equals( new UUID( 0x1122 ) ))
      return "BasicPrinting";
    else if ( uuidvalue.equals( new UUID( 0x1123 ) ))
      return "PrintingStatus";
    else if ( uuidvalue.equals( new UUID( 0x1201 ) ))
      return "GenericNetworking";
    else if ( uuidvalue.equals( new UUID( 0x1202 ) ))
      return "GenericFileTransfer";
    else if ( uuidvalue.equals( new UUID( 0x1203 ) ))
      return "GenericAudio";
    else if ( uuidvalue.equals( new UUID( 0x1204 ) ))
      return "GenericTelephony";
    else
      return uuidvalue.toString();
  }

  /**
   * BTMajorDeviceName
   *
   * Returns the readable explanation of the given major device number.
   * @param device int
   * @return String
   */
  public static String BTMajorDeviceName( int device )
  {
    if ( device == 0x0000 )
      return "Miscellaneous";
    else if ( device == 0x0100)
      return "Computer";
    else if ( device == 0x0200 )
      return "Phone";
    else if ( device == 0x0300 )
      return "LAN";
    else if ( device == 0x0400 )
      return "Audio/Video";
    else if ( device == 0x0500 )
      return "Peripheral";
    else if ( device == 0x0600 )
      return "Imaging";
    else if ( device == 0x1F00 )
      return "Uncategorized";
    else
      return "UnknownMajorDevice: "+device;
  }

  /**
   * BTMinorDeviceName
   *
   * Returns a readable information based on the Major and Minor Device
   * class of a device according to the Bluetooth standard. A device can only
   * have one, single Major device class.
   *
   * @param major major device class
   * @param minor minor device class
   * @return
   */
  public static String BTMinorDeviceName( int major, int minor )
  {
    if ( major == 0x0000 )
      return "Miscellaneous";
    else if ( major == 0x0100 && minor == 0x00 )
      return "Uncategorized";
    else if ( major == 0x0100 && minor == 0x04 )
      return "Workstation";
    else if ( major == 0x0100 && minor == 0x08 )
      return "Server";
    else if ( major == 0x0100 && minor == 0x0C )
      return "Laptop";
    else if ( major == 0x0100 && minor == 0x10 )
      return "PDA";
    else if ( major == 0x0100 && minor == 0x14 )
      return "Palm";
    else if ( major == 0x0100 && minor == 0x18 )
      return "Wearable";

    else if ( major == 0x0200 && minor == 0x00 )
      return "Uncategorized";
    else if ( major == 0x0200 && minor == 0x04 )
      return "Cellular";
    else if ( major == 0x0200 && minor == 0x08 )
      return "Cordless";
    else if ( major == 0x0200 && minor == 0x0C )
      return "SmartPhone";
    else if ( major == 0x0200 && minor == 0x10 )
      return "Modem";
    else if ( major == 0x0200 && minor == 0x14 )
      return "ISDN";

    else if ( major == 0x0300 && minor == 0x00 )
      return "FullyAvailable";
    else if ( major == 0x0300 && minor == 0x20 )
      return "(1to17%)-Utilized";
    else if ( major == 0x0300 && minor == 0x40 )
      return "(17to33%)-Utilized";
    else if ( major == 0x0300 && minor == 0x60 )
      return "(33to50%)-Utilized";
    else if ( major == 0x0300 && minor == 0x80 )
      return "(50to67%)-Utilized";
    else if ( major == 0x0300 && minor == 0xA0 )
      return "(67to83%)-Utilized";
    else if ( major == 0x0300 && minor == 0xC0 )
      return "(83to100%)-Utilized";
    else if ( major == 0x0300 && minor == 0xE0 )
      return "NoServiceAvailable";

    else if ( major == 0x0400 && minor== 0x00 )
      return "Uncategorized";
    else if ( major == 0x0400 && minor == 0x04 )
      return "Headset";
    else if ( major == 0x0400 && minor == 0x08 )
      return "HandsFree";
    else if ( major == 0x0400 && minor == 0x0C )
      return "Reserved";
    else if ( major == 0x0400 && minor == 0x10 )
      return "Microphone";
    else if ( major == 0x0400 && minor == 0x14 )
      return "Speaker";
    else if ( major == 0x0400 && minor == 0x18 )
      return "Headphones";
    else if ( major == 0x0400 && minor == 0x1C )
      return "Portable/Audio";
    else if ( major == 0x0400 && minor == 0x20 )
      return "Car/Audio";
    else if ( major == 0x0400 && minor == 0x24 )
      return "SetTopBox";
    else if ( major == 0x0400 && minor == 0x28 )
      return "HiFiAudioDevice";
    else if ( major == 0x0400 && minor == 0x2C )
      return "VCR";
    else if ( major == 0x0400 && minor == 0x30 )
      return "VideoCamera";
    else if ( major == 0x0400 && minor == 0x34 )
      return "Camcorder";
    else if ( major == 0x0400 && minor == 0x38 )
      return "VideoMonitor";
    else if ( major == 0x0400 && minor == 0x3C )
      return "VideoDisplay&Speaker";
    else if ( major == 0x0400 && minor == 0x40 )
      return "VideoConferencing";
    else if ( major == 0x0400 && minor == 0x44 )
      return "Reserved";
    else if ( major == 0x0400 && minor == 0x48 )
      return "Gaming";

    else if ( major == 0x0500 && minor == 0x00)
      return "Uncategorized";
    else if ( major == 0x0500 && minor == 0x04)
      return "Joystick";
    else if ( major == 0x0500 && minor == 0x08)
      return "Gamepad";
    else if ( major == 0x0500 && minor == 0x0C)
      return "RemoteControl";
    else if ( major == 0x0500 && minor == 0x10)
      return "SensingDevice";
    else if ( major == 0x0500 && minor == 0x14)
      return "Digitizer/Tablet";
    else if ( major == 0x0500 && minor == 0x18)
      return "CardReader";
    else if ( major == 0x0500 && minor == 0x40)
      return "Keyboard";
    else if ( major == 0x0500 && minor == 0x80)
      return "PointingDevice";
    else if ( major == 0x0500 && minor == 0xC0)
      return "KeyboardPointingDevice";

    else if ( major == 0x0600 && minor == 0x10)
      return "Display";
    else if ( major == 0x0600 && minor == 0x20)
      return "Camera";
    else if ( major == 0x0600 && minor == 0x40)
      return "Scanner";
    else if ( major == 0x0600 && minor == 0x80)
      return "Printer";

    else if ( major == 0x1F00 )
      return "Uncategorized: "+minor;
    else
      return "UnknownMinorDevice: "+minor;

  }

  /**
   * BTMajorServiceName
   *
   * Passes back an String array depending on the value of the int parameter.
   * A Bluetooth device could support more than one major service class.
   *
   * @param d int
   * @return String[]
   */
  public static String[] BTMajorServiceName( int d )
  {
    // we use a vector here since we do not know the number of Major
    // Service classes we will end up with.
    Vector v = new Vector(3);     // 3 is closer to reality than the default (10)

    if ( (d & 0x2000) > 0 )
      v.addElement( "Limited discoverable" );
    if ( (d & 0x10000) > 0 )
      v.addElement( "Positioning" );
    if ( (d & 0x20000) > 0 )
      v.addElement( "Networking" );
    if ( (d & 0x40000) > 0 )
      v.addElement( "Rendering" );
    if ( (d & 0x80000) > 0 )
      v.addElement( "Capturing" );
    if ( (d & 0x100000) > 0 )
      v.addElement( "Object transfer" );
    if ( (d & 0x200000) > 0 )
      v.addElement( "Audio" );
    if ( (d & 0x400000) > 0 )
      v.addElement( "Telephony" );
    if ( (d & 0x800000) > 0 )
      v.addElement( "Information" );

    // copy back the Vector into a String array
    String[] str = new String[ v.size() ];
    v.copyInto( str );
    return str;

  }

  /**
   * cls
   *
   * Clear the whole form content.
   */
  public void cls() {

    int s = this.form.size();
    for (int i = 0; i < s; i++)  // delete line by line
      form.delete(0);

  }

  /**
   * log
   *
   * Display a message on the form and for debugging on the console
   * if needed. This version is using a StringItem, hence two
   * String parameters.
   *
   * @param label String
   * @param message String
   */
  public void log (String label, String message)
  {
    // System.out.println(message);   // for debugging if needed
    StringItem item = new StringItem(label,message);
    form.append(item);
  }

  /**
   * Display a message on the form and for debugging on the console
   * if needed.
   *

   * @param message String
   */
  public void log (String message)
  {
    // System.out.println(message);  // for debugging if needed
    StringItem item = new StringItem("",message);
    form.append(item);
  }


}
