content: package com.almalence.sony.cameraremote;
  
  import java.io.IOException;
  import java.util.ArrayList;
  import java.util.Collections;
  import java.util.List;
  
  import android.util.Log;
  
  import com.almalence.sony.cameraremote.utils.SimpleHttpClient;
  import com.almalence.sony.cameraremote.utils.XmlElement;
  
  /**
   * A server device description class.
   */
  public final class ServerDevice {
  
      private static final String TAG = ServerDevice.class.getSimpleName();
  
      /**
       * Camera Remote API service (category). For example, "camera", "guide" and
       * so on. "Action List URL" is API request target URL of each service.
       */
      public static class ApiService {
          private String mName;
  
          private String mActionListUrl;
  
          /**
           * Constructor
           * 
           * @param name category name
           * @param actionListUrl action list URL of the category
           */
          public ApiService(String name, String actionListUrl) {
              mName = name;
              mActionListUrl = actionListUrl;
          }
  
          /**
           * Returns the category name.
           * 
           * @return category name.
           */
          public String getName() {
              return mName;
          }
  
          /**
           * Sets a category name.
           * 
           * @param name category name
           */
          public void setName(String name) {
              this.mName = name;
          }
  
          /**
           * Returns the action list URL of the category.
           * 
           * @return action list URL
           */
          public String getActionListUrl() {
              return mActionListUrl;
          }
  
          /**
           * Sets an action list URL of the category.
           * 
           * @param actionListUrl action list URL of the category
           */
          public void setActionListUrl(String actionListUrl) {
              this.mActionListUrl = actionListUrl;
          }
  
          /**
           * Returns the endpoint URL of the category.
           * 
           * @return endpoint URL
           */
          public String getEndpointUrl() {
              String url = null;
              if (mActionListUrl == null || mName == null) {
                  url = null;
              } else if (mActionListUrl.endsWith("/")) {
                  url = mActionListUrl + mName;
              } else {
                  url = mActionListUrl + "/" + mName;
              }
              return url;
          }
      }
  
      private String mDDUrl;
  
      private String mFriendlyName;
  
      private String mModelName;
  
      private String mUDN;
  
      private String mIconUrl;
  
      private final List<ApiService> mApiServices;
  
      private ServerDevice() {
          mApiServices = new ArrayList<ServerDevice.ApiService>();
      }
  
      /**
       * Returns URL of Device Description XML
       * 
       * @return URL string
       */
      public String getDDUrl() {
          return mDDUrl;
      }
  
      /**
       * Returns a value of friendlyName in DD.
       * 
       * @return friendlyName
       */
      public String getFriendlyName() {
          return mFriendlyName;
      }
  
      /**
       * Returns a value of modelName in DD.
       *
       * @return modelName
       */
      public String getModelName() {
          return mModelName;
      }
  
      /**
       * Returns a value of UDN in DD.
       * 
       * @return UDN
       */
      public String getUDN() {
          return mUDN;
      }
  
      /**
       * Returns URL of icon in DD.
       * 
       * @return URL of icon
       */
      public String getIconUrl() {
          return mIconUrl;
      }
  
      /**
       * Returns IP address of the DD.
       * 
       * @return IP address
       */
      public String getIpAddres() {
          String ip = null;
          if (mDDUrl != null) {
              return toHost(mDDUrl);
          }
          return ip;
      }
  
      /**
       * Returns a list of categories that the server supports.
       * 
       * @return a list of categories
       */
      public List<ApiService> getApiServices() {
          return Collections.unmodifiableList(mApiServices);
      }
  
      /**
       * Checks to see whether the server supports the category.
       * 
       * @param serviceName category name
       * @return true if it's supported.
       */
      public boolean hasApiService(String serviceName) {
          if (serviceName == null) {
              return false;
          }
          for (ApiService apiService : mApiServices) {
              if (serviceName.equals(apiService.getName())) {
                  return true;
              }
          }
          return false;
      }
  
      /**
       * Returns a ApiService object.
       * 
       * @param serviceName category name
       * @return ApiService object
       */
      public ApiService getApiService(String serviceName) {
          if (serviceName == null) {
              return null;
          }
          for (ApiService apiService : mApiServices) {
              if (serviceName.equals(apiService.getName())) {
                  return apiService;
              }
          }
          return null;
      }
  
      /**
       * Adds a ApiService object.
       * 
       * @param name
       * @param actionUrl
       */
      private void addApiService(String name, String actionUrl) {
          ApiService service = new ApiService(name, actionUrl);
          mApiServices.add(service);
      }
  
      /**
       * Fetches device description xml file from server and parses it.
       * 
       * @param ddUrl URL of device description xml.
       * @return ServerDevice instance
       */
      public static ServerDevice fetch(String ddUrl) {
          if (ddUrl == null) {
              throw new NullPointerException("ddUrl is null.");
          }
  
          String ddXml = "";
          try {
              ddXml = SimpleHttpClient.httpGet(ddUrl);
              Log.d(TAG, "fetch () httpGet done.");
          } catch (IOException e) {
              Log.e(TAG, "fetch: IOException.", e);
              return null;
          }
  
          XmlElement rootElement = XmlElement.parse(ddXml);
  
          // "root"
          ServerDevice device = null;
          if ("root".equals(rootElement.getTagName())) {
              device = new ServerDevice();
              device.mDDUrl = ddUrl;
  
              // "device"
              XmlElement deviceElement = rootElement.findChild("device");
              device.mFriendlyName = deviceElement.findChild("friendlyName").getValue();
              device.mModelName = deviceElement.findChild("modelName").getValue();
              device.mUDN = deviceElement.findChild("UDN").getValue();
  
              // "iconList"
              XmlElement iconListElement = deviceElement.findChild("iconList");
              List<XmlElement> iconElements = iconListElement.findChildren("icon");
              for (XmlElement iconElement : iconElements) {
                  // Choose png icon to show Android UI.
                  if ("image/png".equals(iconElement.findChild("mimetype").getValue())) {
                      String uri = iconElement.findChild("url").getValue();
                      String hostUrl = toSchemeAndHost(ddUrl);
                      device.mIconUrl = hostUrl + uri;
                  }
              }
  
              // "av:X_ScalarWebAPI_DeviceInfo"
              XmlElement wApiElement = deviceElement.findChild("X_ScalarWebAPI_DeviceInfo");
              XmlElement wApiServiceListElement = wApiElement.findChild("X_ScalarWebAPI_ServiceList");
              List<XmlElement> wApiServiceElements = wApiServiceListElement
                      .findChildren("X_ScalarWebAPI_Service");
              for (XmlElement wApiServiceElement : wApiServiceElements) {
                  String serviceName = wApiServiceElement.findChild("X_ScalarWebAPI_ServiceType")
                          .getValue();
                  String actionUrl = wApiServiceElement.findChild("X_ScalarWebAPI_ActionList_URL")
                          .getValue();
                  device.addApiService(serviceName, actionUrl);
              }
          }
          Log.d(TAG, "fetch () parsing XML done.");
          return device;
      }
  
      private static String toSchemeAndHost(String url) {
          int i = url.indexOf("://"); // http:// or https://
          if (i == -1) {
              return "";
          }
  
          int j = url.indexOf("/", i + 3);
          if (j == -1) {
              return "";
          }
  
          String hostUrl = url.substring(0, j);
          return hostUrl;
      }
  
      private static String toHost(String url) {
          int i = url.indexOf("://"); // http:// or https://
          if (i == -1) {
              return "";
          }
  
          int j = url.indexOf(":", i + 3);
          if (j == -1) {
              return "";
          }
  
          String host = url.substring(i + 3, j);
          return host;
      }
  }
  