#include <libpq-fe.h>
#include <postgres.h>

#define TPC_LOGPATH_MAX 255

/*
 * The state pipeline is fairly simple.
 *
 * BEGIN -> PREPARE -> (COMMIT | ROLLBACK) -> (COMPLETE | INCOMPLETE)
 * 
 * BEGIN:  We have declared we want to create a two-phase commit set
 *         But have not added transactions to it.
 *
 * PREPARE:  We are asking remote connections to prepare commits
 *
 * COMMIT: We have completed the prepare commands and are committing all.
 *
 * ROLLBACK:  We are rolling back all.
 *
 * COMPLETE:  We have successfully committed or rolled back ALL transactions
 *
 * INCOMPLETE:  We were unable to commit or roll back ALL transactions.
 *              EXTERNAL INTERVENTION IS REQUIRED FOR INCOMLETE TPC SETS
 */
typedef enum {
  BEGIN,
  PREPARE,
  COMMIT,
  ROLLBACK,
  COMPLETE,
  INCOMPLETE
} tpc_phase;


/*
 * tpc_txn may change without notice
 */

typedef struct tpc_txn {
   PGconn *cnx;                 /* connection to use */
   char txn_name[NAMEDATALEN];  /* transaction name  */
   struct tpc_txn *next;
} tpc_txn;

/*
 * We use an enriched single linked list to model the
 * transaction set here.
 *
 * For public usage, tpc_phase may be used to check
 * the results of rollback or commit.  COMPLETE means
 * that the transaction set was completed and cleaned up.
 *
 * INCOMPLETE means that the transaction set left dangling
 * transactions in places that must be externally cleaned up
 * and we don't want to wait around for them on the server.
 *
 * logpath gives you the path to the log file and the log
 * file descriptor will be closed after this point.
 */

typedef struct tpc_txnset {
   char logpath[TPC_LOGPATH_MAX];
   FILE *log;
   char txn_prefix[NAMEDATALEN]; /* overkill on size */
   uint counter;
   tpc_phase tpc_phase;
   tpc_txn *head;
   tpc_txn *latest;
} tpc_txnset;

extern tpc_txnset * tpc_begin(char *prefix);
extern char * tpc_prepare(tpc_txnset *txnset, PGconn *cnx);
extern tpc_phase tpc_commit(tpc_txnset *txnset);
extern tpc_phase tpc_rollback(tpc_txnset *txnset);
extern void tpc_process_file(char *fname);
