// 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 com.google.gerrit.server.ioutil.BasicSerialization.readEnum;
import static com.google.gerrit.server.ioutil.BasicSerialization.readVarInt32;
import static com.google.gerrit.server.ioutil.BasicSerialization.writeEnum;
import static com.google.gerrit.server.ioutil.BasicSerialization.writeVarInt32;
import static java.util.stream.Collectors.toList;

import com.google.common.collect.ImmutableList;
import com.google.gerrit.entities.CodedEnum;
import com.google.gerrit.jgit.diff.ReplaceEdit;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.eclipse.jgit.diff.Edit;

public class IntraLineDiff implements Serializable {
  static final long serialVersionUID = IntraLineDiffKey.serialVersionUID;

  public enum Status implements CodedEnum {
    EDIT_LIST('e'),
    DISABLED('D'),
    TIMEOUT('T'),
    ERROR('E');

    private final char code;

    Status(char code) {
      this.code = code;
    }

    @Override
    public char getCode() {
      return code;
    }
  }

  private transient Status status;
  private transient ImmutableList<Edit> edits;

  IntraLineDiff(Status status) {
    this.status = status;
    this.edits = ImmutableList.of();
  }

  IntraLineDiff(List<Edit> edits) {
    this.status = Status.EDIT_LIST;
    this.edits = ImmutableList.copyOf(edits);
  }

  public Status getStatus() {
    return status;
  }

  public ImmutableList<Edit> getEdits() {
    // Edits are mutable objects. As we serialize IntraLineDiff asynchronously in H2CacheImpl, we
    // must ensure that its state isn't modified until it was properly stored in the cache.
    return deepCopyEdits(edits);
  }

  private void writeObject(ObjectOutputStream out) throws IOException {
    writeEnum(out, status);
    writeVarInt32(out, edits.size());
    for (Edit e : edits) {
      writeEdit(out, e);

      if (e instanceof ReplaceEdit) {
        ReplaceEdit r = (ReplaceEdit) e;
        writeVarInt32(out, r.getInternalEdits().size());
        for (Edit i : r.getInternalEdits()) {
          writeEdit(out, i);
        }
      } else {
        writeVarInt32(out, 0);
      }
    }
  }

  private void readObject(ObjectInputStream in) throws IOException {
    status = readEnum(in, Status.values());
    int editCount = readVarInt32(in);
    Edit[] editArray = new Edit[editCount];
    for (int i = 0; i < editCount; i++) {
      editArray[i] = readEdit(in);

      int innerCount = readVarInt32(in);
      if (0 < innerCount) {
        Edit[] inner = new Edit[innerCount];
        for (int j = 0; j < innerCount; j++) {
          inner[j] = readEdit(in);
        }
        editArray[i] = new ReplaceEdit(editArray[i], asList(inner));
      }
    }
    edits = ImmutableList.copyOf(editArray);
  }

  private static ImmutableList<Edit> deepCopyEdits(List<Edit> edits) {
    return edits.stream().map(IntraLineDiff::copy).collect(ImmutableList.toImmutableList());
  }

  private static Edit copy(Edit edit) {
    if (edit instanceof ReplaceEdit) {
      return copy((ReplaceEdit) edit);
    }
    return new Edit(edit.getBeginA(), edit.getEndA(), edit.getBeginB(), edit.getEndB());
  }

  private static ReplaceEdit copy(ReplaceEdit edit) {
    List<Edit> internalEdits =
        edit.getInternalEdits().stream().map(IntraLineDiff::copy).collect(toList());
    return new ReplaceEdit(
        edit.getBeginA(), edit.getEndA(), edit.getBeginB(), edit.getEndB(), internalEdits);
  }

  private static void writeEdit(OutputStream out, Edit e) throws IOException {
    writeVarInt32(out, e.getBeginA());
    writeVarInt32(out, e.getEndA());
    writeVarInt32(out, e.getBeginB());
    writeVarInt32(out, e.getEndB());
  }

  private static Edit readEdit(InputStream in) throws IOException {
    int beginA = readVarInt32(in);
    int endA = readVarInt32(in);
    int beginB = readVarInt32(in);
    int endB = readVarInt32(in);
    return new Edit(beginA, endA, beginB, endB);
  }

  private static List<Edit> asList(Edit[] l) {
    return Collections.unmodifiableList(Arrays.asList(l));
  }
}
