/*
   * Parses the JSON properties and upgrades the component if necessary.
   * This method is called recursively for nested components.
   */
  private static void upgradeComponent(
      int srcYaVersion, Map<String, JSONValue> componentProperties, StringBuilder upgradeDetails) {

    String componentType = componentProperties.get("$Type").asString().getString();

    // Get the source component version from the componentProperties.
    int srcCompVersion = 0;
    if (componentProperties.containsKey("$Version")) {
      String version = componentProperties.get("$Version").asString().getString();
      srcCompVersion = Integer.parseInt(version);
    }

    if (srcYaVersion < 2) {
      // In YOUNG_ANDROID_VERSION 2, the Logger component was removed; Notifier should be used
      // instead.
      // Here we change the Logger component to a Notifier component automatically. Sweet!
      // (We need to do this upgrade here, not in the upgradeComponentProperties method. This is
      // because the code below calls COMPONENT_DATABASE.getComponentVersion() and that will fail
      // if componentType is "Logger" because "Logger" isn't a valid component type anymore.)
      if (componentType.equals("Logger")) {
        componentType = "Notifier";
        srcCompVersion = COMPONENT_DATABASE.getComponentVersion(componentType);
        componentProperties.put("$Type", new ClientJsonString(componentType));
        componentProperties.put("$Version", new ClientJsonString("" + srcCompVersion));
        upgradeDetails.append(
            MESSAGES.upgradeDetailLoggerReplacedWithNotifier(
                componentProperties.get("$Name").asString().getString()));
      }
    }

    // Get the system component version from the component database.
    final int sysCompVersion = COMPONENT_DATABASE.getComponentVersion(componentType);

    // Upgrade if necessary.
    upgradeComponentProperties(componentProperties, componentType, srcCompVersion, sysCompVersion);

    if (srcYaVersion < 26) {
      // Beginning with YOUNG_ANDROID_VERSION 26:
      // - In .scm files, values for asset, BluetoothClient, component, lego_nxt_sensor_port,
      // and string properties no longer contain leading and trailing quotes.
      unquotePropertyValues(componentProperties, componentType);
    }

    // Upgrade nested components
    if (componentProperties.containsKey("$Components")) {
      JSONArray componentsArray = componentProperties.get("$Components").asArray();
      for (JSONValue nestedComponent : componentsArray.getElements()) {
        upgradeComponent(srcYaVersion, nestedComponent.asObject().getProperties(), upgradeDetails);
      }
    }
  }
  private static int upgradeFormProperties(
      Map<String, JSONValue> componentProperties, int srcCompVersion) {
    if (srcCompVersion < 2) {
      // The Screen.Scrollable property was added.
      // If the form contains a direct child component whose height is set to fill parent,
      // we set the Scrollable property value to false.
      if (componentProperties.containsKey("$Components")) {
        JSONArray componentsArray = componentProperties.get("$Components").asArray();
        for (JSONValue nestedComponent : componentsArray.getElements()) {
          Map<String, JSONValue> nestedComponentProperties =
              nestedComponent.asObject().getProperties();
          if (nestedComponentProperties.containsKey("Height")) {
            JSONValue heightValue = nestedComponentProperties.get("Height");
            String heightString = heightValue.asString().getString();
            try {
              int height = Integer.parseInt(heightString);
              if (height == MockVisibleComponent.LENGTH_FILL_PARENT) {
                // Set the Form's Scrollable property to false.
                componentProperties.put("Scrollable", new ClientJsonString("False"));
                break;
              }
            } catch (NumberFormatException e) {
              // Ignore this. If we throw an exception here, the project is unrecoverable.
            }
          }
        }
      }
      // Properties related to this component have now been upgraded to version 2.
      srcCompVersion = 2;
    }
    if (srcCompVersion < 3) {
      // The Screen.Icon property was added.
      // No properties need to be modified to upgrade to version 3.
      srcCompVersion = 3;
    }
    if (srcCompVersion < 4) {
      // The Screen.ErrorOccurred event was added.
      // No properties need to be modified to upgrade to version 4.
      srcCompVersion = 4;
    }
    if (srcCompVersion < 5) {
      // The Screen.ScreenOrientation property and Screen.ScreenOrientationChanged event were
      // added.
      // No properties need to be modified to upgrade to version 5.
      srcCompVersion = 5;
    }
    if (srcCompVersion < 6) {
      // The SwitchForm and SwitchFormWithArgs methods were removed and the OtherScreenClosed event
      // was added.
      srcCompVersion = 6;
    }
    if (srcCompVersion < 7) {
      // The VersionCode and VersionName properties were added. No properties need to be modified
      // to update to version 7.
      srcCompVersion = 7;
    }

    if (srcCompVersion < 8) {
      // The AlignHorizontal and AlignVertical properties were added. No blocks need to be modified
      // to upgrade to version 8.
      srcCompVersion = 8;
    }
    return srcCompVersion;
  }