/**
  * Return the ConfiguratorConfigFile which is determined by the parameters set in Manipulator.
  *
  * @param manipulator
  * @return File
  */
 private static File getConfigFile(Manipulator manipulator) throws IllegalStateException {
   File fwConfigLoc = manipulator.getLauncherData().getFwConfigLocation();
   File baseDir = null;
   if (fwConfigLoc == null) {
     baseDir = manipulator.getLauncherData().getHome();
     if (baseDir == null) {
       if (manipulator.getLauncherData().getLauncher() != null) {
         baseDir = manipulator.getLauncherData().getLauncher().getParentFile();
       } else {
         throw new IllegalStateException(
             "All of fwConfigFile, home, launcher are not set."); //$NON-NLS-1$
       }
     }
   } else {
     if (fwConfigLoc.exists())
       if (fwConfigLoc.isDirectory()) baseDir = fwConfigLoc;
       else baseDir = fwConfigLoc.getParentFile();
     else {
       // TODO We need to decide whether launcher data configLocation is the location of a file or
       // a directory
       if (fwConfigLoc.getName().endsWith(".ini")) // $NON-NLS-1$
       baseDir = fwConfigLoc.getParentFile();
       else baseDir = fwConfigLoc;
     }
   }
   File configuratorFolder =
       new File(baseDir, SimpleConfiguratorManipulatorImpl.CONFIGURATOR_FOLDER);
   File targetFile = new File(configuratorFolder, SimpleConfiguratorManipulatorImpl.CONFIG_LIST);
   if (!Utils.createParentDir(targetFile)) return null;
   return targetFile;
 }
  public BundleInfo[] save(Manipulator manipulator, boolean backup) throws IOException {
    List setToInitialConfig = new LinkedList();
    List setToSimpleConfig = new LinkedList();
    ConfigData configData = manipulator.getConfigData();

    if (!divideBundleInfos(
        manipulator,
        setToInitialConfig,
        setToSimpleConfig,
        configData.getInitialBundleStartLevel())) return configData.getBundles();

    File outputFile = getConfigFile(manipulator);
    URI installArea =
        ParserUtils.getOSGiInstallArea(
                Arrays.asList(manipulator.getLauncherData().getProgramArgs()),
                manipulator.getConfigData().getProperties(),
                manipulator.getLauncherData())
            .toURI();
    saveConfiguration(
        (BundleInfo[]) setToSimpleConfig.toArray(new BundleInfo[setToSimpleConfig.size()]),
        outputFile,
        installArea,
        backup);
    configData.setProperty(
        SimpleConfiguratorManipulatorImpl.PROP_KEY_CONFIGURL, outputFile.toURL().toExternalForm());
    return orderingInitialConfig(setToInitialConfig);
  }
  private boolean divideBundleInfos(
      Manipulator manipulator,
      List setToInitialConfig,
      List setToSimpleConfig,
      final int initialBSL) {
    BundlesState state = manipulator.getBundlesState();
    BundleInfo[] targetBundleInfos = null;
    if (state.isFullySupported()) {
      targetBundleInfos = state.getExpectedState();
    } else {
      targetBundleInfos = manipulator.getConfigData().getBundles();
    }
    BundleInfo configuratorBInfo = null;
    for (int i = 0; i < targetBundleInfos.length; i++) {
      if (isTargetConfiguratorBundle(targetBundleInfos[i].getLocation())) {
        if (targetBundleInfos[i].isMarkedAsStarted()) {
          configuratorBInfo = targetBundleInfos[i];
          break;
        }
      }
    }
    if (configuratorBInfo == null && !manipulators.contains(manipulator)) {
      return false;
    } else if (manipulators.contains(manipulator) && targetBundleInfos.length == 0) {
      // Resulting state will have no bundles - so is an uninstall, including
      // uninstall of the configurator. However, we have seen this manipulator
      // before with a target configurator bundle, so allow uninstall to proceed,
      // but only get one chance.
      manipulators.remove(manipulator);
    } else if (!manipulators.contains(manipulator)) {
      manipulators.add(manipulator);
    }

    if (state.isFullySupported()) {
      state.resolve(false);
    }

    LocationInfo info = new LocationInfo();
    setSystemBundles(state, info);
    if (configuratorBInfo != null) {
      setPrerequisiteBundles(configuratorBInfo, state, info);
      SortedMap bslToList = getSortedMap(initialBSL, targetBundleInfos);
      algorithm(
          initialBSL, bslToList, configuratorBInfo, setToInitialConfig, setToSimpleConfig, info);
    }
    return true;
  }
  public void updateBundles(Manipulator manipulator) throws IOException {
    if (DEBUG)
      System.out.println("SimpleConfiguratorManipulatorImpl#updateBundles()"); // $NON-NLS-1$

    BundlesState bundleState = manipulator.getBundlesState();

    if (bundleState == null) return;
    if (bundleState.isFullySupported()) bundleState.resolve(true);

    BundleInfo[] currentBInfos = bundleState.getExpectedState();
    if (!isTargetConfiguratorBundle(currentBInfos)) return;
    Properties properties = new Properties();
    String[] jvmArgs = manipulator.getLauncherData().getJvmArgs();
    for (int i = 0; i < jvmArgs.length; i++) {
      if (jvmArgs[i].startsWith("-D")) { // $NON-NLS-1$
        int index = jvmArgs[i].indexOf("="); // $NON-NLS-1$
        if (index > 0 && jvmArgs[i].length() > 2) {
          String key = jvmArgs[i].substring(2, index);
          String value = jvmArgs[i].substring(index + 1);
          properties.setProperty(key, value);
        }
      }
    }

    Utils.appendProperties(properties, manipulator.getConfigData().getProperties());
    boolean exclusiveInstallation =
        Boolean.valueOf(
                properties.getProperty(
                    SimpleConfiguratorManipulatorImpl.PROP_KEY_EXCLUSIVE_INSTALLATION))
            .booleanValue();
    File configFile = getConfigFile(manipulator);

    File installArea =
        ParserUtils.getOSGiInstallArea(
            Arrays.asList(manipulator.getLauncherData().getProgramArgs()),
            manipulator.getConfigData().getProperties(),
            manipulator.getLauncherData());
    BundleInfo[] toInstall = new BundleInfo[0];

    boolean isShared = isSharedInstallSetup(installArea, configFile);
    if (!isShared
        || (isShared && !hasBaseChanged(installArea.toURI(), configFile.getParentFile()))) {
      try {
        // input stream will be closed for us
        toInstall = loadConfiguration(new FileInputStream(configFile), installArea.toURI());
      } catch (FileNotFoundException e) {
        // no file, just return an empty list
        toInstall = new BundleInfo[0];
      }
    }

    List toUninstall = new LinkedList();
    if (exclusiveInstallation)
      for (int i = 0; i < currentBInfos.length; i++) {
        boolean install = false;
        for (int j = 0; j < toInstall.length; j++)
          if (currentBInfos[i].getLocation().equals(toInstall[j].getLocation())) {
            install = true;
            break;
          }
        if (!install) toUninstall.add(currentBInfos[i]);
      }

    for (int i = 0; i < toInstall.length; i++) {
      try {
        bundleState.installBundle(toInstall[i]);
      } catch (RuntimeException e) {
        // Ignore
      }
    }
    if (exclusiveInstallation)
      for (Iterator ite = toUninstall.iterator(); ite.hasNext(); ) {
        BundleInfo bInfo = (BundleInfo) ite.next();
        bundleState.uninstallBundle(bInfo);
      }

    bundleState.resolve(true);
    manipulator.getConfigData().setBundles(bundleState.getExpectedState());
  }