/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 
/* vim: set ts=2 et sw=2 tw=80: */
/*
  Copyright 2013-2021 The Libfossil Authors, see LICENSES/BSD-2-Clause.txt

  SPDX-License-Identifier: BSD-2-Clause-FreeBSD
  SPDX-FileCopyrightText: 2021 The Libfossil Authors
  SPDX-ArtifactOfProjectName: Libfossil
  SPDX-FileType: Code
*/
/**
   This is a test app demonstrating creating a repository and checking
   in files without an associated checkout.
*/
#ifdef NDEBUG
/* Force assert() to always be in effect. */
#undef NDEBUG
#endif
#include "fossil-scm/fossil-cli.h"
#include "fossil-scm/fossil-internal.h"
//#include <string.h>

// Only for testing/debugging..
#define MARKER(pfexp)                                               \
  do{ printf("MARKER: %s:%d:%s():\t",__FILE__,__LINE__,__func__);   \
    printf pfexp;                                                   \
  } while(0)

// Global app state.
struct App_ {
  char const * repoDbName;
  bool addEmptyCommit;
} App = {
"_ciwoco.f",
true/*addEmptyCommit*/
};

static int repo_create(bool addEgg){
  int rc;
  fsl_cx * const f = fcli_cx();
  fsl_repo_create_opt cOpt = fsl_repo_create_opt_empty;
  if(addEgg){
    cOpt.commitMessage =
      "This is a repo. There are many like it "
      "but this one is mine.";
  }else{
    cOpt.commitMessage = NULL;
  }
  cOpt.filename = App.repoDbName;
  fsl_file_unlink(cOpt.filename);
  rc = fsl_repo_create(f, &cOpt);
  assert(0==rc);
  assert(fsl_cx_db_repo(f));
  return rc;
}

static int app_stuff(void){
  int rc = 0;
  fsl_cx * const f = fcli_cx();
  fsl_buffer content = fsl_buffer_empty;
  fsl_deck d = fsl_deck_empty;
  char const *fname = 0;
  rc = repo_create(App.addEmptyCommit);
  if(rc) goto end;
  f_out("(Re)created repo: %s\n", fsl_cx_db_file_repo(f, NULL));
  if(App.addEmptyCommit){
    f_out("Empty initial commit was added.\n");
  }else{
    f_out("No empty initial commit was created.\n");
  }
  assert(fsl_needs_repo(f));
  rc = fsl_cx_transaction_begin(f);
  if(rc) goto end;
  if(App.addEmptyCommit){
    rc = fsl_deck_load_sym(f, &d, "trunk", FSL_SATYPE_CHECKIN);
    assert(0==rc);
    assert(f==d.f);
    f_out("Deriving from checking %s\n", d.uuid);
    rc = fsl_deck_derive(&d);
    assert(0==rc);
  }else{
    fsl_deck_init(f, &d, FSL_SATYPE_CHECKIN);
  }
  rc = fsl_deck_D_set(&d, fsl_julian_now());
  assert(0==rc);
  rc = fsl_deck_C_set(&d, "Files added w/o checkout.", -1);
  assert(0==rc);
  rc = fsl_deck_U_set(&d, "ciwoco");
  assert(0==rc);

  char const * fnames[] = {
    "f-test-ciwoco.c",
    "Makefile.in",
  NULL
  };
  for( int i = 0; (fname = fnames[i]); ++i ){
    rc = fsl_buffer_fill_from_filename(&content, fname);
    assert(0==rc);
    rc = fsl_deck_F_set_content(&d, fname, &content,
                                FSL_FILE_PERM_REGULAR, NULL);
    assert(0==rc);
    f_out("Added file: %s\n", fname);
  }
  rc = fsl_deck_save(&d, false);
  assert(0==rc);

  f_out("Saved checkin %s\n", d.uuid);
  assert(fsl_cx_transaction_level(f)>0);
  rc = fsl_cx_transaction_end(f, false);
  end:
  if(fsl_cx_transaction_level(f)){
    fsl_cx_transaction_end(f, true);
  }
  fsl_deck_finalize(&d);
  fsl_buffer_clear(&content);
  if(!rc){
    f_out("Results are in repo file %s\n", App.repoDbName);
  }
  return rc;
}

int main(int argc, const char * const * argv ){
  /**
     Set up flag handling, which is used for processing
     basic CLI flags and generating --help text output.
  */
  const fcli_cliflag FCliFlags[] = {
    FCLI_FLAG_BOOL_INVERT("e", "empty", &App.addEmptyCommit,
                          "If set, do not create the initial "
                          "empty checkin."),
    fcli_cliflag_empty_m // list MUST end with this (or equivalent)
  };
  const fcli_help_info FCliHelp = {
    "A demo of creating a new repo and checking in files "
    "without a checkout.",
    NULL, // very brief usage text, e.g. "file1 [...fileN]"
    NULL // optional callback which outputs app-specific help
  };
  fcli.cliFlags = FCliFlags;
  fcli.appHelp = &FCliHelp;
  fcli.clientFlags.checkoutDir = NULL; // same effect as global -C flag.
  fcli_pre_setup();
  /**
     Using fsl_malloc() before calling fcli_setup() IS VERBOTEN. fcli
     swaps out the allocator with a fail-fast one, meaning that if an
     allocation fails, the app crashes. This frees up the client app
     from much of the tedium of dealing with allocation errors (which,
     in practice, "never happen").
  */
  int rc = fcli_setup(argc, argv);
  if(rc) goto end;
  if((rc=fcli_has_unused_args(false))) goto end;
  else if(fsl_cx_db_repo(fcli_cx())){
    rc = fcli_err_set(FSL_RC_MISUSE,
                      "This app must be started WITHOUT a repo/checkout.");
    goto end;
  }

  rc = app_stuff();
  end:
  return fcli_end_of_main(rc);
}
