#include "application.h"
#include "check.h"
#include "colors.h"
#include "config.h"
#include "error.h"
#include "internal.h"
#include "parse.h"
#include "print.h"
#include "proof.h"
#include "resources.h"
#include "witness.h"
#include "simplify.h"

#include <inttypes.h>
#include <string.h>
#include <unistd.h>
#include <time.h>

typedef struct application application;



void init_app(application *application, kissat *solver)
{
    memset(application, 0, sizeof *application);
    application->solver = solver;
    application->witness = true;
    application->time = 0;
    application->conflicts = -1;
    application->decisions = -1;
    application->strict = NORMAL_PARSING;
}

static void print_common_dimacs_and_proof_usage(void)
{
    printf("\n");
    printf("Furthermore '<dimacs>' is the input file in DIMACS format.\n");
#ifndef NPROOFS
    printf("If '<proof>' is specified then a proof trace is written.\n");
#endif
}

static void print_complete_dimacs_and_proof_usage(void)
{
    printf("\n");
    printf("Furthermore '<dimacs>' is the input file in DIMACS format.\n");
#ifdef _POSIX_C_SOURCE
    printf("The solver reads from '<stdin>' if '<dimacs>' is unspecified.\n");
    printf("If the path has a '.bz2', '.gz', '.lzma', '7z' or '.xz' suffix\n");
    printf("then the solver tries to find a corresponding decompression\n");
    printf("tool ('bzip2', 'gzip', 'lzma', '7z', or 'xz') to decompress\n");
    printf("the input file on-the-fly after checking that the input file\n");
    printf("has the correct format (starts with the corresponding\n");
    printf("signature bytes).\n");
#endif
    printf("\n");
#ifndef NPROOFS
    printf("If '<proof>' is specified then a proof trace is written to the\n");
    printf("given file.  If the file name is '-' then the proof is written\n");
    printf("to '<stdout>'."); // In this case the ASCII version of the DRAT format\n");
    // printf("is used.  For real files the binary proof format is used unless\n");
    // printf("'--no-binary' is specified.\n");
    printf("\n");
#ifdef _POSIX_C_SOURCE
    printf("Writing of compressed proof files follows the same principle\n");
    printf("as reading compressed files. The compression format is based\n");
    printf("on the file suffix and it is checked that the corresponding\n");
    printf("compression utility can be found.\n");
#else
    printf("The solver was built without POSIX support. Thus compressed\n");
    printf("and unlocked reading and writing are not available. This is\n");
    printf("usually enforced by the '-p' (pedantic) configuration. If you\n");
    printf("need compressed reading and writing then configure and build\n");
    printf("the solver without '-p'. This will also speed-up file I/O.\n");
#endif
#else
    printf("The solver was built without proof support. If you need proofs\n");
    printf("use a configuration without '--no-proofs' nor '--ultimate'.\n");
#endif
}

static void print_common_usage(void)
{
    printf("usage: kissat [ <option> ... ] [ <dimacs> "
#ifndef NPROOFS
        "[ <proof> ] "
#endif
        "]\n"
        "\n"
        "where '<option>' is one of the following common options:\n"
        "\n"
        "  -h      print this list of common command line options\n"
        "  --help  print complete list of command line options\n");
    printf("\n");
#ifndef NPROOFS
    printf("  -f      force writing proof (to existing CNF alike file)\n");
#endif
#if !defined(QUIET) && defined(LOGGING)
    printf("  -l      increase logging level (implies '-v' twice)\n");
#endif
    printf("  -n      do not print satisfying assignment\n");
#ifndef QUIET
    printf("\n");
    printf("  -q      suppress all messages\n");
    printf("  -s      print complete statistics\n");
    printf("  -v      increase verbose level\n");
#endif
    print_common_dimacs_and_proof_usage();
}

static void print_complete_usage(void)
{
    printf("usage: kissat [ <option> ... ] [ <dimacs> "
#ifndef NPROOFS
        "[ <proof> ] "
#endif
        "]\n"
        "\n"
        "where '<option>' is one of the following common options:\n"
        "\n"
        "  --help  print this list of all command line options\n"
        "  -h      print only reduced list of command line options\n");
    printf("\n");
#ifndef NPROOFS
    printf("  -f      force writing proof (to existing CNF alike file)\n");
#endif
#if !defined(QUIET) && defined(LOGGING)
    printf("  -l      print logging messages"
#ifndef NOPTIONS
        " (see also '--log')"
#endif
        "\n");
#endif
    printf("  -n      do not print satisfying assignment\n");
#ifndef QUIET
    printf("\n");
    printf("  -q      suppress all messages"
#ifndef NOPTIONS
        " (see also '--quiet')"
#endif
        "\n");
    printf("  -s      print all statistics"
#ifndef NOPTIONS
        " (see also '--statistics')"
#endif
        "\n");
    printf("  -v      increase verbose level"
#ifndef NOPTIONS
        " (see also '--verbose')"
#endif
        "\n");
#endif
    printf("\n");
    printf("Further '<option>' can be one of the "
        "following less frequent options:\n");
    printf("\n");
    printf("  --banner             print solver information\n");
    printf("  --color              "
        "use colors (default if connected to terminal)\n");
    printf("  --no-color           "
        "no colors (default if not connected to terminal)\n");
#ifndef NOPTIONS
    printf("  --embedded           print embedded option list\n");
#endif
#ifndef NPROOFS
    printf("  --force              same as '-f' (force writing proof)\n");
#endif
    printf("  --id                 print GIT identifier\n");
#ifndef NOPTIONS
    printf("  --range              print option range list\n");
#endif
    printf("  --relaxed            relaxed parsing"
        " (ignore DIMACS header)\n");
    printf("  --strict             stricter parsing"
        " (no empty header lines)\n");
    printf("  --version            print version and exit\n");
    printf("\n");
    printf("The following solving limits can be enforced:\n");
    printf("\n");
    printf("  --conflicts=<limit>\n");
    printf("  --decisions=<limit>\n");
    printf("\n");
    printf("Satisfying assignments have by default values for all variables\n");
    printf("unless '--partial' is specified, then only values are printed\n");
    printf("for variables which are necessary to satisfy the formula.\n");
    printf("\n");
#ifndef NOPTIONS
    printf("The following predefined option settings are supported:\n");
    printf("\n");
    kissat_configuration_usage();
    printf("\n");
    printf("Or '<option>' is one of the following long options:\n\n");
    kissat_options_usage();
#else
    printf("The solver was configured without options ('--no-options').\n");
    printf("Thus all internal options are fixed and can not be changed.\n");
    printf("If you want to change them at run-time use a configuration\n");
    printf("without '--no-options'. Note, that '--extreme', '-competition'\n");
    printf("as well as '--ultimate' all enforce '--no-options' as well.\n");
#ifdef SAT
    printf("The '--sat' option is ignored since set at compile time.\n");
#elif UNSAT
    printf("The '--unsat' option is ignored since set at compile time.\n");
#else
    printf("The '--default' option is ignored but allowed.\n");
#endif
#endif
    print_complete_dimacs_and_proof_usage();
}

static bool parsed_one_option_and_return_zero_exit_code(char *arg)
{
    if (!strcmp(arg, "-h")) {
        print_common_usage();
        return true;
    }
    if (!strcmp(arg, "--help")) {
        print_complete_usage();
        return true;
    }
    if (!strcmp(arg, "--banner")) {
        kissat_banner(0, "KISSAT SAT Solver");
        return true;
    }
    if (!strcmp(arg, "--compiler")) {
        printf("%s\n", kissat_compiler());
        return true;
    }
#ifndef NOPTIONS
    if (!strcmp(arg, "--embedded")) {
        kissat_print_embedded_option_list();
        return true;
    }
#endif
    if (!strcmp(arg, "--id")) {
        printf("%s\n", kissat_id());
        return true;
    }
#ifndef NOPTIONS
    if (!strcmp(arg, "--range")) {
        kissat_print_option_range_list();
        return true;
    }
#endif
    if (!strcmp(arg, "--version")) {
        printf("%s\n", kissat_version());
        return true;
    }
    return false;
}

static const char *single_first_option_table[] = {
    "-h",
    "--help",
    "--banner",
    "--compiler",
#ifndef NOPTIONS
    "--embedded",
#endif
    "--id",
#ifndef NOPTIONS
    "--range",
#endif
    "--version"
};

static bool single_first_option(const char *arg)
{
    const unsigned size = sizeof single_first_option_table / sizeof(char *);
    for (unsigned i = 0; i < size; i++)
        if (!strcmp(single_first_option_table[i], arg))
            return true;
    return false;
}

#define ERROR(...)                 \
    do {                           \
        kissat_error(__VA_ARGS__); \
        return false;              \
    } while (0)

#ifndef NPROOFS

static bool most_likely_existing_cnf_file(const char *path)
{
    if (!kissat_file_readable(path))
        return false;

    if (kissat_has_suffix(path, ".dimacs"))
        return true;
    if (kissat_has_suffix(path, ".dimacs.7z"))
        return true;
    if (kissat_has_suffix(path, ".dimacs.bz2"))
        return true;
    if (kissat_has_suffix(path, ".dimacs.gz"))
        return true;
    if (kissat_has_suffix(path, ".dimacs.lzma"))
        return true;
    if (kissat_has_suffix(path, ".dimacs.xz"))
        return true;

    if (kissat_has_suffix(path, ".cnf"))
        return true;
    if (kissat_has_suffix(path, ".cnf.7z"))
        return true;
    if (kissat_has_suffix(path, ".cnf.bz2"))
        return true;
    if (kissat_has_suffix(path, ".cnf.gz"))
        return true;
    if (kissat_has_suffix(path, ".cnf.lzma"))
        return true;
    if (kissat_has_suffix(path, ".cnf.xz"))
        return true;

    return false;
}

#endif

#ifndef NPROOFS

#define LONG_FALSE_OPTION(ARG, NAME) \
    (!strcmp((ARG), "--no-" NAME) || !strcmp((ARG), "--" NAME "=0") || !strcmp((ARG), "--" NAME "=false"))

#endif

#define LONG_TRUE_OPTION(ARG, NAME) \
    (!strcmp((ARG), "--" NAME) || !strcmp((ARG), "--" NAME "=1") || !strcmp((ARG), "--" NAME "=true"))

bool parse_options(application *application, int argc, char **argv)
{
    kissat *solver = application->solver;
    const char *strict_option = 0;
#ifndef NOPTIONS
    const char *configuration = 0;
#endif
#ifndef NPROOFS
    const char *force_option = 0;
#endif
    const char *valstr;
    for (int i = 1; i < argc; i++) {
        const char *arg = argv[i];
        if (single_first_option(arg))
            ERROR("option '%s' only allowed as %s argument", arg, i == 1 ? "single" : "first");
#ifndef NPROOFS
        else if (!strcmp(arg, "-f") || LONG_TRUE_OPTION(arg, "force") || LONG_TRUE_OPTION(arg, "forced")) {
            if (application->force) {
                assert(force_option);
                if (!strcmp(force_option, arg))
                    ERROR("multiple '%s' options", force_option);
                else
                    ERROR("'%s' and '%s' have the same effect", force_option, arg);
            }
            application->force = true;
            force_option = arg;
        }
#endif
        else if (LONG_TRUE_OPTION(arg, "relax") || LONG_TRUE_OPTION(arg, "relaxed")) {
            if (strict_option) {
                if (application->strict != RELAXED_PARSING)
                    ERROR("can not combine contradictory '%s' and '%s'", strict_option, arg);
                else if (!strcmp(strict_option, arg))
                    ERROR("multiple '%s' options", strict_option);
                else
                    ERROR("'%s' and '%s' have the same effect", strict_option, arg);
            }
            application->strict = RELAXED_PARSING;
            strict_option = arg;
        } else if (LONG_TRUE_OPTION(arg, "strict") || LONG_TRUE_OPTION(arg, "stricter") ||
            LONG_TRUE_OPTION(arg, "pedantic")) {
            if (strict_option) {
                if (application->strict != PEDANTIC_PARSING)
                    ERROR("can not combine contradictory '%s' and '%s'", strict_option, arg);
                else if (!strcmp(strict_option, arg))
                    ERROR("multiple '%s' options", strict_option);
                else
                    ERROR("'%s' and '%s' have the same effect", strict_option, arg);
            }
            application->strict = PEDANTIC_PARSING;
            strict_option = arg;
        }
#if defined(LOGGING) && !defined(QUIET) && !defined(NOPTIONS)
        else if (!strcmp(arg, "-l")) {
            int value = GET_OPTION(log);
            if (value < INT_MAX)
                value++;
            kissat_set_option(solver, "log", value);
        }
#endif
        else if (!strcmp(arg, "-n"))
            application->witness = false;
#if !defined(QUIET) && !defined(NOPTIONS)
        else if (!strcmp(arg, "-q"))
            kissat_set_option(solver, "quiet", 1);
        else if (!strcmp(arg, "-s"))
            kissat_set_option(solver, "statistics", 1);
        else if (!strcmp(arg, "-v")) {
            int value = GET_OPTION(verbose);
            if (value < INT_MAX)
                value++;
            kissat_set_option(solver, "verbose", value);
        }
#endif
        else if (!strcmp(arg, "--color") || !strcmp(arg, "--colors") || !strcmp(arg, "--colour") ||
            !strcmp(arg, "--colours"))
            kissat_force_colors();
        else if (!strcmp(arg, "--no-color") || !strcmp(arg, "--no-colors") || !strcmp(arg, "--no-colour") ||
            !strcmp(arg, "--no-colours"))
            kissat_force_no_colors();
        else if ((valstr = kissat_parse_option_name(arg, "time"))) {
            int val;
            if (kissat_parse_option_value(valstr, &val) && val > 0) {
                if (application->time > 0)
                    ERROR("multiple '--time=%d' and '%s'", application->time, arg);
                application->time = val;
                alarm(val);
            } else
                ERROR("invalid argument in '%s' (try '-h')", arg);
        } else if ((valstr = kissat_parse_option_name(arg, "conflicts"))) {
            int val;
            if (kissat_parse_option_value(valstr, &val) && val >= 0) {
                if (application->conflicts >= 0)
                    ERROR("multiple '--conflicts=%d' and '%s'", application->conflicts, arg);
                kissat_set_conflict_limit(solver, val);
                application->conflicts = val;
            } else
                ERROR("invalid argument in '%s' (try '-h')", arg);
        } else if ((valstr = kissat_parse_option_name(arg, "decisions"))) {
            int val;
            if (kissat_parse_option_value(valstr, &val) && val >= 0) {
                if (application->decisions >= 0)
                    ERROR("multiple '--decisions=%d' and '%s'", application->decisions, arg);
                kissat_set_decision_limit(solver, val);
                application->decisions = val;
            } else
                ERROR("invalid argument in '%s' (try '-h')", arg);
        } else if (!strcmp(arg, "--partial"))
            application->partial = true;
#ifndef NPROOFS
        else if (LONG_FALSE_OPTION(arg, "binary"))
            application->binary = -1;
        else if (LONG_TRUE_OPTION(arg, "binary")) {
            application->binary = 1;
        }
#endif
#ifndef NOPTIONS
        else if (arg[0] == '-' && arg[1] == '-' && kissat_has_configuration(arg + 2)) {
            if (configuration)
                ERROR("multiple configurations '%s' and '%s'", configuration, arg);
            kissat_set_configuration(solver, arg + 2);
            configuration = arg;
        } else if (arg[0] == '-' && arg[1] == '-') {
            char name[kissat_options_max_name_buffer_size];
            int value;
            if (!kissat_options_parse_arg(arg, name, &value))
                ERROR("invalid long option '%s' (try '-h')", arg);
            kissat_set_option(solver, name, value);
        }
#else
#ifdef SAT
        else if (!strcmp(arg, "--sat"))
            ;
#elif defined(UNSAT)
        else if (!strcmp(arg, "--unsat"))
            ;
#else
        else if (!strcmp(arg, "--default"))
            ;
#endif
        else if (arg[0] == '-' && arg[1] == '-')
            ERROR("invalid long option '%s' "
                "(configured with '--no-options')",
                arg);
#endif
#ifdef QUIET
        else if (arg[0] == '-' && !arg[2] && (arg[1] == 'q' || arg[1] == 's' || arg[1] == 'v'))
            ERROR("invalid short option '%s' (configured with '-q')", arg);
#endif
#ifndef LOGGING
        else if (!strcmp(arg, "-l"))
            ERROR("invalid short option '%s' (configured without '-l')", arg);
#endif
#ifdef NOPTIONS
        else if (arg[0] == '-' && !arg[2] && (arg[1] == 'l' || arg[1] == 'q' || arg[1] == 's' || arg[1] == 'v'))
            ERROR("invalid short option '%s' "
                "(configured with '--no-options')",
                arg);
#endif
        else if (arg[0] == '-' && arg[1])
            ERROR("invalid short option '%s' (try '-h')", arg);
#ifndef NPROOFS
        else if (application->proof_path)
            ERROR("three file arguments '%s', '%s' and '%s' (try '-h')", application->input_path,
                application->proof_path, arg);
#endif
        else if (application->input_path) {
#ifndef NPROOFS
            if (!application->force && most_likely_existing_cnf_file(arg))
                ERROR("not writing proof to '%s' file (use '-f')", arg);
            if (!kissat_file_writable(arg))
                ERROR("can not write proof to '%s'", arg);
            application->proof_path = arg;
#else
            ERROR("two file arguments '%s' and '%s' without proof support "
                "(try '-h')",
                application->input_path, arg);
#endif
        } else {
            if (!kissat_file_readable(arg))
                ERROR("can not read '%s'", arg);
            application->input_path = arg;
        }
    }
#if !defined(QUIET) && !defined(NOPTIONS)
    if (kissat_get_option(solver, "quiet")) {
        if (kissat_get_option(solver, "statistics"))
            ERROR("can not use '--quiet' ('-q') with '--statistics' ('-s')");
        if (kissat_get_option(solver, "verbose"))
            ERROR("can not use '--quiet' ('-q') with '--verbose' ('-v')");
    }
#endif
    solver->step_chb = 0.1 * GET_OPTION(stepchb);
    solver->heuristic = GET_OPTION(heuristic);
    solver->mab = GET_OPTION(mab);
    solver->mode_mab = GET_OPTION(modemab);
    if (solver->mab) {
        for (unsigned i = 0; i < solver->mab_heuristics; i++) {
            solver->mab_reward[i] = 0;
            solver->mab_select[i] = 0;
            // printf("mab time uninitialized: %d %g\n", i, solver->mab_time[i]);
            solver->mab_time[i] = 0;
            solver->mab_propagations[i] = 0;
            solver->mab_ticks[i] = 0;
        }
        solver->mabc = GET_OPTION(mabcint) + 0.1 * GET_OPTION(mabcdecimal);
        solver->mab_select[solver->heuristic]++;
        solver->mab_tot_time = 0;
        solver->mab_last_time = 0;
        solver->mab_tot_propagations = 0;
        solver->mab_last_propagations = 0;
        solver->mab_last_ticks = 0;
        solver->mab_tot_ticks = 0;
    }
    if (solver->mode_mab) {
        solver->modec = GET_OPTION(modecint) + 0.1 * GET_OPTION(mabcdecimal);
    }
    //solver->max_seed_count = GET_OPTION(geneseedcount);
    //INIT_STACK(solver->seeds);
    return true;
}

static bool parse_input(application *application)
{
#ifndef QUIET
    double entered = kissat_process_time();
#endif
    kissat *solver = application->solver;
    // uint64_t lineno;
    file file;
    const char *path = application->input_path;
    if (!path)
        kissat_read_already_open_file(&file, stdin, "<stdin>");
    else if (!kissat_open_to_read_file(&file, path))
        ERROR("failed to open '%s' for reading", path);
    kissat_section(solver, "parsing");
    kissat_message(solver, "opened and reading %sDIMACS file:", file.compressed ? "compressed " : "");
    kissat_message(solver, "");
    kissat_message(solver, "  %s", file.path);
    kissat_message(solver, "");
    // const char *error = kissat_parse_dimacs(solver, application->strict, &file,
    //                                         &lineno, &application->max_var);
    bool res = kissat_simplify(solver, &application->max_var, &file);
    // printf("fgafsda\n");

    if (!res) {
        printf("c solved by simplify\n");
        return false;
    }
    kissat_close_file(&file);
    // if (error)
    //    ERROR("%s:%" PRIu64 ": parse error: %s", file.path, lineno, error);
#ifndef QUIET
    kissat_message(solver, "closing input after reading %s", FORMAT_BYTES(file.bytes));
    if (file.compressed) {
        assert(path);
        size_t bytes = kissat_file_size(path);
        kissat_message(solver, "inflated input file of size %s by %.2f", FORMAT_BYTES(bytes),
            kissat_average(file.bytes, bytes));
    }
    kissat_message(solver, "finished parsing after %.2f seconds", kissat_process_time() - entered);
#endif
    return true;
}

#ifndef NPROOFS

static bool write_proof(application *application)
{
    const char *path = application->proof_path;
    if (!path)
        return true;
    file *file = &application->proof_file;
    bool binary = true; // binary == true: DRAT, binary == false: pseudo boolean
    if (!strcmp(path, "-")) {
        binary = false;
        kissat_write_already_open_file(file, stdout, "<stdout>");
    } else if (!kissat_open_to_write_file(file, path))
        ERROR("failed to open and write proof to '%s'", path);
    else {
        if (application->binary < 0)
            binary = false;
        if (application->binary > 0) {
            binary = true;
        }
    }
    kissat_init_proof(application->solver, file, binary);
#ifndef QUIET
    kissat *solver = application->solver;
    kissat_section(solver, "proving");
    kissat_message(solver, "%swriting proof to %spbp file:", file->close ? "opened and " : "",
        file->compressed ? "compressed " : "");
    kissat_message(solver, "");
    kissat_message(solver, "  %s", file->path);
#endif
    return true;
}

static void close_proof(application *application, int res)
{
    const char *path = application->proof_path;
    if (!path)
        return;
    kissat_release_proof(application->solver, res);
    kissat_close_file(&application->proof_file);
}

#endif

#ifndef QUIET

#ifndef NOPTIONS
static void print_option(kissat *solver, int value, const opt *o)
{
    char buffer[96];
    const bool b = (o->low == 0 && o->high == 1);
    const char *val_str = FORMAT_VALUE(b, value);
    const char *def_str = FORMAT_VALUE(b, o->value);
    sprintf(buffer, "%s=%s", o->name, val_str);
    kissat_message(solver, "--%-30s (%s default '%s')", buffer, (value == o->value ? "same as" : "different from"),
        def_str);
}
#endif

#ifndef NOPTIONS
static void print_options(kissat *solver)
{
    const int verbosity = kissat_verbosity(solver);
    if (verbosity < 0)
        return;
    size_t printed = 0;
    for (all_options(o)) {
        const int value = *kissat_options_ref(&solver->options, o);
        if (o->value != value || verbosity > 0) {
            if (!printed++)
                kissat_section(solver, "options");

            print_option(solver, value, o);
        }
    }
}
#endif

static void print_limits(application *application)
{
    kissat *solver = application->solver;
    const int verbosity = kissat_verbosity(solver);
    if (verbosity < 1 && application->conflicts < 0 && application->decisions < 0)
        return;

    kissat_section(solver, "limits");
    if (!application->time && application->conflicts < 0 && application->conflicts < 0)
        kissat_message(solver, "no time, conflict nor decision limit set");
    else {
        if (application->time)
            kissat_message(solver, "time limit set to %d seconds", application->time);
        else if (verbosity > 0)
            kissat_message(solver, "no time limit");

        if (application->conflicts >= 0)
            kissat_message(solver, "conflict limit set to %d conflicts", application->conflicts);
        else if (verbosity > 0)
            kissat_message(solver, "no conflict limit");

        if (application->decisions >= 0)
            kissat_message(solver, "decision limit set to %d decisions", application->decisions);
        else if (verbosity > 0)
            kissat_message(solver, "no decision limit");
    }
}

#endif


/* void kissat_check_a (kissat * solver)
{
  kissat_message (solver, "checking assignment\n");
  const int *begin = BEGIN_STACK (solver->original);
  const int *end = END_STACK (solver->original), *q;

  size_t count = 0;

  for (const int *p = begin; p != end; p = q + 1)
    {
      bool satisfied = false;
      int lit;
      for (q = p; (lit = *q); q++)
    if (!satisfied && kissat_value (solver, lit) == lit)
      satisfied = true;

      count++;

      if (satisfied)
    continue;
      kissat_fatal_message_start ();
      fputs ("unsatisfied clause:\n", stderr);
      for (q = p; (lit = *q); q++)
    fprintf (stderr, "%d ", lit);
      fputs ("0\n", stderr);
      fflush (stderr);
      kissat_abort ();
    }
    kissat_message (solver, "assignment satisfies all original clauses\n");

} */

int kissat_application(kissat *solver, int argc, char **argv)
{
    if (argc == 2)
        if (parsed_one_option_and_return_zero_exit_code(argv[1]))
            return 0;
    application application;
    init_app(&application, solver);
    if (!parse_options(&application, argc, argv))
        return 1;
#ifndef QUIET
    kissat_section(solver, "banner");
    if (!GET_OPTION(quiet))
        kissat_banner("c ", "KISSAT SAT Solver");
#endif
#ifndef NPROOFS
    if (!write_proof(&application))
        return 1;
#endif
    if (!parse_input(&application)) {
        printf("c UNSATISFIABLE\n");
        printf("p cnf 1 1\n");
        printf("0\n");
        fflush(stdout);
#ifndef NPROOFS
        // CHECK_AND_ADD_EMPTY();
        // ADD_EMPTY_TO_PROOF();
        close_proof(&application, 20);
#endif
        return 20;
    }
#ifndef QUIET
#ifndef NOPTIONS
    print_options(solver);
#endif
    print_limits(&application);
    kissat_section(solver, "solving");
#endif
    int res = 0;
#ifndef QUIET
    kissat_print_statistics(solver);
#endif
#ifndef NPROOFS
    close_proof(&application, res);
#endif
#ifndef QUIET
    kissat_section(solver, "shutting down");
    kissat_message(solver, "exit %d", res);
#endif
    //    kissat_message(solver, "exit time %g", kissat_process_time());

    return res;
}
