/**
   * Method updateTargetFile.
   *
   * @param aFile IFile
   * @return IFile
   * @throws CoreException
   * @throws ReviewsFileStorageException
   */
  public static R4EFileVersion updateTargetFile(IFile aFile)
      throws CoreException, ReviewsFileStorageException {

    if (null == aFile) {
      return null; // should never happen
    }

    String remoteID = null;
    String localID = null;

    // Get handle to local storage repository
    final IRFSRegistry localRepository =
        RFSRegistryFactory.getRegistry(R4EUIModelController.getActiveReview().getReview());
    if (null == localRepository) {
      return null;
    }
    // Get Remote repository file info
    final ScmConnector connector = ScmCore.getConnector(aFile.getProject());
    if (null != connector) {
      final ScmArtifact artifact = connector.getArtifact(aFile);
      if ((null != artifact) && (null != artifact.getPath())) {
        // File found in remote repo.

        // Here we check if the file in the remote repository is different than the input file.
        // We cannot use the artifact ID directly and we need to fetch and calculate that SHA of the
        // remote file
        // because we do not know which version control system is used.
        // We need to do this comparison because the versions always return the latest file stored.

        final IFileRevision fileRev = artifact.getFileRevision(null);
        if (null != fileRev) {
          final IStorage fileStore = fileRev.getStorage(null);
          if (null != fileStore) {
            remoteID = localRepository.blobIdFor(fileStore.getContents());
            localID = localRepository.blobIdFor(aFile.getContents());
            if ((null != remoteID) && remoteID.equals(localID)) {
              // The files are the same. Copy from the remote repo
              return copyRemoteFileToLocalRepository(localRepository, artifact);
            }
          }
        }
        // The files are different.  This means the current user modified the file in his workspace
        return copyWorkspaceFileToLocalRepository(localRepository, aFile);
      }
    }
    // Else we copy the file that is in the current workspace
    return copyWorkspaceFileToLocalRepository(localRepository, aFile);
  }
  /**
   * Method copyRemoteFileToLocalRepository.
   *
   * @param aLocalRepository IRFSRegistry
   * @param aArtifact ScmArtifact
   * @return IFile
   * @throws CoreException
   * @throws ReviewsFileStorageException
   */
  public static R4EFileVersion copyRemoteFileToLocalRepository(
      IRFSRegistry aLocalRepository, ScmArtifact aArtifact)
      throws ReviewsFileStorageException, CoreException {

    if ((null == aArtifact)
        || (null == aArtifact.getPath())
        || aArtifact.getPath().equals(INVALID_PATH)) {
      return null; // File not found in remote repository
    }
    final IFileRevision fileRev = aArtifact.getFileRevision(null);
    if (null == fileRev) {
      return null;
    }

    // Pull file from the version control system
    InputStream iStream = null;
    final IStorage fileStore = fileRev.getStorage(null);
    if (null == fileStore) {
      return null;
    }
    try {
      iStream = fileStore.getContents();
    } catch (CoreException e) {
      R4EUIPlugin.Ftracer.traceInfo("Exception: " + e.toString() + " (" + e.getMessage() + ")");
      return null;
    }

    // Create and Set value in temporary File version
    final R4EFileVersion tmpFileVersion = RModelFactory.eINSTANCE.createR4EFileVersion();
    if ((null != tmpFileVersion) && (null != aLocalRepository)) {
      updateFileVersion(tmpFileVersion, aArtifact);

      // Push a local copy to local review repository, and obtain the local id
      tmpFileVersion.setLocalVersionID(aLocalRepository.registerReviewBlob(iStream));
      if (null != iStream) {
        try {
          iStream.close();
        } catch (IOException e) {
          R4EUIPlugin.Ftracer.traceWarning("Exception while closing stream, " + e.toString());
        }
      }
    }
    return tmpFileVersion;
  }
  /**
   * Method updateBaseFile.
   *
   * @param aFile IFile
   * @return IFile
   * @throws CoreException
   * @throws ReviewsFileStorageException
   */
  public static R4EFileVersion updateBaseFile(IFile aFile)
      throws CoreException, ReviewsFileStorageException {
    if (null == aFile) {
      return null; // should never happen
    }

    // Get Remote repository file info
    final ScmConnector connector = ScmCore.getConnector(aFile.getProject());
    if (null != connector) {
      final ScmArtifact artifact = connector.getArtifact(aFile);
      if ((null != artifact) && (null != artifact.getId())) {
        // File was modified, so we need to fetch the base file from the versions repository and
        // copy it to our own local repository
        final IRFSRegistry localRepository =
            RFSRegistryFactory.getRegistry(R4EUIModelController.getActiveReview().getReview());
        return copyRemoteFileToLocalRepository(localRepository, artifact);
      }
    } // else file not in source control

    // File was not modified, or No Version Control System or Remote File detected, so there is no
    // base
    return null;
  }
  /**
   * Method updateFileVersion
   *
   * @param aTargetFileVer R4EFileVersion
   * @param aScmArt ScmArtifact
   * @throws CoreException
   */
  public static void updateFileVersion(R4EFileVersion aTargetFileVer, ScmArtifact aScmArt)
      throws CoreException {

    if ((null != aTargetFileVer) && (null != aScmArt)) {
      aTargetFileVer.setName(aScmArt.getFileRevision(null).getName());
      aTargetFileVer.setVersionID(aScmArt.getId());
      final IFileRevision fileRev = aScmArt.getFileRevision(null);
      if (null != fileRev) {
        final IStorage fileStore = fileRev.getStorage(null);
        if (null != fileStore) {
          final IPath filePath = fileStore.getFullPath();
          if (null != filePath) {
            aTargetFileVer.setRepositoryPath(filePath.toPortableString());
          }
        }
      }

      final String fileRelPath = aScmArt.getProjectRelativePath();
      if (null == fileRelPath) {
        R4EUIPlugin.Ftracer.traceDebug(
            "Invalid relative file path in scmArtifact with path: " + aScmArt.getPath());
      }
      final IProject project = ResourceUtils.getProject(aScmArt.getProjectName());
      final IResource resource = ResourceUtils.findResource(project, fileRelPath);

      aTargetFileVer.setPlatformURI(ResourceUtils.toPlatformURIStr(resource));
      aTargetFileVer.setResource(resource);

      final String projPlatformURI = ResourceUtils.toPlatformURIStr(project);
      if (null == projPlatformURI) {
        R4EUIPlugin.Ftracer.traceDebug(
            "Unable to resolve the project: "
                + aScmArt.getProjectName()
                + " platform's URI, in scmArtifact with path: "
                + aScmArt.getPath());
      }
    }
  }
  /**
   * Method copyRemoteFileToLocalRepository.
   *
   * @param aLock ReentrantLock
   * @param aLocalRepository IRFSRegistry
   * @param aArtifact ScmArtifact
   * @param aMainMonitor IProgressMonitor
   * @param aSubMonitor IProgressMonitor
   * @return IFile
   * @throws CoreException
   * @throws ReviewsFileStorageException
   * @throws MainJobCancelledException
   * @throws SubJobCancelledException
   */
  public static R4EFileVersion copyRemoteFileToLocalRepository(
      ReentrantLock aLock,
      IRFSRegistry aLocalRepository,
      ScmArtifact aArtifact,
      IProgressMonitor aMainMonitor)
      throws ReviewsFileStorageException, CoreException {
    ReentrantLock lock = aLock;
    if (null == lock) {
      lock = new ReentrantLock();
    }

    // Check if Main Job or Sub Job was cancelled before fetching
    if (aMainMonitor.isCanceled()) {
      throw new CoreException(
          new Status(
              IStatus.CANCEL,
              R4EUIPlugin.PLUGIN_ID,
              IStatus.CANCEL,
              R4EUIConstants.CANCEL_EXCEPTION_MSG,
              null));
    }

    if ((null == aArtifact)
        || (null == aArtifact.getPath())
        || aArtifact.getPath().equals(INVALID_PATH)) {
      return null; // File not found in remote repository
    }

    // Tracing benchmarks
    Date fetchStart = null;
    if (Tracer.isInfo()) {
      fetchStart = new Date();
    }

    final IFileRevision fileRev = aArtifact.getFileRevision(null);
    if (null == fileRev) {
      return null;
    }

    // Pull file from the version control system
    InputStream iStream = null;
    final IStorage fileStore = fileRev.getStorage(null);
    if (null == fileStore) {
      return null;
    }
    try {
      iStream = fileStore.getContents();
    } catch (CoreException e) {
      R4EUIPlugin.Ftracer.traceInfo("Exception: " + e.toString() + " (" + e.getMessage() + ")");
      return null;
    }

    // Create and Set value in temporary File version
    final R4EFileVersion tmpFileVersion = RModelFactory.eINSTANCE.createR4EFileVersion();
    if ((null != tmpFileVersion) && (null != aLocalRepository)) {
      updateFileVersion(tmpFileVersion, aArtifact);

      // Check if Main Job or Sub Job was cancelled before pushing a local copy
      if (aMainMonitor.isCanceled()) {
        throw new CoreException(
            new Status(
                IStatus.CANCEL,
                R4EUIPlugin.PLUGIN_ID,
                IStatus.CANCEL,
                R4EUIConstants.CANCEL_EXCEPTION_MSG,
                null));
      }

      // Tracing benchmarks
      Date blobRegStart = null;
      if (fetchStart != null) {
        blobRegStart = new Date();
      }

      // Push a local copy to local review repository, and obtain the local id
      lock.lock();
      try {
        tmpFileVersion.setLocalVersionID(aLocalRepository.registerReviewBlob(iStream));
      } finally {
        lock.unlock();

        if (fetchStart != null) {
          long downloadTime = blobRegStart.getTime() - fetchStart.getTime();
          long uploadTime = (new Date()).getTime() - blobRegStart.getTime();
          R4EUIPlugin.Ftracer.traceInfo(
              "Registered blob for "
                  + fileRev.getName()
                  + " "
                  + //$NON-NLS-1$//$NON-NLS-2$
                  aArtifact.getId()
                  + ", fetch (ms): "
                  + downloadTime
                  + ", push (ms) "
                  + uploadTime); //$NON-NLS-1$ //$NON-NLS-2$
        }

        if (null != iStream) {
          try {
            iStream.close();
          } catch (IOException e) {
            R4EUIPlugin.Ftracer.traceWarning("Exception while closing stream, " + e.toString());
          }
        }
      }
    }
    return tmpFileVersion;
  }