// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2012 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0

package com.google.appinventor.client.youngandroid;

import static com.google.appinventor.client.Ode.MESSAGES;

import java.util.Map;

import com.google.appinventor.client.editor.simple.SimpleComponentDatabase;
import com.google.appinventor.client.editor.simple.components.MockVisibleComponent;
import com.google.appinventor.client.output.OdeLog;
import com.google.appinventor.client.properties.json.ClientJsonString;
import com.google.appinventor.common.utils.StringUtils;
import com.google.appinventor.components.common.YaVersion;
import com.google.appinventor.shared.properties.json.JSONArray;
import com.google.appinventor.shared.properties.json.JSONValue;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.user.client.Window;

/**
 * A class that can upgrade a Young Android Form source file.
 *
 * @author [email protected] (Liz Looney)
 */
public final class YoungAndroidFormUpgrader {
  static class LoadException extends IllegalStateException {
    LoadException(String message) {
      super(message);
    }
  }

  private static final SimpleComponentDatabase COMPONENT_DATABASE =
      SimpleComponentDatabase.getInstance();

  private YoungAndroidFormUpgrader() {
  }

  /**
   * Upgrades the given sourceProperties if necessary.
   *
   * @param sourceProperties the properties from the source file
   * @return true if the sourceProperties was upgraded, false otherwise
   */
  public static boolean upgradeSourceProperties(Map<String, JSONValue> sourceProperties) {
    StringBuilder upgradeDetails = new StringBuilder();
    try {
      int srcYaVersion = getSrcYaVersion(sourceProperties);
      if (needToUpgrade(srcYaVersion)) {
        Map<String, JSONValue> formProperties =
            sourceProperties.get("Properties").asObject().getProperties();
        upgradeComponent(srcYaVersion, formProperties, upgradeDetails);
        // The sourceProperties were upgraded. Update the version number.
        setSrcYaVersion(sourceProperties);
        if (upgradeDetails.length() > 0) {
          Window.alert(MESSAGES.projectWasUpgraded(upgradeDetails.toString()));
        }
        return true;
      }
    } catch (LoadException e) {
      // This shouldn't happen. If it does it's our fault, not the user's fault.
      Window.alert(MESSAGES.unexpectedProblem(e.getMessage()));
      OdeLog.xlog(e);
    }
    return false;
  }

  private static int getSrcYaVersion(Map<String, JSONValue> sourceProperties) {
    int srcYaVersion = 0;
    if (sourceProperties.containsKey("YaVersion")) {
      String version = sourceProperties.get("YaVersion").asString().getString();
      srcYaVersion = Integer.parseInt(version);
    }
    return srcYaVersion;
  }

  private static void setSrcYaVersion(Map<String, JSONValue> sourceProperties) {
    sourceProperties.put("YaVersion", new ClientJsonString("" + YaVersion.YOUNG_ANDROID_VERSION));
  }

  private static boolean needToUpgrade(int srcYaVersion) {
    // Compare the source file's YoungAndroid version with the system's YoungAndroid version.
    final int sysYaVersion = YaVersion.YOUNG_ANDROID_VERSION;
    if (srcYaVersion > sysYaVersion) {
      // The source file's version is newer than the system's version.
      // This can happen if the user is using (or in the past has used) a non-production version of
      // App Inventor.
      // This can also happen if the user is connected to a new version of App Inventor and then
      // later is connected to an old version of App Inventor.
      // We'll try to load the project but there may be compatibility issues if the project uses
      // future components or other features that the current system doesn't understand.
      Window.alert(MESSAGES.newerVersionProject());
      return false;
    }

    if (srcYaVersion == 0) {
      // The source file doesn't have a YoungAndroid version number.
      // There are two situations that cause this:
      // 1. The project may have been downloaded from alpha (androidblocks.googlelabs.com) and
      // uploaded to beta (appinventor.googlelabs.com), which is illegal.
      // 2. The project may have been created with beta (appinventor.googlelabs.com) before we
      // started putting version numbers into the source file, which is legal, and nothing
      // really changed between version 0 and version 1.
      //
      // For a limited time, we assume #2, show a warning, and proceed.
      // TODO(lizlooney) - after the limited time is up (when we think that all appinventor
      // projects have been upgraded), we may decide to refuse to load the project.
      Window.alert(MESSAGES.veryOldProject());
    }

    return (srcYaVersion < sysYaVersion);
  }

  /*
   * 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;
    try {
      sysCompVersion = COMPONENT_DATABASE.getComponentVersion(componentType);
    } catch (IllegalArgumentException e) {
      OdeLog.wlog("Cound not find component of type = " + componentType
        + " assuming it is an external component.");
      return;                   // This should be safe because external components don't have
                                // nested children
    }

    // 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 void upgradeComponentProperties(Map<String, JSONValue> componentProperties,
      String componentType, int srcCompVersion, final int sysCompVersion) {
    // Compare the source file's component version with the system's component version.
    if (srcCompVersion == 0) {
      // The source file doesn't have a version number for this component.
      // There are two situations that cause this:
      // 1. The project may have been downloaded from alpha (androidblocks.googlelabs.com) and
      // uploaded to beta (appinventor.googlelabs.com), which is illegal.
      // 2. The project may have been created with beta (appinventor.googlelabs.com) before we
      // started putting version numbers into the source file, which is legal, and nothing
      // really changed between version 0 and version 1.
      //
      // For a limited time, we assume #2 and pretend that the source file said version 1.
      // TODO(lizlooney) - after the limited time is up (when we think that all appinventor
      // projects have been upgraded), we may decide to refuse to load the project.
      srcCompVersion = 1;
    }

    if (srcCompVersion > sysCompVersion) {
      // This shouldn't happen because we should have already detected that the project is a newer
      // version than the system and returned false in needToUpgrade.
      // NOTE(lizlooney,user) - we need to make sure that this situation does not happen by
      // incrementing YaVersion.YOUNG_ANDROID_VERSION each time a component's version number is
      // incremented.
      throw new LoadException(
          MESSAGES.newerVersionComponentException(componentType, srcCompVersion, sysCompVersion));
    }

    if (srcCompVersion < sysCompVersion) {
      // NOTE(lizlooney,user) - when a component changes, increment the component's version
      // number in com.google.appinventor.components.common.YaVersion and add code here to upgrade
      // properties as necessary.
      if (componentType.equals("AccelerometerSensor")){
        srcCompVersion = upgradeAccelerometerSensorProperties(componentProperties, srcCompVersion);

      } else if (componentType.equals("ActivityStarter")) {
        srcCompVersion = upgradeActivityStarterProperties(componentProperties, srcCompVersion);

      } else if (componentType.equals("Ball")) {
        srcCompVersion = upgradeBallProperties(componentProperties, srcCompVersion);

      } else if (componentType.equals("BarcodeScanner")) {
        srcCompVersion = upgradeBarcodeScannerProperties(componentProperties, srcCompVersion);

      } else if (componentType.equals("BluetoothClient")) {
        srcCompVersion = upgradeBluetoothClientProperties(componentProperties, srcCompVersion);

      } else if (componentType.equals("BluetoothServer")) {
        srcCompVersion = upgradeBluetoothServerProperties(componentProperties, srcCompVersion);

      } else if (componentType.equals("Slider")) {
        srcCompVersion = upgradeSliderProperties(componentProperties, srcCompVersion);

      } else if (componentType.equals("TextToSpeech")) {
        srcCompVersion = upgradeTextToSpeechProperties(componentProperties, srcCompVersion);

      } else if (componentType.equals("Button")) {
        srcCompVersion = upgradeButtonProperties(componentProperties, srcCompVersion);

      } else if (componentType.equals("Camera")) {
        srcCompVersion = upgradeCameraProperties(componentProperties, srcCompVersion);

      } else if (componentType.equals("Canvas")) {
        srcCompVersion = upgradeCanvasProperties(componentProperties, srcCompVersion);

      } else if (componentType.equals("CheckBox")) {
        srcCompVersion = upgradeCheckBoxProperties(componentProperties, srcCompVersion);

      } else if (componentType.equals("Clock")) {
        srcCompVersion = upgradeClockProperties(componentProperties, srcCompVersion);

      } else if (componentType.equals("ContactPicker")) {
        srcCompVersion = upgradeContactPickerProperties(componentProperties, srcCompVersion);

      } else if (componentType.equals("DatePicker")) {
        srcCompVersion = upgradeDatePickerProperties(componentProperties, srcCompVersion);

      } else if (componentType.equals("EmailPicker")) {
        srcCompVersion = upgradeEmailPickerProperties(componentProperties, srcCompVersion);

      } else if (componentType.equals("File")) {
        srcCompVersion = upgradeFileProperties(componentProperties, srcCompVersion);

      } else if (componentType.equals("Form")) {
        srcCompVersion = upgradeFormProperties(componentProperties, srcCompVersion);

      } else if (componentType.equals("FusiontablesControl")) {
        srcCompVersion = upgradeFusiontablesControlProperties(componentProperties, srcCompVersion);

      } else if (componentType.equals("HorizontalArrangement")) {
        srcCompVersion = upgradeHorizontalArrangementProperties(componentProperties, srcCompVersion);

      } else if (componentType.equals("Image")) {
        srcCompVersion = upgradeImageProperties(componentProperties, srcCompVersion);

      } else if (componentType.equals("ImagePicker")) {
        srcCompVersion = upgradeImagePickerProperties(componentProperties, srcCompVersion);

      } else if (componentType.equals("ImageSprite")) {
        srcCompVersion = upgradeImageSpriteProperties(componentProperties, srcCompVersion);

      } else if (componentType.equals("Label")) {
        srcCompVersion = upgradeLabelProperties(componentProperties, srcCompVersion);

      } else if (componentType.equals("ListPicker")) {
        srcCompVersion = upgradeListPickerProperties(componentProperties, srcCompVersion);

      } else if (componentType.equals("ListView")) {
        srcCompVersion = upgradeListViewProperties(componentProperties, srcCompVersion);

      } else if (componentType.equals("LocationSensor")) {
        srcCompVersion = upgradeLocationSensorProperties(componentProperties, srcCompVersion);

      } else if (componentType.equals("OrientationSensor")) {
        srcCompVersion = upgradeOrientationSensorProperties(componentProperties, srcCompVersion);

      } else if (componentType.equals("PasswordTextBox")) {
        srcCompVersion = upgradePasswordTextBoxProperties(componentProperties, srcCompVersion);

      } else if (componentType.equals("PhoneCall")) {
        srcCompVersion = upgradePhoneCallProperties(componentProperties, srcCompVersion);

      } else if (componentType.equals("PhoneNumberPicker")) {
        srcCompVersion = upgradePhoneNumberPickerProperties(componentProperties, srcCompVersion);

      } else if (componentType.equals("Player")) {
        srcCompVersion = upgradePlayerProperties(componentProperties, srcCompVersion);

      } else if (componentType.equals("Sound")) {
        srcCompVersion = upgradeSoundProperties(componentProperties, srcCompVersion);

      } else if (componentType.equals("SoundRecorder")) {
        srcCompVersion = upgradeSoundRecorderProperties(componentProperties, srcCompVersion);

      } else if (componentType.equals("TimePicker")) {
        srcCompVersion = upgradeTimePickerProperties(componentProperties, srcCompVersion);

      } else if (componentType.equals("TinyWebDB")) {
        srcCompVersion = upgradeTinyWebDBProperties(componentProperties, srcCompVersion);

      } else if (componentType.equals("VerticalArrangement")) {
        srcCompVersion = upgradeVerticalArrangementProperties(componentProperties, srcCompVersion);

      } else if (componentType.equals("VideoPlayer")) {
        srcCompVersion = upgradeVideoPlayerProperties(componentProperties, srcCompVersion);

      } else if (componentType.equals("TextBox")) {
        srcCompVersion = upgradeTextBoxProperties(componentProperties, srcCompVersion);

      } else if (componentType.equals("Texting")) {
        srcCompVersion = upgradeTextingProperties(componentProperties, srcCompVersion);

      }  else if (componentType.equals("Notifier")) {
        srcCompVersion = upgradeNotifierProperties(componentProperties, srcCompVersion);

      } else if (componentType.equals("Twitter")) {
        srcCompVersion = upgradeTwitterProperties(componentProperties, srcCompVersion);

      } else if (componentType.equals("Web")) {
        srcCompVersion = upgradeWebProperties(componentProperties, srcCompVersion);

      } else if (componentType.equals("WebViewer")) {
        srcCompVersion = upgradeWebViewerProperties(componentProperties, srcCompVersion);
      } else if (componentType.equals("FirebaseDB")) {
        srcCompVersion = upgradeFirebaseDBProperties(componentProperties, srcCompVersion);
      } else if (componentType.equals("Pedometer")) {
        srcCompVersion = upgradePedometerProperties(componentProperties, srcCompVersion);
      }

      if (srcCompVersion < sysCompVersion) {
        // If we got here, a component needed to be upgraded, but nothing handled it.
        // NOTE(lizlooney,user) - we need to make sure that this situation does not happen by
        // adding the appropriate code above to handle all component upgrades.
        throw new LoadException(
            MESSAGES.noUpgradeStrategyException(componentType, srcCompVersion, sysCompVersion));
      }

      // The component was upgraded. Update the $Version property.
      componentProperties.put("$Version", new ClientJsonString("" + srcCompVersion));

    }
  }

  private static void unquotePropertyValues(Map<String, JSONValue> componentProperties,
      String componentType) {
    // From the component database, get the map of property names and types for the component type.
    Map<String, String> propertyTypesByName =
        COMPONENT_DATABASE.getPropertyTypesByName(componentType);

    // Iterate through the component properties.
    for (String propertyName : componentProperties.keySet()) {
      // Get the property type.
      String propertyType = propertyTypesByName.get(propertyName);
      // In theory the check for propertyType == null shouldn't be necessary
      // but I have sometimes had a problem with it being null when running
      // with GWT debugging. Maybe it changes the timing somehow. Anyway,
      // this test for null should not hurt anything. -Sharon
      if (propertyType == null) {
        OdeLog.wlog("Couldn't find propertyType for property " + propertyName +
            " in component type " + componentType);
        continue;
      }
      // If the property type is one that was previously quoted, unquote the value.
      if (propertyType.equals("asset") ||
          propertyType.equals("BluetoothClient") ||
          propertyType.equals("component") ||
          propertyType.equals("lego_nxt_sensor_port") ||
          propertyType.equals("string")) {
        // Unquote the property value.
        JSONValue propertyValue = componentProperties.get(propertyName);
        String propertyValueString = propertyValue.asString().getString();
        propertyValueString = StringUtils.unquote(propertyValueString);
        componentProperties.put(propertyName, new ClientJsonString(propertyValueString));
      }
    }
  }

  private static int upgradeAccelerometerSensorProperties(Map<String, JSONValue> componentProperties,
      int srcCompVersion) {
    if (srcCompVersion < 2) {
      // The AccelerometerSensor.MinimumInterval property was added.
      // No properties need to be modified to upgrade to version 2.
      srcCompVersion = 2;
    }
    if (srcCompVersion < 3) {
      // The AccelerometerSensor.Sensitivity property was added.
      // No properties need to be modified to upgrade to version 3.
      srcCompVersion = 3;
    }
    return srcCompVersion;
  }

  private static int upgradeActivityStarterProperties(Map<String, JSONValue> componentProperties,
      int srcCompVersion) {
    if (srcCompVersion < 2) {
      // The ActivityStarter.DataType, ActivityStarter.ResultType, and ActivityStarter.ResultUri
      // properties were added.
      // The ActivityStarter.ResolveActivity method was added.
      // The ActivityStarter.ActivityError event was added.
      // No properties need to be modified to upgrade to version 2.
      srcCompVersion = 2;
    }
    if (srcCompVersion < 3) {
      // The ActivityStarter.ActivityError event was marked userVisible false and is no longer
      // used.
      // No properties need to be modified to upgrade to version 3.
      srcCompVersion = 3;
    }
    if (srcCompVersion < 4) {
      // The ActivityStarter.StartActivity method was modified to provide the parent Form's
      // screen animation type.
      // No properties need to be modified to upgrade to version 4.
      srcCompVersion = 4;
    }
    if (srcCompVersion < 5) {
      // The ActivityStarter.ActivityCanceled event was added.
      // No properties need to be modified to upgrade to version 5.
      srcCompVersion = 5;
    }
    if (srcCompVersion < 6) {
      // Extras property was added to accept a list of key-value pairs to put to the intent
      String defaultValue = "";
      boolean sendWarning = false;

      if (componentProperties.containsKey("ExtraKey")) {
        String extraKeyValue = componentProperties.get("ExtraKey").asString().getString();
        if (!extraKeyValue.equals(defaultValue)) {
          sendWarning = true;
        }
      }

      if (componentProperties.containsKey("ExtraValue")) {
        String extraValueValue = componentProperties.get("ExtraValue").asString().getString();
        if (!extraValueValue.equals(defaultValue)) {
          sendWarning = true;
        }
      }

      if (sendWarning) {
        Window.alert(MESSAGES.extraKeyValueWarning());
      }

      srcCompVersion = 6;
    }
    return srcCompVersion;
  }

  private static int upgradeBallProperties(Map<String, JSONValue> componentProperties,
      int srcCompVersion) {
    if (srcCompVersion < 2) {
      // The Heading property was changed from int to double
      srcCompVersion = 2;
    }
    if (srcCompVersion < 3) {
      // The Z property was added
      srcCompVersion = 3;
    }
    if (srcCompVersion < 4) {
      // The TouchUp, TouchDown, and Flung events were added. (for all sprites)
      // No properties need to be modified to upgrade to version 4.
      srcCompVersion = 4;
      }
    if (srcCompVersion < 5) {
      // The callback parameters speed and heading were added to Flung.
      srcCompVersion = 5;
    }
    return srcCompVersion;
  }
  private static int upgradeBarcodeScannerProperties(Map<String, JSONValue> componentProperties,
      int srcCompVersion) {
    if (srcCompVersion < 2) {
      // The UseExternalScanner property was added.
      srcCompVersion = 2;
    }
    return srcCompVersion;
  }

  private static int upgradeBluetoothClientProperties(Map<String, JSONValue> componentProperties,
      int srcCompVersion) {
    if (srcCompVersion < 2) {
      // The BluetoothClient.Enabled property was added.
      // No properties need to be modified to upgrade to version 2.
      srcCompVersion = 2;
    }
    if (srcCompVersion < 3) {
      // The BluetoothClient.BluetoothError event was marked userVisible false and is no longer
      // used.
      // No properties need to be modified to upgrade to version 3.
      srcCompVersion = 3;
    }
    if (srcCompVersion < 4) {
      // The BluetoothClient.DelimiterByte property was added.
      // No properties need to be modified to upgrade to version 4.
      srcCompVersion = 4;
    }
    if (srcCompVersion < 5) {
      // The BluetoothClient.Secure property was added.
      // No properties need to be modified to upgrade to version 5.
      srcCompVersion = 5;
    }
    return srcCompVersion;
  }

  private static int upgradeBluetoothServerProperties(Map<String, JSONValue> componentProperties,
      int srcCompVersion) {
    if (srcCompVersion < 2) {
      // The BluetoothServer.Enabled property was added.
      // No properties need to be modified to upgrade to version 2.
      srcCompVersion = 2;
    }
    if (srcCompVersion < 3) {
      // The BluetoothServer.BluetoothError event was marked userVisible false and is no longer
      // used.
      // No properties need to be modified to upgrade to version 3.
      srcCompVersion = 3;
    }
    if (srcCompVersion < 4) {
      // The BluetoothServer.DelimiterByte property was added.
      // No properties need to be modified to upgrade to version 4.
      srcCompVersion = 4;
    }
    if (srcCompVersion < 5) {
      // The BluetoothServer.Secure property was added.
      // No properties need to be modified to upgrade to version 5.
      srcCompVersion = 5;
    }
    return srcCompVersion;
  }
  private static int upgradeSliderProperties(Map<String, JSONValue> componentProperties,
      int srcCompVersion) {
    if (srcCompVersion < 1) {
      // Initial version. Placeholder for future upgrades
      srcCompVersion = 1;
    }
    if (srcCompVersion < 2) {
      // Added the property to allow for the removal of the Thumb Slider
      srcCompVersion = 2;
    }
    return srcCompVersion;
  }

  private static int upgradeTextToSpeechProperties(Map<String, JSONValue> componentProperties,
      int srcCompVersion) {
    if (srcCompVersion < 2) {
      // Added speech pitch and rate
      srcCompVersion = 2;
    }
    if (srcCompVersion < 3) {
      // The AvailableLanguages property was added
      // The AvailableCountires property was added
      // No properties need to be modified to upgrade to version 3.
      srcCompVersion = 3;
    }
    if (srcCompVersion < 4) {
      // the Country designer property was changed to use a ChoicePropertyEditor
      // the Language designer property was changed to use a ChoicePropertyEditor
      srcCompVersion = 4;
    }
    if (srcCompVersion < 5) {
      // default value was added to the Country designer property
      // default value was added to the Language designer property
      srcCompVersion = 5;
    }
    return srcCompVersion;
  }

  private static int upgradeButtonProperties(Map<String, JSONValue> componentProperties,
      int srcCompVersion) {
    if (srcCompVersion < 2) {
      // The Alignment property was renamed to TextAlignment.
      handlePropertyRename(componentProperties, "Alignment", "TextAlignment");
      // Properties related to this component have now been upgraded to version 2.
      srcCompVersion = 2;
    }
    if (srcCompVersion < 3) {
      // The LongClick event was added.
      // No properties need to be modified to upgrade to version 3.
      srcCompVersion = 3;
    }
    if (srcCompVersion < 4) {
      // The Shape property was added.
      // No properties need to be modified to upgrade to version 4.
      srcCompVersion = 4;
    }
    if (srcCompVersion < 5) {
      // The ShowFeedback property was added.
      // No properties need to be modified to upgrade to version 5.
      srcCompVersion = 5;
    }
    if (srcCompVersion < 6) {
      // - Added TouchUp and TouchDown events
      // - FontSize, FontBold, FontItalic properties made visible in block editor
      // No properties need to be modified to upgrade to version 6.
      srcCompVersion = 6;
    }
    return srcCompVersion;
  }

  private static int upgradeCameraProperties(Map<String, JSONValue> componentProperties,
      int srcCompVersion) {
    if (srcCompVersion < 2) {
      // The UseFront property was added.
      // No properties need to be modified to upgrade to version 2.
      srcCompVersion = 2;
    }
    if (srcCompVersion < 3) {
      // The UseFront property was removed, it isn't supported in
      // newer versions of Android
      if (componentProperties.containsKey("UseFront")) {
        componentProperties.remove("UseFront");
        upgradeWarnDialog(MESSAGES.useFrontDeprecated());
      }
      srcCompVersion = 3;
    }
    return srcCompVersion;
  }

  private static int upgradeCanvasProperties(Map<String, JSONValue> componentProperties,
      int srcCompVersion) {
    if (srcCompVersion < 2) {
      // The LineWidth property was added.
      // No properties need to be modified to upgrade to version 2.
      srcCompVersion = 2;
    }
    if (srcCompVersion < 3) {
      // The FontSize and TextAlignment properties and
      // the DrawText and DrawTextAtAngle methods were added.
      // No properties need to be modified to upgrade to version 3.
      srcCompVersion = 3;
    }
    if (srcCompVersion < 4) {
      // No properties need to be modified to upgrade to version 4.
      // The Save and SaveAs methods were added.
      srcCompVersion = 4;
    }
    if (srcCompVersion < 5) {
      // No properties need to be modified to upgrade to version 5.
      // The methods GetBackgroundPixelColor, GetPixelColor, and
      // SetBackgroundPixelColor were added.
      srcCompVersion = 5;
    }
    if (srcCompVersion < 6) {
      // No properties need to be modified to upgrade to version 6.
      // The events TouchDown, TouchUp, and Flung were added.
      srcCompVersion = 6;
    }
    if (srcCompVersion < 7) {
      // The callback parameters speed and heading were added to Flung.
      srcCompVersion = 7;
    }
    if (srcCompVersion < 8) {
      // DrawCircle parameter names changed to centerx,centery, radius
      // Touched parameter touchedSprite name changed to touchedAnySprite
      // Dragged parameter draggedSprite name changed to draggedAnySprite
      srcCompVersion = 8;
    }
    if (srcCompVersion < 9) {
      // DrawCircle takes a new isFilled as fourth parameter.
      srcCompVersion = 9;
    }
    if (srcCompVersion < 10) {
      // TextAlignment default was changed to Component.ALIGNMENT_CENTER.
      // Previously the default was ALIGNMENT_NORMAL (left).
      int oldDefault = 0; // ALIGNMENT_NORMAL (left)
      JSONValue def = new ClientJsonString(Integer.toString(oldDefault));
      componentProperties.put("TextAlignment", def);
      srcCompVersion = 10;
    }
    return srcCompVersion;
  }

  private static int upgradeCheckBoxProperties(Map<String, JSONValue> componentProperties,
      int srcCompVersion) {
    if (srcCompVersion < 2) {
      // The Value property was renamed to Checked.
      handlePropertyRename(componentProperties, "Value", "Checked");
      // Properties related to this component have now been upgraded to version 2.
      srcCompVersion = 2;
    }
    return srcCompVersion;
  }

  private static int upgradeClockProperties(Map<String, JSONValue> componentProperties,
    int srcCompVersion) {
    if (srcCompVersion < 3) {
      // (2) The FormatDate and FormatDateTime methods were modified to take another parameter of pattern.
      // No properties need to be modified to upgrade to version 2.
      // (3) Duration Support was added
      // No properties need to be added to upgrade to version 3.
      srcCompVersion = 3;
    }
    return srcCompVersion;
  }

  private static int upgradeContactPickerProperties(Map<String, JSONValue> componentProperties,
      int srcCompVersion) {
    if (srcCompVersion < 2) {
      // The Alignment property was renamed to TextAlignment.
      handlePropertyRename(componentProperties, "Alignment", "TextAlignment");
      // Properties related to this component have now been upgraded to version 2.
      srcCompVersion = 2;
    }
    if (srcCompVersion < 3) {
      // The Open method was added.  No changes are needed.
      srcCompVersion = 3;
    }
    if (srcCompVersion < 4) {
      // The Shape property was added.
      // No properties need to be modified to upgrade to version 4.
      srcCompVersion = 4;
    }
    if (srcCompVersion < 5) {
      // The PhoneNumber, PhoneNumberList, and EmailAddressList properties were added.
      // For Eclair and up, we now use ContactsContract instead of the deprecated Contacts.
      srcCompVersion = 5;
    }
    if (srcCompVersion < 6) {
      // The ContactUri property was added.
      // No properties need to be modified to upgrade to version 6.
      srcCompVersion = 6;
    }
    return srcCompVersion;
  }

  private static int upgradeDatePickerProperties(Map<String, JSONValue> componentProperties,
      int srcCompVersion) {
    if (srcCompVersion < 2) {
      // The SetDateToDisplay and LaunchPicker methods were added.
      // No properties need to be modified to upgrade to version 2.
      srcCompVersion = 2;
    }
    if (srcCompVersion < 3) {
      // SetDateToDisplayFromInstant, and Instant property are added.
      // No properties need to be modified to upgrade to version 3.
      srcCompVersion = 3;
    }
    return srcCompVersion;
  }

  private static int upgradeEmailPickerProperties(Map<String, JSONValue> componentProperties,
      int srcCompVersion) {
    if (srcCompVersion < 2) {
      // The Alignment property was renamed to TextAlignment.
      handlePropertyRename(componentProperties, "Alignment", "TextAlignment");
      // Properties related to this component have now been upgraded to version 2.
      srcCompVersion = 2;
    }
    if (srcCompVersion < 3) {
      // RequestFocus function was added (via TextBoxBase)
      srcCompVersion = 3;
    }
    return srcCompVersion;
  }

  private static int upgradeFileProperties(Map<String, JSONValue> componentProperties,
      int srcCompVersion) {
    if(srcCompVersion < 2) {
      // File.AfterFileSaved event was added.
      // No properties need to be modified to upgrade to version 2.
      srcCompVersion = 2;
    }
    return srcCompVersion;
  }

  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;
    }
    if (srcCompVersion < 9) {
      // The OpenScreenAnimation and CloseScreenAnimation properties were added. No blocks need
      // to be modified to upgrade to version 9.
      srcCompVersion = 9;
    }
    if (srcCompVersion < 10) {
      // The BackPressed event was added. No blocks need to be modified to upgrade to version 10.
      srcCompVersion = 10;
    }
    if (srcCompVersion < 11) {
      // OpenScreenAnimation and CloseScreenAnimation are now properties.
      srcCompVersion = 11;
    }
    if (srcCompVersion < 12) {
      // The AboutScreen property was added.
      srcCompVersion = 12;
    }
    if (srcCompVersion < 13) {
      // The Scrollable property was set to False by default.
      if (componentProperties.containsKey("Scrollable")){
        String value = ((ClientJsonString)componentProperties.get("Scrollable")).getString();
        if (value.equals("False")){
          componentProperties.remove("Scrollable");
        }
      }
      else {
        componentProperties.put("Scrollable", new ClientJsonString("True"));
      }
      srcCompVersion = 13;
    }

    if (srcCompVersion < 15) {
      // The AppName property was added.
      // The Compatibility Mode property was added. No properties need to be modified to update to
      // version 7.
      srcCompVersion = 15;
    }
    if (srcCompVersion < 16) {
      // The ShowStatusBar property was added.
      // The TitleVisible property was added.
      srcCompVersion = 16;
    }
    if (srcCompVersion < 17) {
      // The CompatibilityMode property was added
      // When upgrading projects, turn on Compatbility Mode
      // NOTE: This change never saw production, but was on various
      // Test Instances
      componentProperties.put("CompatibilityMode", new ClientJsonString("True"));
      srcCompVersion = 17;
    }

    if (srcCompVersion < 18) {
      // Compatilibity Mode property turned into the Sizing property
      if (componentProperties.containsKey("CompatibilityMode")) {
        componentProperties.remove("CompatibilityMode");
      } else {
        componentProperties.put("Sizing", new ClientJsonString("Responsive"));
      }
      srcCompVersion = 18;
    }

    if (srcCompVersion < 19) {
      // Added HideKeyboard
      srcCompVersion = 19;
    }

    if (srcCompVersion < 20) {
      // The ShowistsAsJson Property was added.
      srcCompVersion = 20;
    }

    return srcCompVersion;
  }

  private static int upgradeFusiontablesControlProperties(Map<String, JSONValue> componentProperties,
      int srcCompVersion) {
    if (srcCompVersion < 2) {
      // No properties need to be modified to upgrade to version 2.
      // The ApiKey property and the SendQuery and ForgetLogin methods were added.
      srcCompVersion = 2;
    }
    if (srcCompVersion < 3) {
      // No properties need to be modified to upgrade to version 3.
      // GetRows, InsertRows and GetRowsWithConditions methods were added.
      // KeyFile, UseServiceAuthentication and ServiceAccountEmail properties
      // were added.
      srcCompVersion = 3;
    }
    return srcCompVersion;
  }

  private static int upgradeHorizontalArrangementProperties(Map<String, JSONValue> componentProperties,
      int srcCompVersion) {
    if (srcCompVersion < 2) {
      // The AlignHorizontal and AlignVertical properties were added. No blocks need to be modified
      // to upgrqde to version 2.
      srcCompVersion = 2;
    }
    if (srcCompVersion < 3) {
      // - Added background color & image
      srcCompVersion = 3;
    }
    return srcCompVersion;
  }

  private static int upgradeImageProperties(Map<String, JSONValue> componentProperties,
      int srcCompVersion) {
    if (srcCompVersion < 2) {
      // The RotationAngle property was added.
      // No properties need to be modified to upgrade to version 2.
      srcCompVersion = 2;
    }
    if (srcCompVersion < 3) {
      // ScalePictureToFit was replaced by Scaling property
      // Note: We will do this upgrade in a future release (jis: 2/12/2016)
      // if (componentProperties.containsKey("ScalePictureToFit")) {
      //   JSONValue propValue = componentProperties.remove("ScalePictureToFit");
      //   if (propValue.asString().getString().equals("True")) {
      //     // 1 corresponds to Scale to fit
      //     componentProperties.put("Scaling", new ClientJsonString("1"));
      //   }
      // }
      srcCompVersion = 3;
    }
    return srcCompVersion;
  }

  private static int upgradeImagePickerProperties(Map<String, JSONValue> componentProperties,
      int srcCompVersion) {
    if (srcCompVersion < 2) {
      // The Alignment property was renamed to TextAlignment.
      handlePropertyRename(componentProperties, "Alignment", "TextAlignment");
      // Properties related to this component have now been upgraded to version 2.
      srcCompVersion = 2;
    }
    if (srcCompVersion < 3) {
      // The Open method was added.  No changes are needed.
      srcCompVersion = 3;
    }
    if (srcCompVersion < 4) {
      // The Shape property was added.
      // No properties need to be modified to upgrade to version 4.
      srcCompVersion = 4;
    }
    if (srcCompVersion < 5) {
      // The ImagePath property was renamed to Selection.
      handlePropertyRename(componentProperties, "ImagePath", "Selection");
      // Properties related to this component have now been upgraded to version 2.
      srcCompVersion = 5;
    }
    return srcCompVersion;
  }

  private static int upgradeImageSpriteProperties(Map<String, JSONValue> componentProperties,
      int srcCompVersion) {
    if (srcCompVersion < 2) {
      // The SpriteComponent.Rotates property was added
      // No properties need to be modified to upgrade to version 2.
      srcCompVersion = 2;
    }
    if (srcCompVersion < 3) {
      // The Heading property was changed from int to Double
      srcCompVersion = 3;
    }
    if (srcCompVersion < 4) {
      // The Z property was added
      srcCompVersion = 4;
    }
    if (srcCompVersion < 5) {
      // The TouchUp, TouchDown, and Flung events were added. (for all sprites)
      // No properties need to be modified to upgrade to version 5.
      srcCompVersion = 5;
    }
    if (srcCompVersion < 6) {
      // The callback parameters speed and heading were added to Flung.
      srcCompVersion = 6;
    }
    return srcCompVersion;
  }

  private static int upgradeLabelProperties(Map<String, JSONValue> componentProperties,
      int srcCompVersion) {
    if (srcCompVersion < 2) {
      // The Alignment property was renamed to TextAlignment.
      handlePropertyRename(componentProperties, "Alignment", "TextAlignment");
      // Properties related to this component have now been upgraded to version 2.
      srcCompVersion = 2;
    }
    if (srcCompVersion < 4) {
      // The LabelFormat method was added.  No changes are needed. (3)
      // The HasMargins property was added. (4)
      componentProperties.put("HasMargins", new ClientJsonString("False"));
      srcCompVersion = 4;
    }
    return srcCompVersion;
  }

  private static int upgradeListPickerProperties(Map<String, JSONValue> componentProperties,
      int srcCompVersion) {
    if (srcCompVersion < 2) {
      // The Alignment property was renamed to TextAlignment.
      handlePropertyRename(componentProperties, "Alignment", "TextAlignment");
      // Properties related to this component have now been upgraded to version 2.
      srcCompVersion = 2;
    }
    if (srcCompVersion < 3) {
      // The SelectionIndex property was added.  No changes are needed.
      srcCompVersion = 3;
    }
    if (srcCompVersion < 4) {
      // The Open method was added.  No changes are needed.
      srcCompVersion = 4;
    }
    if (srcCompVersion < 5) {
      // The Shape property was added.
      // No properties need to be modified to upgrade to version 5.
      srcCompVersion = 5;
    }
    if (srcCompVersion < 6) {
      // The getIntent method was modified to add the parent Form's screen
      // animation type. No properties need to be modified to upgrade to
      // version 6.
      srcCompVersion = 6;
    }
    if (srcCompVersion < 7) {
      //  Added ShowFilterBar property
      srcCompVersion = 7;
    }
    if (srcCompVersion < 8) {
      //  Added title property
      srcCompVersion = 8;
    }
    if (srcCompVersion < 9) {
      // Added ItemTextColor, ItemBackgroundColor
      srcCompVersion = 9;
    }
    return srcCompVersion;
  }

  private static int upgradeListViewProperties(Map<String, JSONValue> componentProperties,
      int srcCompVersion) {
    if (srcCompVersion < 2) {
      // Added the Elements property
      srcCompVersion = 2;
    }
    if (srcCompVersion < 3) {
      // Added the BackgroundColor property
      // Added the TextColor property
      srcCompVersion = 3;
    }
    if (srcCompVersion < 4) {
      // Added the TextSize property
      srcCompVersion = 4;
    }
    if (srcCompVersion < 5) {
      // Added the SelectionColor property
      srcCompVersion = 5;
    }
    return srcCompVersion;
  }

  private static int upgradeLocationSensorProperties(Map<String, JSONValue> componentProperties,
      int srcCompVersion) {
    if (srcCompVersion < 3) {
      // Version 2:
      // The TimeInterval and DistanceInterval properties were added.
      // No properties need to be modified to upgrade to Version 2.
      // Version 3:
      // The speed parameter was added to the LocationChanged event
      srcCompVersion = 3;
    }
    return srcCompVersion;
  }

  private static int upgradeOrientationSensorProperties(
      Map<String, JSONValue> componentProperties, int srcCompVersion) {
    if (srcCompVersion < 2) {
      // The Yaw property was renamed to Azimuth.
      handlePropertyRename(componentProperties, "Yaw", "Azimuth");
      // Properties related to this component have now been upgraded to version 2.
      srcCompVersion = 2;
    }
    return srcCompVersion;
  }

  private static int upgradePasswordTextBoxProperties(Map<String, JSONValue> componentProperties,
      int srcCompVersion) {
    if (srcCompVersion < 2) {
      // The Alignment property was renamed to TextAlignment.
      handlePropertyRename(componentProperties, "Alignment", "TextAlignment");
      // Properties related to this component have now been upgraded to version 2.
      srcCompVersion = 2;
    }
    if (srcCompVersion < 3) {
      // Added RequestFocus Function (via TextBoxBase)
      srcCompVersion = 3;
    }
    return srcCompVersion;
  }

  private static int upgradePhoneCallProperties(Map<String, JSONValue> componentProperties,
      int srcCompVersion) {
    if (srcCompVersion < 2) {
      // The PhoneCallStarted event was added.
      // The PhoneCallEnded event was added.
      // The IncomingCallAnswered event was added.
      // No properties need to be modified to upgrade to version 2.
      srcCompVersion = 2;
    }
    return srcCompVersion;
  }

  private static int upgradePhoneNumberPickerProperties(Map<String, JSONValue> componentProperties,
      int srcCompVersion) {
    if (srcCompVersion < 2) {
      // The Alignment property was renamed to TextAlignment.
      handlePropertyRename(componentProperties, "Alignment", "TextAlignment");
      // Properties related to this component have now been upgraded to version 2.
      srcCompVersion = 2;
    }
    if (srcCompVersion < 3) {
      // The Open method was added.  No changes are needed.
      srcCompVersion = 3;
    }
    if (srcCompVersion < 4) {
      // The Shape property was added.
      // No properties need to be modified to upgrade to version 4.
      srcCompVersion = 4;
    }
    return srcCompVersion;
  }

  private static int upgradePlayerProperties(Map<String, JSONValue> componentProperties,
      int srcCompVersion) {
    if (srcCompVersion < 2) {
      // The Player.PlayerError event was added.
      // No properties need to be modified to upgrade to version 2.
      srcCompVersion = 2;
    }
    if (srcCompVersion < 3) {
      // The Player.PlayerError event was marked userVisible false and is no longer used.
      // No properties need to be modified to upgrade to version 3.
      srcCompVersion = 3;
    }
    if (srcCompVersion < 4) {
      // The Looping and Volume properties were added.
      // The Completed Event was added.
      // The IsPlaying method was added.
      // No properties need to be modified to upgrade to version 4.
      srcCompVersion = 4;
    }
    if (srcCompVersion < 5) {
      // The IsPlaying method was renamed to Loop.
      handlePropertyRename(componentProperties, "IsLooping", "Loop");
      // Properties related to this component have now been upgraded to version  5.
      srcCompVersion = 5;
    }
    if (srcCompVersion < 6) {
        // The PlayInForeground method was added.
        // The OtherPlayerStarted event was added.
        // Properties related to this component have now been upgraded to version  6.
        srcCompVersion = 6;
      }
    return srcCompVersion;
  }

  private static int upgradeSoundProperties(Map<String, JSONValue> componentProperties,
      int srcCompVersion) {
    if (srcCompVersion < 2) {
      // The Sound.SoundError event was added.
      // No properties need to be modified to upgrade to version 2.
      srcCompVersion = 2;
    }
    if (srcCompVersion < 3) {
      // The Sound.SoundError event was marked userVisible false and is no longer used.
      // No properties need to be modified to upgrade to version 3.
      srcCompVersion = 3;
    }
    return srcCompVersion;
  }

  private static int upgradeSoundRecorderProperties(Map<String, JSONValue> componentProperties,
      int srcCompVersion) {
    if (srcCompVersion < 2) {
      // The SoundRecorder.RecordFile property was added.
      // No properties need to be modified to upgrade to version 2.
      srcCompVersion = 2;
    }
    return srcCompVersion;
  }


  private static int upgradeTimePickerProperties(Map<String, JSONValue> componentProperties,
      int srcCompVersion) {
    if (srcCompVersion < 2) {
      // The SetTimeToDisplay and LaunchPicker methods were added.
      // No properties need to be modified to upgrade to version 2.
      srcCompVersion = 2;
    }
    if (srcCompVersion < 3) {
      // SetTimeToDisplayFromInstant, and Instant property are added.
      // No properties need to be modified to upgrade to version 3.
      srcCompVersion = 3;
    }
    return srcCompVersion;
  }

  private static int upgradeTinyWebDBProperties(Map<String, JSONValue> componentProperties,
      int srcCompVersion) {
    if (srcCompVersion < 2) {
      // The TinyWebDB.ShowAlert method was removed. Notifier.ShowAlert should be used instead.
      // No properties need to be modified to upgrade to version 2.
      srcCompVersion = 2;
    }
    return srcCompVersion;
  }

  private static int upgradeVerticalArrangementProperties(Map<String, JSONValue> componentProperties,
      int srcCompVersion) {
    if (srcCompVersion < 2) {
      // The AlignHorizontal and AlignVertical properties were added. No blocks need to be modified
      // to upgrqde to version 2.
      srcCompVersion = 2;
    }
    if (srcCompVersion < 3) {
      // - Added background color & image
      srcCompVersion = 3;
    }
    return srcCompVersion;
  }

  private static int upgradeNotifierProperties(Map<String, JSONValue> componentProperties,
                                                  int srcCompVersion) {
    if (srcCompVersion < 2) {
      // A new boolean socket was added to allow canceling out of ShowChooseDialog
      // and ShowTextDialog
      srcCompVersion = 2;
    }
    if (srcCompVersion < 3) {
      // The BackgroundColor, NotifierLength, and TextColor options were added.
      // No properties need to be modified to upgrade to version 3.
      srcCompVersion = 3;
    }
    if (srcCompVersion < 4) {
      // A new type of dialog was created, a ProgressDialog, and a method to
      // dismiss the dialog was also added.
      srcCompVersion = 4;
    }
    return srcCompVersion;
  }

  private static int upgradeVideoPlayerProperties(Map<String, JSONValue> componentProperties,
      int srcCompVersion) {
    if (srcCompVersion < 2) {
      // The VideoPlayer.VideoPlayerError event was added.
      // No properties need to be modified to upgrade to version 2.
      srcCompVersion = 2;
    }
    if (srcCompVersion < 3) {
      // The VideoPlayer.VideoPlayerError event was marked userVisible false and is no longer used.
      // No properties need to be modified to upgrade to version 3.
      srcCompVersion = 3;
    }
    if (srcCompVersion < 4) {
      // The VideoPlayer.height and VideoPlayer.width getter and setters were marked as
      // visible to the user.
      // The FullScreen property was created.
      // No properties need to be modified to upgrade to version 4.
      srcCompVersion = 4;
    }
    if (srcCompVersion < 5) {
        // The Volume property (setter only) was created.
        // No properties need to be modified to upgrade to version 4.
        srcCompVersion = 5;
      }
    return srcCompVersion;
  }

  private static int upgradeTwitterProperties(Map<String, JSONValue> componentProperties,
      int srcCompVersion) {
    if (srcCompVersion < 2) {
      // The designer properties ConsumerKey and ConsumerSecret were added
      // No properties need to be modified to upgrade to version 2.
      srcCompVersion = 2;
    }
    if (srcCompVersion < 3) {
      // The designer property TwitPic_API_Key was added
      // No properties need to be modified to upgrade to version 3.
      srcCompVersion = 3;
    }
    if (srcCompVersion < 4) {
      // The designer property TwitPic_API_Key and functions are hidden and deprecated.
      // No properties need to be modified to upgrade to version 4.
      srcCompVersion = 4;
    }
    return srcCompVersion;
  }

  private static int upgradeTextingProperties(Map<String, JSONValue> componentProperties,
                                              int srcCompVersion) {
    if (srcCompVersion < 2) {
      // The designer property GoogleVoiceEnabled was added
      // No properties need to be modified to upgrade to version 2.
      srcCompVersion = 2;
    }
    if (srcCompVersion < 3) {
      if (componentProperties.containsKey("ReceivingEnabled")) {
        JSONValue receivingEnabled = componentProperties.get("ReceivingEnabled");
        String receivingString = receivingEnabled.asString().getString();
        if (receivingString.equals("true")) {
          componentProperties.put("ReceivingEnabled", new ClientJsonString("2"));
        } else {
          componentProperties.put("ReceivingEnabled", new ClientJsonString("1"));
        }
      }
      srcCompVersion = 3;
    }

    return srcCompVersion;
  }

  private static int upgradeTextBoxProperties(Map<String, JSONValue> componentProperties,
      int srcCompVersion) {
    if (srcCompVersion < 2) {
      // The property (and designer property) TextBox.NumbersOnly was added
      // No properties need to be modified to upgrade to version 2.
      srcCompVersion = 2;
    }
    if (srcCompVersion < 3) {
      // The Alignment property was renamed to TextAlignment.
      handlePropertyRename(componentProperties, "Alignment", "TextAlignment");
      // Properties related to this component have now been upgraded to version 3.
      srcCompVersion = 3;
    }

    if (srcCompVersion < 4) {
      // The MultiLine property was added.
      // The default for Multiline from now on is false, but up until now,
      // all text boxes have been multiline.
      // We need to set the MultiLine to true when we upgrade old projects.
      componentProperties.put("MultiLine", new ClientJsonString("True"));
      // Properties related to this component have now been upgraded to version 4.
      srcCompVersion = 4;
    }
    if (srcCompVersion < 5) {
      // RequestFocus method was added
      srcCompVersion = 5;
    }
    return srcCompVersion;
  }

  private static int upgradeWebProperties(Map<String, JSONValue> componentProperties,
                                          int srcCompVersion) {
    if (srcCompVersion < 2) {
      // The RequestHeaders and AllowCookies properties were added.
      // The BuildPostData and ClearCookies methods were added.
      // The existing PostText method was renamed to PostTextWithEncoding, and a new PostText
      // method was added.
      // No properties need to be modified to upgrade to version 2.
      srcCompVersion = 2;
    }
    if (srcCompVersion < 3) {
      // The methods PutText, PutTextWithEncoding, PutFile and Delete were added.
      // The method BuildPostData was renamed to BuildRequestData.
      // No properties need to be modified to upgrade to version 3.
      srcCompVersion = 3;
    }
    if (srcCompVersion < 4) {
      // The XMLTextDecode method was added.
      // No properties need to be modified to upgrade to version 4.
      srcCompVersion = 4;
    }
    return srcCompVersion;
  }

  private static int upgradeWebViewerProperties(Map<String, JSONValue> componentProperties,
                                                int srcCompVersion) {
    if (srcCompVersion < 6) {
      // The CanGoForward and CanGoBack methods were added.
      // No properties need to be modified to upgrade to version 2.
      // UsesLocation property added.
      // No properties need to be modified to upgrade to version 3.
      // WebViewString added
      // No properties need to be modified to upgrade to version 4.
      // IgnoreSslError property added (version 5)
      // ClearCaches method was added (version 6)
      srcCompVersion = 6;
    }
    return srcCompVersion;
  }

  private static int upgradeFirebaseDBProperties(Map<String, JSONValue> componentProperties,
    int srcCompVersion) {
    if (srcCompVersion < 3) {
      // Version 2
      // Added AppendValue, RemoveFirst and FirstRemoved
      // Version 3
      // Added RemoveValue, GetTagList and Persist
      srcCompVersion = 3;
    }
    return srcCompVersion;
  }

  private static int upgradePedometerProperties(Map<String, JSONValue> componentProperties,
    int srcCompVersion) {
    if (srcCompVersion < 2) {
      // The step sensing algorithm was updated to be more accurate.
      // The GPS related functionality was removed.
      srcCompVersion = 2;
    }
    return srcCompVersion;
  }

  private static void handlePropertyRename(Map<String, JSONValue> componentProperties,
      String oldPropName, String newPropName) {
    if (componentProperties.containsKey(oldPropName)) {
      componentProperties.put(newPropName, componentProperties.remove(oldPropName));
    }
  }

  private static void handleSupplyValueForPreviouslyDefaultedProperty(
      Map<String, JSONValue> componentProperties,
      String PropName, JSONValue valueToSupply) {
    // if the property wasn't previously there as a key, the previous value was
    // the default value
    if (!(componentProperties.containsKey(PropName))) {
      componentProperties.put(PropName, valueToSupply);
    }
  }

  private static void upgradeWarnDialog(String aMessage) {
    final DialogBox dialogBox = new DialogBox(false, true);
    dialogBox.setStylePrimaryName("ode-DialogBox");
    dialogBox.setText(MESSAGES.warningDialogTitle());
    dialogBox.setGlassEnabled(true);
    dialogBox.setAnimationEnabled(true);
    final HTML message = new HTML(aMessage);
    message.setStyleName("DialogBox-message");
    VerticalPanel vPanel = new VerticalPanel();
    Button okButton = new Button("OK");
    okButton.addClickListener(new ClickListener() {
        @Override
        public void onClick(Widget sender) {
          dialogBox.hide();
        }
      });
    vPanel.add(message);
    vPanel.add(okButton);
    dialogBox.setWidget(vPanel);
    dialogBox.center();
    dialogBox.show();
  }

}