package com.beijunyi.parallelgit.filesystem.io;

import java.io.IOException;
import javax.annotation.Nonnull;

import com.beijunyi.parallelgit.filesystem.exceptions.IncompatibleFileModeException;
import com.beijunyi.parallelgit.utils.io.BlobSnapshot;
import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.ObjectId;

import static org.eclipse.jgit.lib.FileMode.*;

public class FileNode extends Node<BlobSnapshot, byte[]> {

  private static final byte[] EMPTY_BYTE_ARRAY = new byte[0];

  private long size = -1;

  private FileNode(ObjectId id, FileMode mode, DirectoryNode parent) {
    super(id, mode, parent);
  }

  private FileNode(FileMode mode, DirectoryNode parent) {
    super(mode, parent);
  }

  private FileNode(byte[] bytes, FileMode mode, DirectoryNode parent) {
    super(bytes, mode, parent);
  }

  @Nonnull
  protected static FileNode fromBlob(ObjectId id, FileMode mode, DirectoryNode parent) {
    return new FileNode(id, mode, parent);
  }

  @Nonnull
  public static FileNode fromBytes(byte[] bytes, FileMode mode, DirectoryNode parent) {
    return new FileNode(bytes, mode, parent);
  }

  @Nonnull
  public static FileNode newFile(FileMode mode, DirectoryNode parent) {
    return new FileNode(mode, parent);
  }

  @Nonnull
  public static FileNode newFile(boolean executable, DirectoryNode parent) {
    return newFile(executable ? EXECUTABLE_FILE : REGULAR_FILE, parent);
  }

  @Override
  protected Class<? extends BlobSnapshot> getSnapshotType() {
    return BlobSnapshot.class;
  }

  public long getSize() throws IOException {
    if(size != -1)
      return size;
    size = id != null ? objService.getBlobSize(id) : 0;
    return size;
  }

  @Nonnull
  @Override
  protected byte[] getDefaultData() {
    return EMPTY_BYTE_ARRAY;
  }

  @Nonnull
  @Override
  protected byte[] loadData(BlobSnapshot snapshot) {
    return snapshot.getData();
  }

  @Override
  protected boolean isTrivial(byte[] data) {
    return false;
  }

  @Nonnull
  @Override
  protected BlobSnapshot captureData(byte[] data, boolean persist) {
    return BlobSnapshot.capture(data);
  }

  @Nonnull
  @Override
  public Node clone(DirectoryNode parent) throws IOException {
    FileNode ret;
    if(isInitialized()) {
      ret = newFile(mode, parent);
      ret.data = data;
      ret.size = data.length;
    } else if(id != null) {
      ret = FileNode.fromBlob(id , mode, parent);
      parent.getObjectService().pullObject(id, objService);
    } else
      throw new IllegalStateException();
    return ret;
  }

  public void setBytes(byte[] bytes) {
    this.data = bytes;
    this.size = bytes.length;
    id = null;
    invalidateParentCache();
  }

  protected void checkFileMode(FileMode proposed) {
    if(TREE.equals(proposed) || GITLINK.equals(proposed))
      throw new IncompatibleFileModeException(mode, proposed);
  }

}
