/* 

 cybercash.c by jsc@arsdigita.com; June 1998

 defines three Tcl procedures for the AOLserver API:
   cc_generate_order_id, returns a unique order ID (not useful if you
      are generating keys with an Oracle sequence or whatever)
   cc_send_to_server_21, access to the direct Cybercash API documented 
      in Appendix B of the CashRegister Service Development Guide (1.0)
   cc_do_direct_payment, access to the directpaycredit facility documented
      in Appendix A of the CashRegister Service Development Guide (1.0)

   note that cc_send_to_server_21 provides a superset of the capabilities
   of cc_do_direct_payment

  this software is copyright 1998 by ArsDigita, LLC and Jin S. Choi
  it is distributed free under the GNU General Public License

    (available at http://www.gnu.org/copyleft/gpl.html )

 */

#include "ns.h"
#include "CCMckDirect.h"
#include "CCMckDirectPayment.h"
#include "CCErrno.h"

#define CONFFILE "/home/cybercash/mck-cgi/conf/merchant_conf"

DllExport int Ns_ModuleVersion = 1;
static Tcl_CmdProc GenerateOrderIDCmd;
static Tcl_CmdProc SendToServer21Cmd;

static int
GenerateOrderIDCmd(ClientData dummy, Tcl_Interp *interp, int argc, char **argv)
{
  struct tm* timerec;
  pid_t	   mypid;
  time_t	   mytime;

  if (argc != 1) 
    {
      interp->result = "Usage: cc_generate_order_id";
      return TCL_ERROR;
    }

  mytime = time((time_t *) NULL);
  mypid = getpid();
  timerec = gmtime(&mytime);
	
  sprintf(interp->result,"%02d%02d%02d%02d%02d%05ld",
          timerec->tm_year, timerec->tm_mon + 1, timerec->tm_mday,
          timerec->tm_hour, timerec->tm_min,
          mypid);
  return TCL_OK;
}

/** 
 * Returns CC_SUCCESS if successful, CC error code if one of the 
 * CCAddPairNVlist()'s failed.
 */
static int
copy_ns_set_to_NVlist(Ns_Set *set, CCNVlistPtr nv)
{
  int i;
  int set_size = Ns_SetSize(set);

  for (i = 0; i < set_size; i++) 
    {
      char *key = Ns_SetKey(set, i);
      char *value = Ns_SetValue(set, i);
      int err;

      err = CCAddPairNVlist(nv, key, value);
      if (err != CC_SUCCESS)
        return err;
    }
  return CC_SUCCESS;
}

static void
copy_NVlist_to_ns_set(CCNVlistPtr nv, Ns_Set *set)
{
  int i;
  int len = CCSizeNVlist(nv);

  for (i = 0; i < len; i++) 
    {
      CCNVpairPtr pair = CCGetPairNVlist(nv, i);
      char *key = pair->name;
      char *value = pair->value;
      
      Ns_SetPut(set, key, value);
    }
}

/**
 * Takes two ns_set's, input and output.
 * Output set is cleared and filled with result values.
 */
static int
SendToServer21Cmd(ClientData dummy, Tcl_Interp *interp, int argc, char **argv)
{
  Ns_Set *input, *output;
  CCNVlistPtr args, result;
  char *command;

  if (argc != 4) 
    {
      interp->result = "Usage: cc_send_to_server_21 <command> <input ns_set> <output ns_set>";
      return TCL_ERROR;
    }
  command = argv[1];
  input = Ns_TclGetSet(interp, argv[2]);
  output = Ns_TclGetSet(interp, argv[3]);
  if (input == NULL || output == NULL)
    {
      interp->result = "input or output was not a valid ns_set";
      return TCL_ERROR;
    }
  args = CCNewNVlist();

  if (copy_ns_set_to_NVlist(input, args) != CC_SUCCESS) 
    {
      interp->result = "send_to_server couldn't convert input args to CCNVlist";
      return TCL_ERROR;
    }
  result = SendCC2_1Server(command, args);
  CCDeleteNVlist(args);

  copy_NVlist_to_ns_set(result, output);
  CCDeleteNVlist(result);
  return TCL_OK;
}

static int
DirectPaymentCmd(ClientData dummy, Tcl_Interp *interp, int argc, char **argv)
{
  Ns_Set *input, *pop, *tokenlist;
  CCNVlistPtr args, POP, TokenList;
  char *url;

  /* Check input values. */
  if (argc != 5) 
    {
      interp->result = "Usage: cc_do_direct_payment <url> <input ns_set> <POP ns_set> <token list ns_set>";
      return TCL_ERROR;
    }
  url = argv[1];
  input = Ns_TclGetSet(interp, argv[2]);
  pop = Ns_TclGetSet(interp, argv[3]);
  tokenlist = Ns_TclGetSet(interp, argv[4]);
  if (input == NULL || tokenlist == NULL || pop == NULL)
    {
      interp->result = "one of the arguments was not a valid ns_set";
      return TCL_ERROR;
    }

  /* Convert input args. */ 
  args = CCNewNVlist();
  if (copy_ns_set_to_NVlist(input, args) != CC_SUCCESS) 
    {
      interp->result = "couldn't convert input args to CCNVlist";
      return TCL_ERROR;
    }
  
  /* Call the CC function. */
  TokenList = NULL;
  doDirectPayment(url, args, &POP, &TokenList);
  CCDeleteNVlist(args);

  /* Convert output to ns_set's. */
  copy_NVlist_to_ns_set(POP, pop);
  copy_NVlist_to_ns_set(TokenList, tokenlist);
  CCDeleteNVlist(POP);
  CCDeleteNVlist(TokenList);
  return TCL_OK;
}




static int
CybercashInterpInit(Tcl_Interp *interp, void *context) 
{
  int error_code;
  
  error_code = CCMckDirectSetup(CONFFILE);
  if (error_code != 0) {
    Ns_Log(Error, "Couldn't initialize cybercash module with conf file %s: %s [%d]\n", 
           CONFFILE, CCGetErrorMessage(error_code), error_code);
    return NS_ERROR;
  }
  Tcl_CreateCommand(interp, "cc_generate_order_id", GenerateOrderIDCmd, NULL, NULL);
  Tcl_CreateCommand(interp, "cc_send_to_server_21", SendToServer21Cmd, NULL, NULL);
  Tcl_CreateCommand(interp, "cc_do_direct_payment", DirectPaymentCmd, NULL, NULL);
  return NS_OK;
}

DllExport int
Ns_ModuleInit(char *hServer, char *hModule)
{
  return (Ns_TclInitInterps(hServer, CybercashInterpInit, NULL));
}


