/* -*- 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

  Heavily indebted to the Fossil SCM project (https://fossil-scm.org).
  
  *****************************************************************************
   This file implements an "artifact diff" for in-repo content.
*/

#include "libfossil.h"
#include <stdlib.h> /* atoi() */

struct ADiffAppT {
  fsl_diff_opt diffOpt;
  fsl_diff_builder * diffBuilder;
};
typedef struct ADiffAppT ADiffAppT;
ADiffAppT ADiffApp = {
fsl_diff_opt_empty_m,
NULL
};

static int f_adiff(fsl_id_t v1, fsl_id_t v2){
  int rc = 0;
  fsl_cx * const f = fcli_cx();
  fsl_buffer lhs = fsl_buffer_empty;
  fsl_buffer rhs = fsl_buffer_empty;
  rc = fsl_content_get(f, v1, &lhs);
  if(0==rc) rc = fsl_content_get(f, v2, &rhs);
  if(0==rc) rc = fsl_diff_v2(&lhs, &rhs, ADiffApp.diffBuilder);
  fsl_buffer_clear(&lhs);
  fsl_buffer_clear(&rhs);
  return rc;
}

int main(int argc, char const * const * argv ){
  int rc = 0;
  const char * vFrom = NULL;
  const char * vTo = NULL;
  fsl_cx * f;
  fsl_id_t idFrom = 0, idTo = 0;
  bool flagBW = false;
  bool flagColor = false;
  bool flagInvert = false;
  bool flagLineNo = false;
  bool flagSbs = false;
  bool flagIgnoreSpaces = false;
  int flagSbsWidth = -1;
  int flagContextLines = -1;
  fcli_cliflag FCliFlags[] = {
    FCLI_FLAG("v1","from","from-version",&vFrom,
              "Name of version 1. Default is the first non-flag argument"),
    FCLI_FLAG("v2","to","to-version",&vTo,
              "Name of version 2. Default is the second non-flag argument"),
    FCLI_FLAG_BOOL("w","ignore-all-space",&flagIgnoreSpaces,
                   "Ignore all whitespace differences."),
    FCLI_FLAG_BOOL("y", "sbs", &flagSbs,
                   "Use side-by-side diff."),
    FCLI_FLAG_I32("W","sbs-width","max column width",&flagSbsWidth,
                  "Max side-by-side diff view width. Implies -y."),
    FCLI_FLAG_I32("c","context-lines","line-count",&flagContextLines,
                  "Number of lines of context."),
    FCLI_FLAG_BOOL("l","line-numbers",&flagLineNo,
                   "Add line numbers (unified diff only)."),
    FCLI_FLAG_BOOL("i","invert",&flagInvert,
                   "Invert the direction of the diff."),
    FCLI_FLAG_BOOL("bw","no-color",&flagBW,
                   "Disables ANSI color sequences."),
    FCLI_FLAG_BOOL(NULL,"color", &flagColor,
                   "Try to force ANSI color even if stdout is not "
                   "a terminal or --no-color is used. Does not work "
                   "with all diff formats."),
    fcli_cliflag_empty_m
  };
  fcli_help_info FCliHelp = {
  "Generates diff of individual blobs (not checkin versions!).",
  "fromArtifactUuid toArtifactUuid",
  NULL
  };
  fcli.cliFlags = FCliFlags;
  fcli.appHelp = &FCliHelp;
  rc = fcli_setup(argc, argv);
  if(rc) goto end;

  /* Set up/validate args... */
  f = fcli_cx();
  if(!fsl_cx_db_repo(f)){
    rc = fcli_err_set(FSL_RC_NOT_A_REPO,
                      "Requires a repository db. See --help.");
    goto end;
  }
  if(flagSbsWidth>0){
    ADiffApp.diffOpt.columnWidth = (unsigned short)flagSbsWidth;
    flagSbs = true;
  }
  rc = fsl_diff_builder_factory(flagSbs
                                ? FSL_DIFF_BUILDER_SPLIT_TEXT
                                : FSL_DIFF_BUILDER_UNIFIED_TEXT,
                                &ADiffApp.diffBuilder);
  if(rc) goto end;
  ADiffApp.diffBuilder->opt = &ADiffApp.diffOpt;
  ADiffApp.diffOpt.out = fsl_output_f_FILE;
  ADiffApp.diffOpt.outState = stdout;
  if(flagIgnoreSpaces){
    ADiffApp.diffOpt.diffFlags |= FSL_DIFF2_IGNORE_ALLWS;
  }
  if(flagInvert){
    ADiffApp.diffOpt.diffFlags |= FSL_DIFF2_INVERT;
  }
  if(flagLineNo){
    ADiffApp.diffOpt.diffFlags |= FSL_DIFF2_LINE_NUMBERS;
  }
  if(flagColor || (!flagBW && fsl_isatty(1))){
    fcli_diff_colors(&ADiffApp.diffOpt, FCLI_DIFF_COLORS_DEFAULT);
  }
  if(flagContextLines>=0){
    ADiffApp.diffOpt.contextLines = (unsigned short) flagContextLines;
  }
  if(fcli_has_unused_flags(0)) goto end;
  if(!vFrom) vFrom = fcli_next_arg(1);
  if(!vTo) vTo = fcli_next_arg(1);
  if(!vFrom || !vTo){
    rc = fcli_err_set(FSL_RC_MISUSE, "Both of -v1 UUID and -v2 UUID are required.");
    goto end;
  }

  rc = fsl_sym_to_rid(f, vFrom, FSL_SATYPE_ANY, &idFrom);
  if(!rc){
    rc = fsl_sym_to_rid(f, vTo, FSL_SATYPE_ANY, &idTo);
  }
  if(rc) goto end;
  ADiffApp.diffBuilder->opt->hashLHS = vFrom;
  ADiffApp.diffBuilder->opt->hashRHS = vTo; 

  rc = f_adiff( idFrom, idTo );

  end:
  if(ADiffApp.diffBuilder){
    ADiffApp.diffBuilder->finalize(ADiffApp.diffBuilder);
  }
  return fcli_end_of_main(rc);
}
