/**
   * JComponents are really equal if their names are the same (or this is better than the
   * Object.equals()/hashCode() that is used by default for JComponents). Note that <code>
   * ReasonNotEquals</code> can be used to determine the reason for a failure
   *
   * @param arr1 first array of components
   * @param arr2 second array of components
   * @return true if the arrays are equal
   */
  public static boolean equalsComponentArrays(JComponent[] arr1, JComponent[] arr2) {
    ReasonNotEquals.addClassVisiting("pUtils.equalsComponentArrays()");

    boolean result = true;
    if (arr1 != arr2) {
      // if(arr1.getClass() == arr2.getClass() &&
      // JComponent.class.isAssignableFrom( arr1.getClass()))
      // {
      if (arr1.length == arr2.length) {
        int size = arr1.length;
        for (int i = 0; i < size; i++) {
          String e1 = arr1[i].getName();
          String e2 = arr2[i].getName();
          if (e1 == null ? e2 == null : e1.equals(e2)) { // keep on being true
          } else {
            ReasonNotEquals.addReason("component names not equal: " + e1 + ", " + e2);
            result = false;
            break;
          }
        }
      } else {
        ReasonNotEquals.addReason("component arrays different sizes");
        result = false;
      }
      // }
      // else
      // {
      // result = false;
      // }
    }
    return result;
  }
  /**
   * Method to use when we are needing to see if two sets of components are equal when we are
   * considering them as JavaBeans. If all the properties of each component are equal, then the two
   * sets are equal. 'all the properties' is determined by recursing down to the child components
   *
   * @param components first array of components
   * @param components2 second array of components
   * @param widgetClassifier Provides this method with a definition of a component
   */
  public static boolean equalsByProperties(
      JComponent[] components, JComponent[] components2, WidgetClassifierI widgetClassifier) {
    ReasonNotEquals.addClassVisiting("pUtils.equalsByProperties([])");

    boolean result = true;
    if (components.length != components2.length) {
      ReasonNotEquals.addReason(
          "got lists of components of different sizes: "
              + components.length
              + " and "
              + components2.length);
      result = false;
    } else {
      for (int i = 0; i < components.length; i++) {
        JComponent comp1 = components[i];
        JComponent comp2 = components2[i];
        // not work due to diff classloaders having been used
        // if(comp1.getClass() != comp2.getClass())
        if (!comp1.getClass().getName().equals(comp2.getClass().getName())) {
          ReasonNotEquals.addReason(
              "two components were not of the same class: "
                  + comp1.getClass()
                  + " and "
                  + comp2.getClass());
          result = false;
          break;
        } else {
          result = equalsByProperties(comp1, comp2, widgetClassifier);
          if (!result) {
            ReasonNotEquals.addReason(
                "equalsByProperties() failed for 2 classes of type: " + comp1.getClass().getName());
            break;
          }
        }
      }
    }
    return result;
  }
  public static boolean equalsByProperties(
      JComponent component1, JComponent component2, WidgetClassifierI widgetClassifier) {
    ReasonNotEquals.addClassVisiting("pUtils.equalsByProperties()");

    boolean result = true;
    List oneControls = getAllControls(component1);
    oneControls.add(0, component1);

    List twoControls = getAllControls(component2);
    twoControls.add(0, component2);
    if (oneControls.size() != twoControls.size()) {
      ReasonNotEquals.addReason(
          "got lists of controls of different sizes: "
              + oneControls.size()
              + " and "
              + twoControls.size());
      Print.prList(oneControls, "oneControls");
      Print.prList(twoControls, "twoControls");
      result = false;
    } else {
      for (int i = 0; i < oneControls.size(); i++) {
        Container comp1 = (Container) oneControls.get(i);
        // Err.pr( "Observing a " + comp1.getClass());
        Container comp2 = (Container) twoControls.get(i);
        if (comp1.getClass() != comp2.getClass()) {
          ReasonNotEquals.addReason(
              "first component is of type "
                  + comp1.getClass()
                  + " while second is of type "
                  + comp2.getClass());
          result = false;
          break;
        } else if (!Utils.equals(comp1.getName(), comp2.getName())) {
          ReasonNotEquals.addReason(
              "first component has name "
                  + comp1.getName()
                  + " while second has name "
                  + comp2.getName());
          result = false;
          break;
        } else if (widgetClassifier != null
            && !widgetClassifier.isAWidget(
                comp1.getClass())) { // If a comp1/comp2 is not a widget then end up here and we
          // won't examine
          // its properties
          // Err.pr( comp1.getClass() + " is not a widget: " + widgetClassifier.getReason());
        } else {
          List propertyNamesOne = new ArrayList();
          List propertyNamesTwo = new ArrayList();
          List propertyValuesOne = new ArrayList();
          List propertyValuesTwo = new ArrayList();
          loadPropertyNamesValues(comp1.getClass(), comp1, propertyNamesOne, propertyValuesOne);
          loadPropertyNamesValues(comp2.getClass(), comp2, propertyNamesTwo, propertyValuesTwo);
          if (propertyNamesOne.size() != propertyValuesOne.size()) {
            Err.error("expect names and properties to be same size for " + comp1.getClass());
          } else if (propertyNamesTwo.size() != propertyValuesTwo.size()) {
            Err.error("expect names and properties to be same size for " + comp2.getClass());
          } else if (propertyNamesOne.size() != propertyNamesTwo.size()) {
            ReasonNotEquals.addReason(
                "there should be an equal number of properties in "
                    + comp1.getClass()
                    + " and "
                    + comp2.getClass());
            result = false;
            break;
          } else {
            // Err.pr( "Will be examining properties from a " + comp1.getClass() + " against " +
            // comp2.getClass());
            for (int j = 0; j < propertyNamesOne.size(); j++) {
              String onePropName = (String) propertyNamesOne.get(j);
              String twoPropName = (String) propertyNamesTwo.get(j);
              if (!onePropName.equals(twoPropName)) {
                // If they are of thge same type, how could they possibly have
                // different property names, thus make this an error
                String txt =
                    "expect property names to be equal, got " + onePropName + " and " + twoPropName;
                // ReasonNotEquals.addReason( txt);
                Err.error(txt);
                result = false;
                break;
              } else {
                Object onePropValue = propertyValuesOne.get(j);
                Object twoPropValue = propertyValuesTwo.get(j);
                boolean debug = false;
                /*
                if(onePropName.equals( "text"))
                {
                Err.debug();
                debug = true;
                }
                */
                if (onePropValue.getClass() != twoPropValue.getClass()) {
                  Err.error(
                      "Property values to be examining should be of the same type, got "
                          + onePropValue.getClass().getName()
                          + " and "
                          + twoPropValue.getClass().getName());
                  result = false;
                  break;
                } else if (!Utils.isSimple(onePropValue.getClass())) {
                  // We only want to do value comparisons for simple types
                  // Err.pr( "Not simple: <" + onePropValue + ">");
                  if (debug) {
                    Err.error("Only supposed to be debugging on a simple property value");
                  }
                } else {
                  if (debug) {
                    Err.pr(
                        "Doing cf between <"
                            + onePropValue
                            + "> and <"
                            + twoPropValue
                            + "> for "
                            + onePropName
                            + " in a "
                            + comp1.getClass());
                    debug = false;
                  }
                  if (!onePropValue.equals(twoPropValue)) {
                    ReasonNotEquals.addReason(
                        "expect property values to be equal, got <"
                            + onePropValue
                            + "> and <"
                            + twoPropValue
                            + ">");
                    result = false;
                    break;
                  } else { // Err.pr( "\tconcordance, prop name " + onePropName + ", prop value " +
                    // onePropValue);
                  }
                }
              }
            }
            if (result == false) {
              break; // so break out of outer loop too
            }
          }
        }
      }
    }
    return result;
  }