content: package org.allaymc.api.block.property.type;
  
  import lombok.AllArgsConstructor;
  import lombok.Getter;
  
  import java.util.List;
  
  /**
   * Represents a type of block property.
   *
   * @author daoge_cmd
   */
  public sealed interface BlockPropertyType<DATATYPE> permits BaseBlockPropertyType {
  
      /**
       * Get the property type by the class.
       *
       * @param clazz the class
       * @return the property type
       */
      static Type getPropertyType(Class<?> clazz) {
          if (clazz == BooleanPropertyType.class) return Type.BOOLEAN;
          else if (clazz == IntPropertyType.class) return Type.INT;
          else if (clazz == EnumPropertyType.class) return Type.ENUM;
          else return null;
      }
  
      /**
       * Get the name of this property type.
       *
       * @return the name
       */
      String getName();
  
      /**
       * Get the default value of this property type.
       *
       * @return the default value
       */
      DATATYPE getDefaultValue();
  
      /**
       * Get the valid values of this property type.
       *
       * @return the valid values
       */
      List<DATATYPE> getValidValues();
  
      /**
       * Get the type of this property type.
       *
       * @return the type
       */
      Type getType();
  
      /**
       * Create a new value for this property type.
       *
       * @param value the value
       * @return the value
       */
      BlockPropertyValue<DATATYPE, ? extends BlockPropertyType<DATATYPE>, ?> createValue(DATATYPE value);
  
      /**
       * Try to create a new value for this property type.
       *
       * @param value the value
       * @return the value
       * @throws IllegalArgumentException if the value is invalid, such as pass a boolean value to an int property type
       */
      BlockPropertyValue<DATATYPE, ? extends BlockPropertyType<DATATYPE>, ?> tryCreateValue(Object value);
  
      /**
       * Create a default value for this property type.
       *
       * @return the value
       */
      default BlockPropertyValue<DATATYPE, ? extends BlockPropertyType<DATATYPE>, ?> createDefaultValue() {
          return createValue(getDefaultValue());
      }
  
      /**
       * Get the bit size of this property type.
       * <p>
       * The bit size is used to calculate the special value for a block state.
       *
       * @return the bit size
       */
      byte getBitSize();
  
      /**
       * The type of block property.
       */
      @Getter
      enum Type {
          BOOLEAN,
          INT,
          ENUM
      }
  
      /**
       * Represents a block property value, and this is the base class for block property value (boolean, enum, int).
       */
      @Getter
      @AllArgsConstructor
      abstract sealed class BlockPropertyValue<DATATYPE, PROPERTY extends BlockPropertyType<DATATYPE>, SERIALIZED_DATATYPE>
              permits BooleanPropertyType.BooleanPropertyValue, EnumPropertyType.EnumPropertyValue, IntPropertyType.IntPropertyValue {
  
          /**
           * The property type of this value.
           */
          protected final PROPERTY propertyType;
          /**
           * The value of this property.
           */
          protected final DATATYPE value;
  
          public abstract int getIndex();
  
          /**
           * Get the serialized value of this property.
           * <p>
           * Different from the value, the serialized value is the value that will be stored in the block state nbt.
           * For example, the value of a boolean property is a boolean, but the serialized value is a byte.
           *
           * @return the serialized value
           */
          public abstract SERIALIZED_DATATYPE getSerializedValue();
  
          @Override
          public String toString() {
              return propertyType.getName() + "=" + getSerializedValue();
          }
      }
  }
  