/**
   * Returns whether a given library project is needed by the receiver.
   *
   * <p>If the library is needed, this finds the matching {@link LibraryState}, initializes it so
   * that it contains the library's {@link IProject} object (so that {@link
   * LibraryState#getProjectState()} does not return null) and then returns it.
   *
   * @param libraryProject the library project to check.
   * @return a non null object if the project is a library dependency, <code>null</code> otherwise.
   * @see LibraryState#getProjectState()
   */
  public LibraryState needs(ProjectState libraryProject) {
    // compute current location
    File projectFile = mProject.getLocation().toFile();

    // get the location of the library.
    File libraryFile = libraryProject.getProject().getLocation().toFile();

    // loop on all libraries and check if the path match
    synchronized (mLibraries) {
      for (LibraryState state : mLibraries) {
        if (state.getProjectState() == null) {
          File library = new File(projectFile, state.getRelativePath());
          try {
            File absPath = library.getCanonicalFile();
            if (absPath.equals(libraryFile)) {
              state.setProject(libraryProject);
              return state;
            }
          } catch (IOException e) {
            // ignore this library
          }
        }
      }
    }

    return null;
  }
    private void setProject(ProjectState project) {
      mProjectState = project;
      mPath = project.getProject().getLocation().toOSString();
      mProjectState.addParentProject(getMainProjectState());

      getMainProjectState().updateFullLibraryList();
    }
  @Override
  public Change createChange(IProgressMonitor pm) throws CoreException, OperationCanceledException {
    if (pm.isCanceled()) {
      return null;
    }
    if (!getArguments().getUpdateReferences()) {
      return null;
    }
    CompositeChange result = new CompositeChange(getName());
    result.markAsSynthetic();

    addManifestFileChanges(result);

    // Update layout files; we don't just need to react to custom view
    // changes, we need to update fragment references and even tool:context activity
    // references
    addLayoutFileChanges(mProject, result);

    // Also update in dependent projects
    ProjectState projectState = Sdk.getProjectState(mProject);
    if (projectState != null) {
      Collection<ProjectState> parentProjects = projectState.getFullParentProjects();
      for (ProjectState parentProject : parentProjects) {
        IProject project = parentProject.getProject();
        addLayoutFileChanges(project, result);
      }
    }

    return (result.getChildren().length == 0) ? null : result;
  }
  /**
   * Returns the {@link LibraryState} object for a given <var>name</var>. This can only return a
   * non-null object if the link between the main project's {@link IProject} and the library's
   * {@link IProject} was done.
   *
   * @return the matching LibraryState or <code>null</code>
   * @see #needs(IProject)
   */
  public LibraryState getLibrary(String name) {
    synchronized (mLibraries) {
      for (LibraryState state : mLibraries) {
        ProjectState ps = state.getProjectState();
        if (ps != null && ps.getProject().getName().equals(name)) {
          return state;
        }
      }
    }

    return null;
  }
  /**
   * Returns the {@link LibraryState} object for a given {@link IProject}. This can only return a
   * non-null object if the link between the main project's {@link IProject} and the library's
   * {@link IProject} was done.
   *
   * @return the matching LibraryState or <code>null</code>
   * @see #needs(ProjectState)
   */
  public LibraryState getLibrary(IProject library) {
    synchronized (mLibraries) {
      for (LibraryState state : mLibraries) {
        ProjectState ps = state.getProjectState();
        if (ps != null && ps.getProject().equals(library)) {
          return state;
        }
      }
    }

    return null;
  }
  /**
   * Resolves a given list of libraries, finds out if they depend on other libraries, and returns a
   * full list of all the direct and indirect dependencies in the proper order (first is higher
   * priority when calling aapt).
   *
   * @param inLibraries the libraries to resolve
   * @param outLibraries where to store all the libraries.
   */
  private void buildFullLibraryDependencies(
      List<LibraryState> inLibraries, ArrayList<IProject> outLibraries) {
    // loop in the inverse order to resolve dependencies on the libraries, so that if a library
    // is required by two higher level libraries it can be inserted in the correct place
    for (int i = inLibraries.size() - 1; i >= 0; i--) {
      LibraryState library = inLibraries.get(i);

      // get its libraries if possible
      ProjectState libProjectState = library.getProjectState();
      if (libProjectState != null) {
        List<LibraryState> dependencies = libProjectState.getLibraries();

        // build the dependencies for those libraries
        buildFullLibraryDependencies(dependencies, outLibraries);

        // and add the current library (if needed) in front (higher priority)
        if (outLibraries.contains(libProjectState.getProject()) == false) {
          outLibraries.add(0, libProjectState.getProject());
        }
      }
    }
  }
  /**
   * Returns whether the project depends on a given <var>library</var>
   *
   * @param library the library to check.
   * @return true if the project depends on the library. This is not affected by whether the link
   *     was done through {@link #needs(ProjectState)}.
   */
  public boolean dependsOn(ProjectState library) {
    synchronized (mLibraries) {
      for (LibraryState state : mLibraries) {
        if (state != null
            && state.getProjectState() != null
            && library.getProject().equals(state.getProjectState().getProject())) {
          return true;
        }
      }
    }

    return false;
  }