
/*---------------------------------------------------------------------------
 * Copyright (C) 1999,2000 Dallas Semiconductor Corporation, All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY,  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL DALLAS SEMICONDUCTOR BE LIABLE FOR ANY CLAIM, DAMAGES
 * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 *
 * Except as contained in this notice, the name of Dallas Semiconductor
 * shall not be used except as stated in the Dallas Semiconductor
 * Branding Policy.
 *---------------------------------------------------------------------------
 */

// OneWireAccessProvider.java 
package com.dalsemi.onewire;

// imports
import java.util.Vector;
import java.util.Enumeration;
import com.dalsemi.onewire.adapter.*;
import java.io.*;
import java.util.Properties;


/**
 * The OneWireAccessProvider class chiefly manages the Dallas Semiconductor
 * adapter class derivatives of DSPortAdapter.  An enumeration of all
 * available adapters will be accessed through the
 * member function EnumerateAllAdapters.  By writing software which cycles
 * through this enumeration instead of using specific adapter classes,
 * developers can provide code which will automatically use new adapters which
 * have not yet been invented. <p>
 *
 * @version    0.00, 30 August 2000
 * @author     DS
 */
public class OneWireAccessProvider
{

   /**
    * Smart default port
    */
   private static String smartDefaultPort = "COM1";

   /**
    * Don't allow anyone to instantiate.
    */
   private OneWireAccessProvider ()
   {
   }

   /**
    * EnumerateAllAdapters returns an <code>Enumeration</code> of all software
    * port adapters.  Programmers who wish to look for iButtons on all available
    * ports should cycle through all the DSPortAdapter objects returned
    * by this method.
    *
    * @return  <code>Enumeration</code> of all adapters in the system.
    */
   public static Enumeration enumerateAllAdapters ()
   {
      Vector        adapter_vector = new Vector(3, 1);
      DSPortAdapter adapter_instance;
      Class         adapter_class;

      // only try native TMEX if on x86 Windows platform
      if ((System.getProperty("os.arch").indexOf("86") != -1)
              && (System.getProperty("os.name").indexOf("Windows") != -1))
      {

         // loop through the TMEX adapters
         for (int port_type = 0; port_type <= 15; port_type++)
         {

            // try to load the adapter classes
            try
            {
               adapter_instance =
                  ( DSPortAdapter ) (new com.dalsemi.onewire.adapter.TMEXAdapter(
                     port_type));

               // only add it if it has some ports 
               if (adapter_instance.getPortNames().hasMoreElements())
                  adapter_vector.addElement(adapter_instance);
            }
            catch (Exception e){}
         }
      }

      // get the pure java adapter
      try
      {
         adapter_class    =
            Class.forName("com.dalsemi.onewire.adapter.USerialAdapter");
         adapter_instance = ( DSPortAdapter ) adapter_class.newInstance();

         // check if has any ports (common javax.comm problem)
         if (!adapter_instance.getPortNames().hasMoreElements())
         {
            System.err.println(
               "javax.comm not setup properly, no ports in enumeration ");
            System.err.println(
               "javax.comm pure-Java DS9097U adapter will not work, not added to adapter enum");
         }
         else
            adapter_vector.addElement(adapter_instance);
      }
      catch (java.lang.NoClassDefFoundError e)
      {
         System.err.println(
            "Could not load javax.comm for pure-Java DS9097U adapter: " + e);
      }
      catch (Exception e){}

      if (adapter_vector.isEmpty())
         System.err.println("No 1-Wire adapter classes found");

      return (adapter_vector.elements());
   }

   /**
    * Attempts to find, open, and verify the specified adapter on the
    * indicated port.
    *
    * @param adapterName, string name of the adapter (match to result
    *             of call to getAdapterName() method in DSPortAdapter)
    * @param portName, string name of the port used in the method
    *             selectPort() in DSPortAdapter
    *
    * @return  DSPortAdapter if adapter present
    *
    * @throws OneWireIOException
    * @throws OneWireException WHEN port or adapter not present
    */
   public static DSPortAdapter getAdapter (String adapterName,
                                           String portName)
      throws OneWireIOException, OneWireException
   {
      DSPortAdapter adapter;

      // enumerature through available adapters to find the correct one
      for (Enumeration adapter_enum = enumerateAllAdapters();
              adapter_enum.hasMoreElements(); )
      {

         // cast the enum as a DSPortAdapter
         adapter = ( DSPortAdapter ) adapter_enum.nextElement();

         // see if this is the type of adapter we want
         if (!adapter.getAdapterName().equals(adapterName))
            continue;

         // attempt to open and verify the adapter
         if (adapter.selectPort(portName))
         {

            // check for the adapter
            if (adapter.adapterDetected())
               return adapter;
            else
            {

               // close the port just opened
               adapter.freePort();

               throw new OneWireException("Port found \"" + portName
                                          + "\" but Adapter \"" + adapterName
                                          + "\" not detected");
            }
         }
         else
            throw new OneWireException(
               "Specified port \"" + portName
               + "\" could not be selected for adapter \"" + adapterName
               + "\"");
      }

      // adapter by that name not found
      throw new OneWireException("Specified adapter name \"" + adapterName
                                 + "\" is not known");
   }

   /**
    * Attempts to find, open, and verify the default adapter and
    * port.  Look for the default adapter/port in the following locations:
    * <p>
    * <ul>
    * <li> Use adapter/port in System.properties for onewire.adapter.default,
    *      and onewire.port.default properties tags.
    * <li> Use adapter/port from onewire.properties file in current directory
    *      or <java.home>/lib/ (Desktop) or /etc/ (TINI)
    * <li> Use smart default, TMEX default on Win32 or
           TINIExternalAdapter port serial1 on TINI)
    * </ul>
    *
    * @return  DSPortAdapter if default adapter present
    *
    * @throws OneWireIOException
    * @throws OneWireException WHEN port or adapter not present
    */
   public static DSPortAdapter getDefaultAdapter ()
      throws OneWireIOException, OneWireException
   {
      return getAdapter(getProperty("onewire.adapter.default"), 
                        getProperty("onewire.port.default"));
   }

   /**
    * Attempts to find a onewire property.
    * Look for the property in the following locations:
    * <p>
    * <ul>
    * <li> In System.properties
    * <li> In onewire.properties file in current directory
    *      or <java.home>/lib/ (Desktop) or /etc/ (TINI)
    * <li> 'smart' default if property is 'onewire.adapter.default'
    *      or 'onewire.port.default'
    * </ul>
    *
    * @param propName, string name of the property to read
    *
    * @return  String representing the property value or 'null' if
    *          it could not be found.
    */
   public static String getProperty (String propName)
   {
      Properties      onewire_properties = new Properties();
      FileInputStream prop_file          = null;
      String          ret_str            = null;
      DSPortAdapter   adapter_instance;
      Class           adapter_class;

      // try system properties
      try
      {
         ret_str = System.getProperty(propName, null);
      }
      catch (Exception e)
      {
         ret_str = null;
      }

      // if defaults not found then try onewire.properties file
      if (ret_str == null)
      {

         // loop to attempt to open the onewire.properties file in two locations
         // .\onewire.properties or <java.home>\lib\onewire.properties
         String path = new String("");

         for (int i = 0; i <= 1; i++)
         {

            // attempt to open the onewire.properties file 
            try
            {
               prop_file = new FileInputStream(path + "onewire.properties");
            }
            catch (IOException e)
            {
               prop_file = null;
            }

            // if open, then try to read value
            if (prop_file != null)
            {

               // attempt to read the onewire.properties
               try
               {
                  onewire_properties.load(prop_file);

                  ret_str = onewire_properties.getProperty(propName, null);
               }
               catch (Exception e)
               {
                  ret_str = null;
               }
            }

            // check to see if we now have the value
            if (ret_str != null)
               break;

            // try the second path
            path = System.getProperty("java.home") + File.separator + "lib"
                   + File.separator;
         }
      }

      // if defaults still not found then check TMEX default
      if (ret_str == null)
      {
         try
         {
            if (propName.equals("onewire.adapter.default"))
               ret_str = TMEXAdapter.getDefaultAdapterName();
            else if (propName.equals("onewire.port.default"))
               ret_str = TMEXAdapter.getDefaultPortName();

            // if did not get real string then null out
            if (ret_str != null)
            {
               if (ret_str.length() <= 0) 
                  ret_str = null;
            }
         }
         catch (UnsatisfiedLinkError e){}
      }

      // if STILL not found then just pick DS9097U on 'smartDefaultPort'
      if (ret_str == null)
      {
         if (propName.equals("onewire.adapter.default"))
            ret_str = "DS9097U";
         else if (propName.equals("onewire.port.default"))
         {
            try
            {
   
               adapter_class    =
                  Class.forName("com.dalsemi.onewire.adapter.USerialAdapter");
               adapter_instance = ( DSPortAdapter ) adapter_class.newInstance();

               // check if has any ports (common javax.comm problem)
               if (adapter_instance.getPortNames().hasMoreElements())
                  ret_str =
                     ( String ) adapter_instance.getPortNames().nextElement();
            }
            catch (Exception e){}
         }
      }

      return ret_str;
   }
}
