/* -*- 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 template application for libfossil fcli client apps, with
   commentary explaining how to do various common things with the
   API. Copy/paste this and modify it to suit.
*/
#include "fossil-scm/fossil-cli.h"
#include "fossil-scm/fossil-internal.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_ {
  bool flag1;
  bool flag2;
  char const * flag3;
  char const * fileArg1;
  int32_t flagInt;
} App = {
false,//flag1
true,//flag2
NULL,//flag3
NULL,//fileArg1
-1//flagInt
};

static int app_stuff(void){
  int rc = 0;
  // do... app... stuff...
  MARKER(("App.flag1=%d\n", App.flag1));
  MARKER(("App.flag2=%d\n", App.flag2));
  MARKER(("App.flag3=%s\n", App.flag3));
  MARKER(("App.flagInt=%"PRIi32"\n", App.flagInt));
  MARKER(("App.fileArg1=%s\n", App.fileArg1));
  return rc;
}

static int fcli_flag_callback_f_int(fcli_cliflag const *f){
  MARKER(("Flag callback: App.flagInt = %"PRIi32"\n", App.flagInt));
  return 0;
}

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_xxx macros are convenience forms for initializing
    // these members...
    FCLI_FLAG_BOOL("1","flag1",&App.flag1,"Flag 1."),
    FCLI_FLAG_BOOL_INVERT(NULL,"2",&App.flag2,"Flag 2."),
    FCLI_FLAG("3",NULL,"string",&App.flag3,"Flag 3"),
    FCLI_FLAG("f","file","filename",NULL,
              // NULL 4th argument  ^^^^ means this flag is only
              // used for --help text generation and handling
              // the flag is left to the app (see below).
              "Input file. May optionally be passed as the first "
              "non-flag argument."),
    FCLI_FLAG_I32_X("i","int",NULL,&App.flagInt,
                    fcli_flag_callback_f_int,
                    "Integer flag"),
    fcli_cliflag_empty_m // list MUST end with this (or equivalent)
  };
  const fcli_help_info FCliHelp = {
    "Replace this text with a brief description of the app.",
    NULL, // very brief usage text, e.g. "file1 [...fileN]"
    NULL // optional callback which outputs app-specific help
  };
  fcli.cliFlags = FCliFlags;
  fcli.appHelp = &FCliHelp;
  //fcli.checkoutDir = NULL; // same effect as global -C flag.
  //Invoke this app with -? -? to see the global options.

  /**
     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 you need to do any custom flags handling, do it after
     fcli_setup() here...
  */  
  if(!fcli_flag_or_arg("f","file", &App.fileArg1)){
    rc = fcli_err_set(FSL_RC_MISUSE,
                      "Missing required filename argument. Try --help.");
    goto end;
  }

  /**
     After all args processing, check for extra/unused flags
     with:
  */
  // if((rc=fcli_has_unused_flags(false))) goto end;
  // Or, more generally:
  if((rc=fcli_has_unused_args(false))) goto end;

  /** Check for a repository (if needed) with: */
  if(!fsl_needs_repo(fcli_cx())){
    /* Sets the context's error state and will produce an appropriate
       error message from fcli_end_of_main(). */
    goto end;
    /**
       Similarly, fsl_needs_ckout() checks for an opened checkout db
       (which also implies a repository: we never open a checkout
       without its corresponding repo).
    */
  }

  /** Perform your app-specific work... */
  rc = app_stuff();

  end:
  return fcli_end_of_main(rc)
    /* Will report any pending error state and return either
       EXIT_SUCCESS or EXIT_FAILURE. */;
  /* Sidebar: all of the memory allocated by this demo app is
     owned by the fcli internals and will be properly cleaned up
     during the at-exit phase. Running this app through valgrind
     should report no memory leaks. */
}
