/*
  Copyright (C) 2009-2017  Brazil
  Copyright (C) 2018-2024  Sutou Kouhei <kou@clear-code.com>

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License version 2.1 as published by the Free Software Foundation.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/

#pragma once

#include "grn.h"

#ifdef __cplusplus
extern "C" {
#endif

#define GRN_JSON_LOAD_OPEN_BRACKET 0x40000000
#define GRN_JSON_LOAD_OPEN_BRACE   0x40000001

typedef struct grn_load_input_ {
  grn_content_type type;
  grn_raw_string table;
  grn_raw_string columns;
  grn_raw_string values;
  grn_raw_string if_exists;
  grn_raw_string each;
  grn_bool output_ids;
  grn_bool output_errors;
  grn_bool lock_table;
  uint32_t emit_level;
} grn_load_input;

void
grn_load_internal(grn_ctx *ctx, grn_load_input *input);

typedef enum {
  GRN_LOADER_BEGIN = 0,
  GRN_LOADER_TOKEN,
  GRN_LOADER_STRING,
  GRN_LOADER_SYMBOL,
  GRN_LOADER_NUMBER,
  GRN_LOADER_STRING_ESC,
  GRN_LOADER_UNICODE0,
  GRN_LOADER_UNICODE1,
  GRN_LOADER_UNICODE2,
  GRN_LOADER_UNICODE3,
  GRN_LOADER_END
} grn_loader_stat;

/*
 * Status of target columns used in Format 1.
 * Target columns are specified via --columns or the first array in a Format 1
 * JSON object.
 */
typedef enum {
  GRN_LOADER_COLUMNS_UNSET = 0, /* Columns are not available. */
  GRN_LOADER_COLUMNS_SET,       /* Columns are available. */
  GRN_LOADER_COLUMNS_BROKEN     /* Columns are specified but broken. */
} grn_loader_columns_status;

typedef struct {
  grn_obj values;
  grn_obj level;
  grn_hash *columns;
  grn_obj ranges;
  grn_obj indexes;
  grn_obj ids;
  grn_obj return_codes;
  grn_obj error_messages;
  uint32_t emit_level;
  int32_t id_offset;  /* Position of _id in values or -1 if _id is N/A. */
  int32_t key_offset; /* Position of _key in values or -1 if _key is N/A. */
  grn_obj *last;
  grn_obj *table;
  grn_obj *ifexists;
  grn_obj *each;
  uint32_t unichar;
  uint32_t unichar_hi;
  uint32_t values_size;
  uint32_t n_records;
  uint32_t n_record_errors;
  uint32_t n_column_errors;
  grn_loader_stat stat;
  grn_content_type input_type;
  grn_loader_columns_status columns_status;
  struct {
    grn_rc rc;
    char buffer[GRN_CTX_MSGSIZE];
    uint32_t line;
    const char *file;
    const char *func;
  } error;
  grn_bool output_ids;
  grn_bool output_errors;
  grn_bool lock_table;
} grn_loader;

typedef struct {
  grn_obj *table;
  uint32_t depth;
  grn_obj *record_value;
  grn_id id;
  grn_obj *key;
  struct {
    const char *column_name;
    uint32_t column_name_size;
    grn_obj *column;
    grn_obj *value;
  } current;
} grn_loader_add_record_data;

void
grn_loader_save_error(grn_ctx *ctx, grn_loader *loader);
void
grn_loader_on_record_added(grn_ctx *ctx, grn_loader *loader, grn_id id);
void
grn_loader_on_column_set(grn_ctx *ctx,
                         grn_loader *loader,
                         grn_loader_add_record_data *data);
void
grn_loader_on_no_identifier_error(grn_ctx *ctx,
                                  grn_loader *loader,
                                  grn_obj *table);
void
grn_loader_merge(grn_ctx *ctx, grn_loader *loader, grn_loader *loader_other);
grn_id
grn_loader_add_record(grn_ctx *ctx,
                      grn_loader *loader,
                      grn_loader_add_record_data *data);
grn_obj *
grn_loader_get_column(grn_ctx *ctx,
                      grn_loader *loader,
                      const char *name,
                      size_t name_length);
void
grn_loader_apply_each(grn_ctx *ctx, grn_loader *loader, grn_id id);

void
grn_p_loader(grn_ctx *ctx, grn_loader *loader);

#ifdef __cplusplus
}
#endif
