// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc.  All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd

import com.google.protobuf.AbstractMessage;
import com.google.protobuf.ByteString;
import com.google.protobuf.CodedInputStream;
import com.google.protobuf.ExtensionRegistry;
import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.Parser;
import com.google.protobuf.TextFormat;
import com.google.protobuf.conformance.Conformance;
import com.google.protobuf.util.JsonFormat;
import com.google.protobuf.util.JsonFormat.TypeRegistry;
import com.google.protobuf_test_messages.proto2.TestMessagesProto2;
import com.google.protobuf_test_messages.proto2.TestMessagesProto2.TestAllTypesProto2;
import com.google.protobuf_test_messages.proto3.TestMessagesProto3;
import com.google.protobuf_test_messages.proto3.TestMessagesProto3.TestAllTypesProto3;
import java.nio.ByteBuffer;
import java.util.ArrayList;

class ConformanceJava {
  private int testCount = 0;
  private TypeRegistry typeRegistry;

  private boolean readFromStdin(byte[] buf, int len) throws Exception {
    int ofs = 0;
    while (len > 0) {
      int read = System.in.read(buf, ofs, len);
      if (read == -1) {
        return false; // EOF
      }
      ofs += read;
      len -= read;
    }

    return true;
  }

  private void writeToStdout(byte[] buf) throws Exception {
    System.out.write(buf);
  }

  // Returns -1 on EOF (the actual values will always be positive).
  private int readLittleEndianIntFromStdin() throws Exception {
    byte[] buf = new byte[4];
    if (!readFromStdin(buf, 4)) {
      return -1;
    }
    return (buf[0] & 0xff)
        | ((buf[1] & 0xff) << 8)
        | ((buf[2] & 0xff) << 16)
        | ((buf[3] & 0xff) << 24);
  }

  private void writeLittleEndianIntToStdout(int val) throws Exception {
    byte[] buf = new byte[4];
    buf[0] = (byte) val;
    buf[1] = (byte) (val >> 8);
    buf[2] = (byte) (val >> 16);
    buf[3] = (byte) (val >> 24);
    writeToStdout(buf);
  }

  private enum BinaryDecoderType {
    BTYE_STRING_DECODER,
    BYTE_ARRAY_DECODER,
    ARRAY_BYTE_BUFFER_DECODER,
    READONLY_ARRAY_BYTE_BUFFER_DECODER,
    DIRECT_BYTE_BUFFER_DECODER,
    READONLY_DIRECT_BYTE_BUFFER_DECODER,
    INPUT_STREAM_DECODER;
  }

  private static class BinaryDecoder<T extends AbstractMessage> {
    public T decode(
        ByteString bytes, BinaryDecoderType type, Parser<T> parser, ExtensionRegistry extensions)
        throws InvalidProtocolBufferException {
      switch (type) {
        case BTYE_STRING_DECODER:
        case BYTE_ARRAY_DECODER:
          return parser.parseFrom(bytes, extensions);
        case ARRAY_BYTE_BUFFER_DECODER:
          {
            ByteBuffer buffer = ByteBuffer.allocate(bytes.size());
            bytes.copyTo(buffer);
            buffer.flip();
            return parser.parseFrom(CodedInputStream.newInstance(buffer), extensions);
          }
        case READONLY_ARRAY_BYTE_BUFFER_DECODER:
          {
            return parser.parseFrom(
                CodedInputStream.newInstance(bytes.asReadOnlyByteBuffer()), extensions);
          }
        case DIRECT_BYTE_BUFFER_DECODER:
          {
            ByteBuffer buffer = ByteBuffer.allocateDirect(bytes.size());
            bytes.copyTo(buffer);
            buffer.flip();
            return parser.parseFrom(CodedInputStream.newInstance(buffer), extensions);
          }
        case READONLY_DIRECT_BYTE_BUFFER_DECODER:
          {
            ByteBuffer buffer = ByteBuffer.allocateDirect(bytes.size());
            bytes.copyTo(buffer);
            buffer.flip();
            return parser.parseFrom(
                CodedInputStream.newInstance(buffer.asReadOnlyBuffer()), extensions);
          }
        case INPUT_STREAM_DECODER:
          {
            return parser.parseFrom(bytes.newInput(), extensions);
          }
      }
      return null;
    }
  }

  private <T extends AbstractMessage> T parseBinary(
      ByteString bytes, Parser<T> parser, ExtensionRegistry extensions)
      throws InvalidProtocolBufferException {
    ArrayList<T> messages = new ArrayList<>();
    ArrayList<InvalidProtocolBufferException> exceptions = new ArrayList<>();

    for (int i = 0; i < BinaryDecoderType.values().length; i++) {
      messages.add(null);
      exceptions.add(null);
    }
    if (messages.isEmpty()) {
      throw new RuntimeException("binary decoder types missing");
    }

    BinaryDecoder<T> decoder = new BinaryDecoder<>();

    boolean hasMessage = false;
    boolean hasException = false;
    for (int i = 0; i < BinaryDecoderType.values().length; ++i) {
      try {
        // = BinaryDecoderType.values()[i].parseProto3(bytes);
        messages.set(i, decoder.decode(bytes, BinaryDecoderType.values()[i], parser, extensions));
        hasMessage = true;
      } catch (InvalidProtocolBufferException e) {
        exceptions.set(i, e);
        hasException = true;
      }
    }

    if (hasMessage && hasException) {
      StringBuilder sb =
          new StringBuilder("Binary decoders disagreed on whether the payload was valid.\n");
      for (int i = 0; i < BinaryDecoderType.values().length; ++i) {
        sb.append(BinaryDecoderType.values()[i].name());
        if (messages.get(i) != null) {
          sb.append(" accepted the payload.\n");
        } else {
          sb.append(" rejected the payload.\n");
        }
      }
      throw new RuntimeException(sb.toString());
    }

    if (hasException) {
      // We do not check if exceptions are equal. Different implementations may return different
      // exception messages. Throw an arbitrary one out instead.
      InvalidProtocolBufferException exception = null;
      for (InvalidProtocolBufferException e : exceptions) {
        if (exception != null) {
          exception.addSuppressed(e);
        } else {
          exception = e;
        }
      }
      throw exception;
    }

    // Fast path comparing all the messages with the first message, assuming equality being
    // symmetric and transitive.
    boolean allEqual = true;
    for (int i = 1; i < messages.size(); ++i) {
      if (!messages.get(0).equals(messages.get(i))) {
        allEqual = false;
        break;
      }
    }

    // Slow path: compare and find out all unequal pairs.
    if (!allEqual) {
      StringBuilder sb = new StringBuilder();
      for (int i = 0; i < messages.size() - 1; ++i) {
        for (int j = i + 1; j < messages.size(); ++j) {
          if (!messages.get(i).equals(messages.get(j))) {
            sb.append(BinaryDecoderType.values()[i].name())
                .append(" and ")
                .append(BinaryDecoderType.values()[j].name())
                .append(" parsed the payload differently.\n");
          }
        }
      }
      throw new RuntimeException(sb.toString());
    }

    return messages.get(0);
  }

  private Conformance.ConformanceResponse doTest(Conformance.ConformanceRequest request) {
    AbstractMessage testMessage;
    String messageType = request.getMessageType();
    boolean isProto3 = messageType.equals("protobuf_test_messages.proto3.TestAllTypesProto3");
    boolean isProto2 = messageType.equals("protobuf_test_messages.proto2.TestAllTypesProto2");

    switch (request.getPayloadCase()) {
      case PROTOBUF_PAYLOAD:
        {
          if (isProto3) {
            try {
              ExtensionRegistry extensions = ExtensionRegistry.newInstance();
              TestMessagesProto3.registerAllExtensions(extensions);
              testMessage =
                  parseBinary(
                      request.getProtobufPayload(), TestAllTypesProto3.parser(), extensions);
            } catch (InvalidProtocolBufferException e) {
              return Conformance.ConformanceResponse.newBuilder()
                  .setParseError(e.getMessage())
                  .build();
            }
          } else if (isProto2) {
            try {
              ExtensionRegistry extensions = ExtensionRegistry.newInstance();
              TestMessagesProto2.registerAllExtensions(extensions);
              testMessage =
                  parseBinary(
                      request.getProtobufPayload(), TestAllTypesProto2.parser(), extensions);
            } catch (InvalidProtocolBufferException e) {
              return Conformance.ConformanceResponse.newBuilder()
                  .setParseError(e.getMessage())
                  .build();
            }
          } else {
            throw new IllegalArgumentException(
                "Protobuf request has unexpected payload type: " + messageType);
          }
          break;
        }
      case JSON_PAYLOAD:
        {
          try {
            JsonFormat.Parser parser = JsonFormat.parser().usingTypeRegistry(typeRegistry);
            if (request.getTestCategory()
                == Conformance.TestCategory.JSON_IGNORE_UNKNOWN_PARSING_TEST) {
              parser = parser.ignoringUnknownFields();
            }
            if (isProto3) {
              TestMessagesProto3.TestAllTypesProto3.Builder builder =
                  TestMessagesProto3.TestAllTypesProto3.newBuilder();
              parser.merge(request.getJsonPayload(), builder);
              testMessage = builder.build();
            } else if (isProto2) {
              TestMessagesProto2.TestAllTypesProto2.Builder builder =
                  TestMessagesProto2.TestAllTypesProto2.newBuilder();
              parser.merge(request.getJsonPayload(), builder);
              testMessage = builder.build();
            } else {
              throw new IllegalArgumentException(
                  "Protobuf request has unexpected payload type: " + messageType);
            }
          } catch (InvalidProtocolBufferException e) {
            return Conformance.ConformanceResponse.newBuilder()
                .setParseError(e.getMessage())
                .build();
          }
          break;
        }
      case TEXT_PAYLOAD:
        {
          if (isProto3) {
            try {
              TestMessagesProto3.TestAllTypesProto3.Builder builder =
                  TestMessagesProto3.TestAllTypesProto3.newBuilder();
              TextFormat.merge(request.getTextPayload(), builder);
              testMessage = builder.build();
            } catch (TextFormat.ParseException e) {
              return Conformance.ConformanceResponse.newBuilder()
                  .setParseError(e.getMessage())
                  .build();
            }
          } else if (isProto2) {
            try {
              TestMessagesProto2.TestAllTypesProto2.Builder builder =
                  TestMessagesProto2.TestAllTypesProto2.newBuilder();
              TextFormat.merge(request.getTextPayload(), builder);
              testMessage = builder.build();
            } catch (TextFormat.ParseException e) {
              return Conformance.ConformanceResponse.newBuilder()
                  .setParseError(e.getMessage())
                  .build();
            }
          } else {
            throw new IllegalArgumentException(
                "Protobuf request has unexpected payload type: " + messageType);
          }
          break;
        }
      case PAYLOAD_NOT_SET:
        {
          throw new IllegalArgumentException("Request didn't have payload.");
        }

      default:
        {
          throw new IllegalArgumentException("Unexpected payload case.");
        }
    }

    switch (request.getRequestedOutputFormat()) {
      case UNSPECIFIED:
        throw new IllegalArgumentException("Unspecified output format.");

      case PROTOBUF:
        {
          ByteString messageString = testMessage.toByteString();
          return Conformance.ConformanceResponse.newBuilder()
              .setProtobufPayload(messageString)
              .build();
        }

      case JSON:
        try {
          return Conformance.ConformanceResponse.newBuilder()
              .setJsonPayload(
                  JsonFormat.printer().usingTypeRegistry(typeRegistry).print(testMessage))
              .build();
        } catch (InvalidProtocolBufferException | IllegalArgumentException e) {
          return Conformance.ConformanceResponse.newBuilder()
              .setSerializeError(e.getMessage())
              .build();
        }

      case TEXT_FORMAT:
        return Conformance.ConformanceResponse.newBuilder()
            .setTextPayload(TextFormat.printer().printToString(testMessage))
            .build();

      default:
        {
          throw new IllegalArgumentException("Unexpected request output.");
        }
    }
  }

  private boolean doTestIo() throws Exception {
    int bytes = readLittleEndianIntFromStdin();

    if (bytes == -1) {
      return false; // EOF
    }

    byte[] serializedInput = new byte[bytes];

    if (!readFromStdin(serializedInput, bytes)) {
      throw new RuntimeException("Unexpected EOF from test program.");
    }

    Conformance.ConformanceRequest request =
        Conformance.ConformanceRequest.parseFrom(serializedInput);
    Conformance.ConformanceResponse response = doTest(request);
    byte[] serializedOutput = response.toByteArray();

    writeLittleEndianIntToStdout(serializedOutput.length);
    writeToStdout(serializedOutput);

    return true;
  }

  public void run() throws Exception {
    typeRegistry =
        TypeRegistry.newBuilder()
            .add(TestMessagesProto3.TestAllTypesProto3.getDescriptor())
            .build();
    while (doTestIo()) {
      this.testCount++;
    }

    System.err.println(
        "ConformanceJava: received EOF from test runner after " + this.testCount + " tests");
  }

  public static void main(String[] args) throws Exception {
    new ConformanceJava().run();
  }
}
