#ifndef DATABASEINFO_H
#define DATABASEINFO_H

struct DatabaseInfo {
public:
  enum class Table : int {
    AdditionalVariables,
    Attributes,
    PriceHistoryRecords,
    ProductAttributes,
    ProductInflowRecords,
    ProductOutflowRecords,
    ProductTypes,
    ProductValues,
    ProductWriteOffRecords,
    Products,
    Suppliers,
    WriteOffReasons,
  };
  enum class View : int { ProductProperties, AvailableProductTypes };
  enum class Column : unsigned int {
    AdditionalVariables_Id,
    AdditionalVariables_Name,
    AdditionalVariables_Value,
    Attributes_Id,
    Attributes_Name,
    PriceHistoryRecords_Id,
    PriceHistoryRecords_ProductId,
    PriceHistoryRecords_Datetime,
    PriceHistoryRecords_Price,
    ProductAttributes_ProductId,
    ProductAttributes_AttributeId,
    ProductInflowRecords_Id,
    ProductInflowRecords_ProductId,
    ProductInflowRecords_Barcode,
    ProductInflowRecords_SupplierId,
    ProductInflowRecords_Count,
    ProductInflowRecords_FullPrice,
    ProductInflowRecords_Datetime,
    ProductOutflowRecords_Id,
    ProductOutflowRecords_ProductId,
    ProductOutflowRecords_Barcode,
    ProductOutflowRecords_Count,
    ProductOutflowRecords_Datetime,
    ProductTypes_Id,
    ProductTypes_ParentId,
    ProductTypes_Name,
    ProductValues_Id,
    ProductValues_ProductId,
    ProductValues_AttributeId,
    ProductValues_Value,
    ProductWriteOffRecords_Id,
    ProductWriteOffRecords_ProductId,
    ProductWriteOffRecords_Barcode,
    ProductWriteOffRecords_ReasonId,
    ProductWriteOffRecords_Count,
    ProductWriteOffRecords_Datetime,
    Products_Id,
    Products_Barcode,
    Products_Name,
    Products_ProductTypeId,
    Suppliers_Id,
    Suppliers_Name,
    Suppliers_Address,
    Suppliers_TelephoneNumber,
    WriteOffReasons_Id,
    WriteOffReasons_Name,
    Products_ProductTypes_ProductId,
    Products_ProductTypes_Barcode,
    Products_ProductTypes_ProductTypeId,
    Products_ProductTypes_ProductName,
    Products_ProductTypes_ProductTypeName,
    ProductProperties_ProductId,
    ProductProperties_AttributeId,
    ProductProperties_Name,
    ProductProperties_Value,
    AvailableProductTypes_Id,
    AvailableProductTypes_ParentId,
    AvailableProductTypes_Name
  };
  // the order corresponds to the record number
  enum class Attribute : int {
    ArticleNumber = 1,
    DateOfManufacture,
    ExpirationDate,
    Unit
  };

public:
  static constexpr const char *name(Table table);
  static constexpr const char *name(View view);
  static constexpr const char *name(Column column);
  static constexpr unsigned int ordinalNumber(Column column);
  static constexpr unsigned int indexNumber(Column column);
};

#include "databaseinfo.tpp"

#ifndef NDATABASE_INFO_MACRO

#define TABLE DatabaseInfo::Table
#define VIEW DatabaseInfo::View
#define COLUMN DatabaseInfo::Column

#define NAME(value) DatabaseInfo::name((value))
#define NUMBER(value) DatabaseInfo::ordinalNumber((value))
#define INDEX(value) DatabaseInfo::indexNumber((value))

#define ASSERT_NAME(value) assert((value) != nullptr)
#define ASSERT_NUMBER(value) assert((value) > 0)
#define ASSERT_INDEX(value) assert((value) < UINT_MAX)

#define CREATE_NAME(variableName, variableValue)                               \
  auto((variableName)) = NAME((variableValue));                                \
  ASSERT_NAME(variableName)

#define CREATE_NUMBER(variableName, variableValue)                             \
  auto((variableName)) = NUMBER((variableValue));                              \
  ASSERT_NUMBER(variableName)

#define CREATE_INDEX(variableName, variableValue)                              \
  auto((variableName)) = INDEX((variableValue));                               \
  ASSERT_INDEX(variableName)

#endif // NDATABASE_INFO_MACRO

#endif // DATABASEINFO_H
