gt:           && version != FORMAT_VERSION_3
context: /**
   * ***************************************************************************** Copyright (c) 2005,
   * 2006 Subclipse project and others. All rights reserved. This program and the accompanying
   * materials are made available under the terms of the Eclipse Public License v1.0 which accompanies
   * this distribution, and is available at http://www.eclipse.org/legal/epl-v10.html
   *
   * <p>Contributors: Subclipse project committers - initial API and implementation
   * ****************************************************************************
   */
  package org.tigris.subversion.subclipse.core.resources;
  
  import java.io.ByteArrayInputStream;
  import java.io.ByteArrayOutputStream;
  import java.io.DataInputStream;
  import java.io.File;
  import java.io.IOException;
  import java.io.Serializable;
  import java.net.MalformedURLException;
  import java.util.ArrayList;
  import java.util.Date;
  import java.util.List;
  import org.eclipse.core.resources.IContainer;
  import org.eclipse.core.resources.ResourcesPlugin;
  import org.eclipse.core.runtime.IPath;
  import org.eclipse.core.runtime.Path;
  import org.tigris.subversion.subclipse.core.ISVNLocalFolder;
  import org.tigris.subversion.subclipse.core.ISVNRepositoryLocation;
  import org.tigris.subversion.subclipse.core.SVNException;
  import org.tigris.subversion.subclipse.core.SVNProviderPlugin;
  import org.tigris.subversion.svnclientadapter.ISVNStatus;
  import org.tigris.subversion.svnclientadapter.SVNConflictDescriptor;
  import org.tigris.subversion.svnclientadapter.SVNConflictVersion;
  import org.tigris.subversion.svnclientadapter.SVNNodeKind;
  import org.tigris.subversion.svnclientadapter.SVNRevision;
  import org.tigris.subversion.svnclientadapter.SVNRevision.Number;
  import org.tigris.subversion.svnclientadapter.SVNStatusKind;
  import org.tigris.subversion.svnclientadapter.SVNUrl;
  
  /**
   * This class has an interface which is very similar to ISVNStatus but we make sure to take as
   * little memory as possible. This class also have a getBytes() method and a constructor/factory
   * method that takes bytes. (However, the bytes are not complete representation of this status, just
   * subset of interesting attributes)
   *
   * <p>This class and neither its LocalResourceStatus which is stored in the workspace metadata does
   * NOT stores resource revision intentionally. The revision numbers changes too frequently and it
   * does not provide too valuable imformation for synchronization needs anyway. The
   * lastChangedRevision() is more important here.
   *
   * @see org.tigris.subversion.svnclientadapter.ISVNStatus
   */
  public abstract class ResourceStatus implements ISVNStatus, Serializable {
  
    static final long serialVersionUID = 1L;
  
    protected static final int FORMAT_VERSION_1 = 1;
    protected static final int FORMAT_VERSION_2 = 2;
    protected static final int FORMAT_VERSION_3 = 3;
    protected static final int FORMAT_VERSION_4 = 4;
    protected static final int FORMAT_VERSION_5 = 5;
  
    protected String url;
    protected File
        file; // file (absolute path) -- not stored in bytes in this class. Subclasses may store it
              // ...
    protected long lastChangedRevision;
    protected long lastChangedDate;
    protected String lastCommitAuthor;
    protected int textStatus;
    protected int propStatus;
    protected int nodeKind;
    protected boolean treeConflicted;
    protected boolean fileExternal;
    protected SVNConflictDescriptor conflictDescriptor;
  
    protected ResourceStatus() {
      super();
    }
  
    /**
     * @param status
     * @param url - Only needed when status.getUrl is Null, such as for an svn:externals folder
     */
    public ResourceStatus(ISVNStatus status, String url, boolean useUrlHack) {
      super();
      /** a temporary variable serving as immediate cache for various status values */
      Object aValue = null;
  
      aValue = status.getUrlString();
      if (aValue == null) {
        if (url == null) this.url = null;
        else this.url = url;
      } else {
        this.url = (String) aValue;
      }
  
      // This is a hack to get the URL for incoming additions if when URL is null due to a JavaHL bug.
      // See Issue #1312 for details.  This should only be done for RemoteResourceStatus (useUrlHack
      // == true),
      // not LocalResourceStatus.
      if (this.url == null && useUrlHack) {
        File file = status.getFile();
        if (file != null) {
          List<String> segments = new ArrayList<String>();
          segments.add(file.getName());
          File parentFile = file.getParentFile();
          while (parentFile != null) {
            if (parentFile.exists()) {
              IContainer container =
                  ResourcesPlugin.getWorkspace()
                      .getRoot()
                      .getContainerForLocation(new Path(parentFile.getPath()));
              if (container != null) {
                ISVNLocalFolder localFolder = SVNWorkspaceRoot.getSVNFolderFor(container);
                SVNUrl parentUrl = localFolder.getUrl();
                if (parentUrl != null) {
                  StringBuffer sb = new StringBuffer(parentUrl.toString());
                  for (int i = segments.size() - 1; i >= 0; i--) {
                    sb.append("/" + segments.get(i));
                  }
                  this.url = sb.toString();
                  break;
                }
              }
            }
            segments.add(parentFile.getName());
            parentFile = parentFile.getParentFile();
          }
        }
      }
  
      aValue = status.getLastChangedRevision();
      if (aValue == null) {
        this.lastChangedRevision = SVNRevision.SVN_INVALID_REVNUM;
      } else {
        this.lastChangedRevision = ((SVNRevision.Number) aValue).getNumber();
      }
  
      aValue = status.getLastChangedDate();
      if (aValue == null) {
        this.lastChangedDate = -1;
      } else {
        this.lastChangedDate = ((Date) aValue).getTime();
      }
  
      this.lastCommitAuthor = status.getLastCommitAuthor();
      this.textStatus = status.getTextStatus().toInt();
      this.propStatus = status.getPropStatus().toInt();
      this.treeConflicted = status.hasTreeConflict();
      this.fileExternal = status.isFileExternal();
      this.conflictDescriptor = status.getConflictDescriptor();
  
      this.nodeKind = status.getNodeKind().toInt();
  
      this.file = status.getFile();
    }
  
    public String toString() {
      return ((file != null) ? file.getAbsolutePath() : "")
          + " ("
          + lastChangedRevision
          + ") "
          + getTextStatus().toString();
    }
  
    /** @return Returns the file. */
    public File getFile() {
      return file;
    }
  
    /**
     * @return Returns the absolute resource path. (It is absolute since it was constructed as
     *     status.getFile().getAbsolutePath())
     */
    public IPath getIPath() {
      return new Path(getPath());
    }
  
    /**
     * @return Returns the absolute resource path (as String). (It is absolute since it was
     *     constructed as status.getFile().getAbsolutePath())
     */
    public String getPath() {
      return file.getAbsolutePath();
    }
  
    public SVNStatusKind getTextStatus() {
      SVNStatusKind statusKind = SVNStatusKind.fromInt(textStatus);
      statusKind.setTreeConflicted(treeConflicted);
      return statusKind;
    }
  
    public SVNStatusKind getPropStatus() {
      return SVNStatusKind.fromInt(propStatus);
    }
  
    public boolean hasTreeConflict() {
      return treeConflicted;
    }
  
    public boolean isFileExternal() {
      return fileExternal;
    }
  
    public SVNConflictDescriptor getConflictDescriptor() {
      return conflictDescriptor;
    }
  
    /**
     * Answer a 'join' of text and property statuses. The text has priority, i.e. the prop does not
     * override the text status unless it is harmless - i.e. SVNStatusKind.NORMAL
     *
     * @param textStatus
     * @param propStatus
     * @return
     */
    public SVNStatusKind getStatusKind() {
      if (!SVNStatusKind.NORMAL.equals(getTextStatus())
          && !SVNStatusKind.EXTERNAL.equals(getTextStatus())
          && !SVNStatusKind.NONE.equals(getTextStatus())) {
        return getTextStatus();
      } else {
        if (SVNStatusKind.MODIFIED.equals(getPropStatus())
            || SVNStatusKind.CONFLICTED.equals(getPropStatus())) {
          return getPropStatus();
        } else {
          return getTextStatus();
        }
      }
    }
  
    public ISVNRepositoryLocation getRepository() {
      if (getUrlString() != null) {
        try {
          return SVNProviderPlugin.getPlugin().getRepository(getUrlString());
        } catch (SVNException e) {
          // an exception is thrown when resource	is not managed
          SVNProviderPlugin.log(e);
          return null;
        }
      } else if (file != null) {
        return SVNWorkspaceRoot.getRepositoryFor(new Path(file.getAbsolutePath()));
      }
      return null;
    }
  
    /* (non-Javadoc)
     * @see org.tigris.subversion.svnclientadapter.ISVNStatus#getNodeKind()
     */
    public SVNNodeKind getNodeKind() {
      return SVNNodeKind.fromInt(nodeKind);
    }
  
    /* (non-Javadoc)
     * @see org.tigris.subversion.svnclientadapter.ISVNStatus#getUrl()
     */
    public SVNUrl getUrl() {
      if (url == null) {
        return null;
      } else {
        try {
          return new SVNUrl(url);
        } catch (MalformedURLException e) {
          return null;
        }
      }
    }
  
    public String getUrlString() {
      return url;
    }
  
    /* (non-Javadoc)
     * @see org.tigris.subversion.svnclientadapter.ISVNStatus#getLastChangedRevision()
     */
    public Number getLastChangedRevision() {
      if (lastChangedRevision == SVNRevision.SVN_INVALID_REVNUM) {
        return null;
      } else {
        return new SVNRevision.Number(lastChangedRevision);
      }
    }
  
    /* (non-Javadoc)
     * @see org.tigris.subversion.svnclientadapter.ISVNStatus#getLastChangedDate()
     */
    public Date getLastChangedDate() {
      if (lastChangedDate == -1) {
        return null;
      } else {
        return new Date(lastChangedDate);
      }
    }
  
    /* (non-Javadoc)
     * @see org.tigris.subversion.svnclientadapter.ISVNStatus#getLastCommitAuthor()
     */
    public String getLastCommitAuthor() {
      return lastCommitAuthor;
    }
  
    /**
     * Initialize receivers internal state according the information encoded in the given
     * DataInputStream. (Which contents was created with {@link #getBytes()}
     *
     * @param dis
     * @return encoding format version
     * @throws SVNException
     */
    protected int initFromBytes(StatusFromBytesStream dis) throws SVNException {
      int version;
      try {
        version = dis.readInt();
        if (version != FORMAT_VERSION_1
            && version != FORMAT_VERSION_2
  