##
## Licensed to the Apache Software Foundation (ASF) under one
## or more contributor license agreements.  See the NOTICE file
## distributed with this work for additional information
## regarding copyright ownership.  The ASF licenses this file
## to you 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.
##
#if ($schema.getNamespace())
package $schema.getNamespace();
#end

import org.apache.avro.specific.SpecificData;
#if (!$schema.isError())
import org.apache.avro.message.BinaryMessageEncoder;
import org.apache.avro.message.BinaryMessageDecoder;
import org.apache.avro.message.SchemaStore;
#end

@SuppressWarnings("all")
#if ($schema.getDoc())
/** $schema.getDoc() */
#end
#foreach ($annotation in $this.javaAnnotations($schema))
@$annotation
#end
@org.apache.avro.specific.AvroGenerated
public class ${this.mangle($schema.getName())}#if ($schema.isError()) extends org.apache.avro.specific.SpecificExceptionBase#else extends org.apache.avro.specific.SpecificRecordBase#end implements org.apache.avro.specific.SpecificRecord {
  private static final long serialVersionUID = ${this.fingerprint64($schema)}L;
  public static final org.apache.avro.Schema SCHEMA$ = new org.apache.avro.Schema.Parser().parse(${this.javaSplit($schema.toString())});
  public static org.apache.avro.Schema getClassSchema() { return SCHEMA$; }

  private static SpecificData MODEL$ = new SpecificData();

#if (!$schema.isError())
  private static final BinaryMessageEncoder<${this.mangle($schema.getName())}> ENCODER =
      new BinaryMessageEncoder<${this.mangle($schema.getName())}>(MODEL$, SCHEMA$);

  private static final BinaryMessageDecoder<${this.mangle($schema.getName())}> DECODER =
      new BinaryMessageDecoder<${this.mangle($schema.getName())}>(MODEL$, SCHEMA$);

  /**
   * Return the BinaryMessageDecoder instance used by this class.
   */
  public static BinaryMessageDecoder<${this.mangle($schema.getName())}> getDecoder() {
    return DECODER;
  }

  /**
   * Create a new BinaryMessageDecoder instance for this class that uses the specified {@link SchemaStore}.
   * @param resolver a {@link SchemaStore} used to find schemas by fingerprint
   */
  public static BinaryMessageDecoder<${this.mangle($schema.getName())}> createDecoder(SchemaStore resolver) {
    return new BinaryMessageDecoder<${this.mangle($schema.getName())}>(MODEL$, SCHEMA$, resolver);
  }

  /** Serializes this ${schema.getName()} to a ByteBuffer. */
  public java.nio.ByteBuffer toByteBuffer() throws java.io.IOException {
    return ENCODER.encode(this);
  }

  /** Deserializes a ${schema.getName()} from a ByteBuffer. */
  public static ${this.mangle($schema.getName())} fromByteBuffer(
      java.nio.ByteBuffer b) throws java.io.IOException {
    return DECODER.decode(b);
  }
#end

#foreach ($field in $schema.getFields())
#if ($field.doc())
  /** $field.doc() */
#end
#foreach ($annotation in $this.javaAnnotations($field))
  @$annotation
#end
  #if (${this.deprecatedFields()})@Deprecated#end #if (${this.publicFields()})public#elseif (${this.privateFields()})private#end ${this.javaUnbox($field.schema())} ${this.mangle($field.name(), $schema.isError())};
#end
#if ($schema.isError())

  public ${this.mangle($schema.getName())}() {
    super();
  }

  public ${this.mangle($schema.getName())}(Object value) {
    super(value);
  }

  public ${this.mangle($schema.getName())}(Throwable cause) {
    super(cause);
  }

  public ${this.mangle($schema.getName())}(Object value, Throwable cause) {
    super(value, cause);
  }

#else
#if ($schema.getFields().size() > 0)

  /**
   * Default constructor.  Note that this does not initialize fields
   * to their default values from the schema.  If that is desired then
   * one should use <code>newBuilder()</code>.
   */
  public ${this.mangle($schema.getName())}() {}
#if ($this.isCreateAllArgsConstructor())

  /**
   * All-args constructor.
#foreach ($field in $schema.getFields())
#if ($field.doc())   * @param ${this.mangle($field.name())} $field.doc()
#else   * @param ${this.mangle($field.name())} The new value for ${field.name()}
#end
#end
   */
  public ${this.mangle($schema.getName())}(#foreach($field in $schema.getFields())${this.javaType($field.schema())} ${this.mangle($field.name())}#if($velocityCount < $schema.getFields().size()), #end#end) {
#foreach ($field in $schema.getFields())
    this.${this.mangle($field.name())} = ${this.mangle($field.name())};
#end
  }
#else
  /**
   * This schema contains more than 254 fields which exceeds the maximum number
   * of permitted constructor parameters in the JVM. An all-args constructor
   * will not be generated. Please use <code>newBuilder()</code> to instantiate
   * objects instead.
   */
#end
#end

#end
  public org.apache.avro.Schema getSchema() { return SCHEMA$; }
  // Used by DatumWriter.  Applications should not call.
  public java.lang.Object get(int field$) {
    switch (field$) {
#set ($i = 0)
#foreach ($field in $schema.getFields())
    case $i: return ${this.mangle($field.name(), $schema.isError())};
#set ($i = $i + 1)
#end
    default: throw new org.apache.avro.AvroRuntimeException("Bad index");
    }
  }

#if ($this.hasLogicalTypeField($schema))
  protected static final org.apache.avro.data.TimeConversions.DateConversion DATE_CONVERSION = new org.apache.avro.data.TimeConversions.DateConversion();
  protected static final org.apache.avro.data.TimeConversions.TimeConversion TIME_CONVERSION = new org.apache.avro.data.TimeConversions.TimeConversion();
  protected static final org.apache.avro.data.TimeConversions.TimestampConversion TIMESTAMP_CONVERSION = new org.apache.avro.data.TimeConversions.TimestampConversion();
  protected static final org.apache.avro.Conversions.DecimalConversion DECIMAL_CONVERSION = new org.apache.avro.Conversions.DecimalConversion();

  private static final org.apache.avro.Conversion<?>[] conversions =
      new org.apache.avro.Conversion<?>[] {
#foreach ($field in $schema.getFields())
      ${this.conversionInstance($field.schema())},
#end
      null
  };

  @Override
  public org.apache.avro.Conversion<?> getConversion(int field) {
    return conversions[field];
  }

#end
  // Used by DatumReader.  Applications should not call.
  @SuppressWarnings(value="unchecked")
  public void put(int field$, java.lang.Object value$) {
    switch (field$) {
#set ($i = 0)
#foreach ($field in $schema.getFields())
    case $i: ${this.mangle($field.name(), $schema.isError())} = (${this.javaType($field.schema())})value$; break;
#set ($i = $i + 1)
#end
    default: throw new org.apache.avro.AvroRuntimeException("Bad index");
    }
  }

#foreach ($field in $schema.getFields())
  /**
   * Gets the value of the '${this.mangle($field.name(), $schema.isError())}' field.
#if ($field.doc())   * @return $field.doc()
#else   * @return The value of the '${this.mangle($field.name(), $schema.isError())}' field.
#end
   */
  public ${this.javaType($field.schema())} ${this.generateGetMethod($schema, $field)}() {
    return ${this.mangle($field.name(), $schema.isError())};
  }

#if ($this.createSetters)
  /**
   * Sets the value of the '${this.mangle($field.name(), $schema.isError())}' field.
#if ($field.doc())   * $field.doc()
#end
   * @param value the value to set.
   */
  public void ${this.generateSetMethod($schema, $field)}(${this.javaType($field.schema())} value) {
    this.${this.mangle($field.name(), $schema.isError())} = value;
  }
#end

#end
  /**
   * Creates a new ${this.mangle($schema.getName())} RecordBuilder.
   * @return A new ${this.mangle($schema.getName())} RecordBuilder
   */
  public static #if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())}.Builder newBuilder() {
    return new #if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())}.Builder();
  }

  /**
   * Creates a new ${this.mangle($schema.getName())} RecordBuilder by copying an existing Builder.
   * @param other The existing builder to copy.
   * @return A new ${this.mangle($schema.getName())} RecordBuilder
   */
  public static #if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())}.Builder newBuilder(#if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())}.Builder other) {
    return new #if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())}.Builder(other);
  }

  /**
   * Creates a new ${this.mangle($schema.getName())} RecordBuilder by copying an existing $this.mangle($schema.getName()) instance.
   * @param other The existing instance to copy.
   * @return A new ${this.mangle($schema.getName())} RecordBuilder
   */
  public static #if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())}.Builder newBuilder(#if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())} other) {
    return new #if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())}.Builder(other);
  }

  /**
   * RecordBuilder for ${this.mangle($schema.getName())} instances.
   */
  public static class Builder extends#if ($schema.isError()) org.apache.avro.specific.SpecificErrorBuilderBase<${this.mangle($schema.getName())}>#else org.apache.avro.specific.SpecificRecordBuilderBase<${this.mangle($schema.getName())}>#end

    implements#if ($schema.isError()) org.apache.avro.data.ErrorBuilder<${this.mangle($schema.getName())}>#else org.apache.avro.data.RecordBuilder<${this.mangle($schema.getName())}>#end {

#foreach ($field in $schema.getFields())
#if ($field.doc())
    /** $field.doc() */
#end
    private ${this.javaUnbox($field.schema())} ${this.mangle($field.name(), $schema.isError())};
#if (${this.hasBuilder($field.schema())})
    private ${this.javaUnbox($field.schema())}.Builder ${this.mangle($field.name(), $schema.isError())}Builder;
#end
#end

    /** Creates a new Builder */
    private Builder() {
      super(SCHEMA$);
    }

    /**
     * Creates a Builder by copying an existing Builder.
     * @param other The existing Builder to copy.
     */
    private Builder(#if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())}.Builder other) {
      super(other);
#foreach ($field in $schema.getFields())
      if (isValidValue(fields()[$field.pos()], other.${this.mangle($field.name(), $schema.isError())})) {
        this.${this.mangle($field.name(), $schema.isError())} = data().deepCopy(fields()[$field.pos()].schema(), other.${this.mangle($field.name(), $schema.isError())});
        fieldSetFlags()[$field.pos()] = true;
      }
#if (${this.hasBuilder($field.schema())})
      if (other.${this.generateHasBuilderMethod($schema, $field)}()) {
        this.${this.mangle($field.name(), $schema.isError())}Builder = ${this.javaType($field.schema())}.newBuilder(other.${this.generateGetBuilderMethod($schema, $field)}());
      }
#end
#end
    }

    /**
     * Creates a Builder by copying an existing $this.mangle($schema.getName()) instance
     * @param other The existing instance to copy.
     */
    private Builder(#if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())} other) {
      #if ($schema.isError())super(other)#else
      super(SCHEMA$)#end;
#foreach ($field in $schema.getFields())
      if (isValidValue(fields()[$field.pos()], other.${this.mangle($field.name(), $schema.isError())})) {
        this.${this.mangle($field.name(), $schema.isError())} = data().deepCopy(fields()[$field.pos()].schema(), other.${this.mangle($field.name(), $schema.isError())});
        fieldSetFlags()[$field.pos()] = true;
      }
#if (${this.hasBuilder($field.schema())})
      this.${this.mangle($field.name(), $schema.isError())}Builder = null;
#end
#end
    }
#if ($schema.isError())

    @Override
    public #if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())}.Builder setValue(Object value) {
      super.setValue(value);
      return this;
    }

    @Override
    public #if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())}.Builder clearValue() {
      super.clearValue();
      return this;
    }

    @Override
    public #if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())}.Builder setCause(Throwable cause) {
      super.setCause(cause);
      return this;
    }

    @Override
    public #if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())}.Builder clearCause() {
      super.clearCause();
      return this;
    }
#end

#foreach ($field in $schema.getFields())
    /**
      * Gets the value of the '${this.mangle($field.name(), $schema.isError())}' field.
#if ($field.doc())      * $field.doc()
#end
      * @return The value.
      */
    public ${this.javaType($field.schema())} ${this.generateGetMethod($schema, $field)}() {
      return ${this.mangle($field.name(), $schema.isError())};
    }

    /**
      * Sets the value of the '${this.mangle($field.name(), $schema.isError())}' field.
#if ($field.doc())      * $field.doc()
#end
      * @param value The value of '${this.mangle($field.name(), $schema.isError())}'.
      * @return This builder.
      */
    public #if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())}.Builder ${this.generateSetMethod($schema, $field)}(${this.javaUnbox($field.schema())} value) {
      validate(fields()[$field.pos()], value);
#if (${this.hasBuilder($field.schema())})
      this.${this.mangle($field.name(), $schema.isError())}Builder = null;
#end
      this.${this.mangle($field.name(), $schema.isError())} = value;
      fieldSetFlags()[$field.pos()] = true;
      return this;
    }

    /**
      * Checks whether the '${this.mangle($field.name(), $schema.isError())}' field has been set.
#if ($field.doc())      * $field.doc()
#end
      * @return True if the '${this.mangle($field.name(), $schema.isError())}' field has been set, false otherwise.
      */
    public boolean ${this.generateHasMethod($schema, $field)}() {
      return fieldSetFlags()[$field.pos()];
    }

#if (${this.hasBuilder($field.schema())})
    /**
     * Gets the Builder instance for the '${this.mangle($field.name(), $schema.isError())}' field and creates one if it doesn't exist yet.
#if ($field.doc())     * $field.doc()
#end
     * @return This builder.
     */
    public ${this.javaType($field.schema())}.Builder ${this.generateGetBuilderMethod($schema, $field)}() {
      if (${this.mangle($field.name(), $schema.isError())}Builder == null) {
        if (${this.generateHasMethod($schema, $field)}()) {
          ${this.generateSetBuilderMethod($schema, $field)}(${this.javaType($field.schema())}.newBuilder(${this.mangle($field.name(), $schema.isError())}));
        } else {
          ${this.generateSetBuilderMethod($schema, $field)}(${this.javaType($field.schema())}.newBuilder());
        }
      }
      return ${this.mangle($field.name(), $schema.isError())}Builder;
    }

    /**
     * Sets the Builder instance for the '${this.mangle($field.name(), $schema.isError())}' field
#if ($field.doc())     * $field.doc()
#end
     * @param value The builder instance that must be set.
     * @return This builder.
     */
    public #if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())}.Builder ${this.generateSetBuilderMethod($schema, $field)}(${this.javaUnbox($field.schema())}.Builder value) {
      ${this.generateClearMethod($schema, $field)}();
      ${this.mangle($field.name(), $schema.isError())}Builder = value;
      return this;
    }

    /**
     * Checks whether the '${this.mangle($field.name(), $schema.isError())}' field has an active Builder instance
#if ($field.doc())     * $field.doc()
#end
     * @return True if the '${this.mangle($field.name(), $schema.isError())}' field has an active Builder instance
     */
    public boolean ${this.generateHasBuilderMethod($schema, $field)}() {
      return ${this.mangle($field.name(), $schema.isError())}Builder != null;
    }
#end

    /**
      * Clears the value of the '${this.mangle($field.name(), $schema.isError())}' field.
#if ($field.doc())      * $field.doc()
#end
      * @return This builder.
      */
    public #if ($schema.getNamespace())$schema.getNamespace().#end${this.mangle($schema.getName())}.Builder ${this.generateClearMethod($schema, $field)}() {
#if (${this.isUnboxedJavaTypeNullable($field.schema())})
      ${this.mangle($field.name(), $schema.isError())} = null;
#end
#if (${this.hasBuilder($field.schema())})
      ${this.mangle($field.name(), $schema.isError())}Builder = null;
#end
      fieldSetFlags()[$field.pos()] = false;
      return this;
    }

#end
    @Override
    @SuppressWarnings("unchecked")
    public ${this.mangle($schema.getName())} build() {
      try {
        ${this.mangle($schema.getName())} record = new ${this.mangle($schema.getName())}(#if ($schema.isError())getValue(), getCause()#end);
#foreach ($field in $schema.getFields())
#if (${this.hasBuilder($field.schema())})
        if (${this.mangle($field.name(), $schema.isError())}Builder != null) {
          record.${this.mangle($field.name(), $schema.isError())} = this.${this.mangle($field.name(), $schema.isError())}Builder.build();
        } else {
#if ($this.hasLogicalTypeField($schema))
          record.${this.mangle($field.name(), $schema.isError())} = fieldSetFlags()[$field.pos()] ? this.${this.mangle($field.name(), $schema.isError())} : (${this.javaType($field.schema())}) defaultValue(fields()[$field.pos()], record.getConversion($field.pos()));
#else
          record.${this.mangle($field.name(), $schema.isError())} = fieldSetFlags()[$field.pos()] ? this.${this.mangle($field.name(), $schema.isError())} : (${this.javaType($field.schema())}) defaultValue(fields()[$field.pos()]);
#end
        }
#else
#if ($this.hasLogicalTypeField($schema))
        record.${this.mangle($field.name(), $schema.isError())} = fieldSetFlags()[$field.pos()] ? this.${this.mangle($field.name(), $schema.isError())} : (${this.javaType($field.schema())}) defaultValue(fields()[$field.pos()], record.getConversion($field.pos()));
#else
        record.${this.mangle($field.name(), $schema.isError())} = fieldSetFlags()[$field.pos()] ? this.${this.mangle($field.name(), $schema.isError())} : (${this.javaType($field.schema())}) defaultValue(fields()[$field.pos()]);
#end
#end
#end
        return record;
      } catch (java.lang.Exception e) {
        throw new org.apache.avro.AvroRuntimeException(e);
      }
    }
  }

  @SuppressWarnings("unchecked")
  private static final org.apache.avro.io.DatumWriter<${this.mangle($schema.getName())}>
    WRITER$ = (org.apache.avro.io.DatumWriter<${this.mangle($schema.getName())}>)MODEL$.createDatumWriter(SCHEMA$);

  @Override public void writeExternal(java.io.ObjectOutput out)
    throws java.io.IOException {
    WRITER$.write(this, SpecificData.getEncoder(out));
  }

  @SuppressWarnings("unchecked")
  private static final org.apache.avro.io.DatumReader<${this.mangle($schema.getName())}>
    READER$ = (org.apache.avro.io.DatumReader<${this.mangle($schema.getName())}>)MODEL$.createDatumReader(SCHEMA$);

  @Override public void readExternal(java.io.ObjectInput in)
    throws java.io.IOException {
    READER$.read(this, SpecificData.getDecoder(in));
  }

}
