// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

package com.google.gerrit.server.ioutil;

import com.google.gerrit.reviewdb.client.CodedEnum;

import org.eclipse.jgit.util.IO;

import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class BasicSerialization {
  private static final byte[] NO_BYTES = {};

  private static int safeRead(final InputStream input) throws IOException {
    final int b = input.read();
    if (b == -1) {
      throw new EOFException();
    }
    return b;
  }

  /** Read a fixed-width 64 bit integer in network byte order (big-endian). */
  public static long readFixInt64(final InputStream input) throws IOException {
    final long h = readFixInt32(input);
    final long l = readFixInt32(input) & 0xFFFFFFFFL;
    return (h << 32) | l;
  }

  /** Write a fixed-width 64 bit integer in network byte order (big-endian). */
  public static void writeFixInt64(final OutputStream output, final long val)
      throws IOException {
    writeFixInt32(output, (int) (val >>> 32));
    writeFixInt32(output, (int) (val & 0xFFFFFFFFL));
  }

  /** Read a fixed-width 32 bit integer in network byte order (big-endian). */
  public static int readFixInt32(final InputStream input) throws IOException {
    final int b1 = safeRead(input);
    final int b2 = safeRead(input);
    final int b3 = safeRead(input);
    final int b4 = safeRead(input);
    return (b1 << 24) | (b2 << 16) | (b3 << 8) | b4;
  }

  /** Write a fixed-width 32 bit integer in network byte order (big-endian). */
  public static void writeFixInt32(final OutputStream output, final int val)
      throws IOException {
    output.write((val >>> 24) & 0xFF);
    output.write((val >>> 16) & 0xFF);
    output.write((val >>> 8) & 0xFF);
    output.write(val & 0xFF);
  }

  /** Read a varint from the input, one byte at a time. */
  public static int readVarInt32(final InputStream input) throws IOException {
    int result = 0;
    int offset = 0;
    for (; offset < 32; offset += 7) {
      final int b = safeRead(input);
      result |= (b & 0x7f) << offset;
      if ((b & 0x80) == 0) {
        return result;
      }
    }
    throw new EOFException();
  }

  /** Write a varint; value is treated as an unsigned value. */
  public static void writeVarInt32(final OutputStream output, int value)
      throws IOException {
    while (true) {
      if ((value & ~0x7F) == 0) {
        output.write(value);
        return;
      } else {
        output.write((value & 0x7F) | 0x80);
        value >>>= 7;
      }
    }
  }

  /** Read a fixed length byte array whose length is specified as a varint. */
  public static byte[] readBytes(final InputStream input) throws IOException {
    final int len = readVarInt32(input);
    if (len == 0) {
      return NO_BYTES;
    }
    final byte[] buf = new byte[len];
    IO.readFully(input, buf, 0, len);
    return buf;
  }

  /** Write a byte array prefixed by its length in a varint. */
  public static void writeBytes(final OutputStream output, final byte[] data)
      throws IOException {
    writeBytes(output, data, 0, data.length);
  }

  /** Write a byte array prefixed by its length in a varint. */
  public static void writeBytes(final OutputStream output, final byte[] data,
      final int offset, final int len) throws IOException {
    writeVarInt32(output, len);
    output.write(data, offset, len);
  }

  /** Read a UTF-8 string, prefixed by its byte length in a varint. */
  public static String readString(final InputStream input) throws IOException {
    final byte[] bin = readBytes(input);
    if (bin.length == 0) {
      return null;
    }
    return new String(bin, 0, bin.length, "UTF-8");
  }

  /** Write a UTF-8 string, prefixed by its byte length in a varint. */
  public static void writeString(final OutputStream output, final String s)
      throws IOException {
    if (s == null) {
      writeVarInt32(output, 0);
    } else {
      writeBytes(output, s.getBytes("UTF-8"));
    }
  }

  /** Read an enum whose code is stored as a varint. */
  public static <T extends CodedEnum> T readEnum(final InputStream input,
      final T[] all) throws IOException {
    final int val = readVarInt32(input);
    for (T t : all) {
      if (t.getCode() == val) {
        return t;
      }
    }
    throw new IOException("Invalid enum " + val + " for " + all[0].getClass());
  }

  /** Write an enum whose code is stored as a varint. */
  public static <T extends CodedEnum> void writeEnum(final OutputStream output,
      final T e) throws IOException {
    writeVarInt32(output, e.getCode());
  }

  private BasicSerialization() {
  }
}
