// Copyright (C) 2010 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.gerrit.server.patch;

import static org.eclipse.jgit.lib.ObjectIdSerialization.readNotNull;
import static org.eclipse.jgit.lib.ObjectIdSerialization.writeNotNull;

import com.google.gerrit.reviewdb.Project;

import org.eclipse.jgit.diff.Edit;
import org.eclipse.jgit.lib.ObjectId;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.List;

public class IntraLineDiffKey implements Serializable {
  static final long serialVersionUID = 3L;

  private transient ObjectId aId;
  private transient ObjectId bId;

  // Transient data passed through on cache misses to the loader.

  private transient Text aText;
  private transient Text bText;
  private transient List<Edit> edits;

  private transient Project.NameKey projectKey;
  private transient ObjectId commit;
  private transient String path;

  public IntraLineDiffKey(ObjectId aId, Text aText, ObjectId bId, Text bText,
      List<Edit> edits, Project.NameKey projectKey, ObjectId commit, String path) {
    this.aId = aId;
    this.bId = bId;

    this.aText = aText;
    this.bText = bText;
    this.edits = edits;

    this.projectKey = projectKey;
    this.commit = commit;
    this.path = path;
  }

  Text getTextA() {
    return aText;
  }

  Text getTextB() {
    return bText;
  }

  List<Edit> getEdits() {
    return edits;
  }

  ObjectId getBlobA() {
    return aId;
  }

  ObjectId getBlobB() {
    return bId;
  }

  Project.NameKey getProject() {
    return projectKey;
  }

  ObjectId getCommit() {
    return commit;
  }

  String getPath() {
    return path;
  }

  @Override
  public int hashCode() {
    int h = 0;

    h = h * 31 + aId.hashCode();
    h = h * 31 + bId.hashCode();

    return h;
  }

  @Override
  public boolean equals(final Object o) {
    if (o instanceof IntraLineDiffKey) {
      final IntraLineDiffKey k = (IntraLineDiffKey) o;
      return aId.equals(k.aId) //
          && bId.equals(k.bId);
    }
    return false;
  }

  @Override
  public String toString() {
    StringBuilder n = new StringBuilder();
    n.append("IntraLineDiffKey[");
    n.append(aId.name());
    n.append("..");
    n.append(bId.name());
    n.append("]");
    return n.toString();
  }

  private void writeObject(final ObjectOutputStream out) throws IOException {
    writeNotNull(out, aId);
    writeNotNull(out, bId);
  }

  private void readObject(final ObjectInputStream in) throws IOException {
    aId = readNotNull(in);
    bId = readNotNull(in);
  }
}
