Index: /trunk/archive/p2tools/src/p2admin.c
===================================================================
--- /trunk/archive/p2tools/src/p2admin.c	(revision 5869)
+++ /trunk/archive/p2tools/src/p2admin.c	(revision 5869)
@@ -0,0 +1,16 @@
+# include "p2search.h"
+
+int main (int argc, char **argv) {
+
+    p2adminConfig (&config, argc, argv);
+
+    if (config->mode == P2_MODE_CREATE) {
+	p2deleteTables (config);
+    }
+
+    if (config->mode == P2_MODE_DELETE) {
+	p2createTables (config);
+    }
+
+    exit (0);
+}
Index: /trunk/archive/p2tools/src/p2adminConfig.c
===================================================================
--- /trunk/archive/p2tools/src/p2adminConfig.c	(revision 5869)
+++ /trunk/archive/p2tools/src/p2adminConfig.c	(revision 5869)
@@ -0,0 +1,64 @@
+# include "p2search.h"
+
+bool p2adminConfig (psConfig *config, int argc, char **argv) {
+
+    // Parse the configurations (re-org a la ppImage)
+    config->site = NULL;            // Site configuration
+    config->camera = NULL;          // Camera configuration
+    config->recipe = NULL;          // Recipe configuration
+    if (! pmConfigRead(&config->site, &config->camera, &config->recipe, &argc, argv, RECIPE)) {
+        psErrorStackPrint(stderr, "Can't find site configuration!\n");
+        exit(EXIT_FAILURE);
+    }
+
+    // Parse other command-line arguments
+    config->arguments = psMetadataAlloc(); // The arguments, with default values
+
+    config->mode = P2_MODE_NONE;
+    if ((N = psArgumentGet (*argc, argv, "-create"))) {
+	psArgumentRemove (N, argc, argv);
+	if (config->mode) psAbort ("p2search", "only one mode selection is allowed");
+	config->mode = P2_MODE_CREATE;
+    }
+    if ((N = psArgumentGet (*argc, argv, "-delete"))) {
+	psArgumentRemove (N, argc, argv);
+	if (config->mode) psAbort ("p2search", "only one mode selection is allowed");
+	config->mode = P2_MODE_DELETE;
+    }
+
+    if (config->mode == P2_MODE_NONE) {
+	fprintf (stderr, "admin mode not specified\n");
+        psArgumentHelp(config->arguments);
+        psFree(config->arguments);
+        exit(EXIT_FAILURE);
+    }
+
+    // paul's argument parsing convention requires: -key value 
+    psMetadataAddStr(config->arguments, PS_LIST_TAIL, "-create", 0, "create the P2 tables", "");
+    psMetadataAddStr(config->arguments, PS_LIST_TAIL, "-delete", 0, "delete the P2 tables", "");
+
+    if ((N = psArgumentGet (*argc, argv, "-help"))) {
+        psArgumentHelp(config->arguments);
+        psFree(config->arguments);
+        exit(EXIT_FAILURE);
+    }
+
+    if (! psArgumentParse(config->arguments, &argc, argv) || argc != 1) {
+        printf("\nPan-STARRS Phase 2 Admin Tool\n\n");
+        printf("Usage: %s [mode]\n", argv[0]);
+        printf(" [mode] : -create | -delete\n\n");
+        psArgumentHelp(config->arguments);
+        psFree(config->arguments);
+        exit(EXIT_FAILURE);
+    }
+
+    // define Database handle, if used
+    config->database = pmConfigDB(config->site);
+    return true;
+} 
+
+/*
+ * USAGE:
+ * p2admin -create : create the P2 tables
+ * p2admin -delete : delete the P2 tables (asks for confirmation)
+ */
Index: /trunk/archive/p2tools/src/p2adminTables.c
===================================================================
--- /trunk/archive/p2tools/src/p2adminTables.c	(revision 5869)
+++ /trunk/archive/p2tools/src/p2adminTables.c	(revision 5869)
@@ -0,0 +1,38 @@
+# include "p2search.h"
+
+bool p2createTables (p2config *config) {
+
+    p2PendingImageCreateTable (config->database);
+    p2PendingExposureCreateTable (config->database);
+
+    return true;
+}
+
+bool p2deleteTables (p2config *config) {
+
+    char line[128], answer[128];
+
+    fprintf (stdout, "*** delete the P2 tables? ***\n");
+    fprintf (stdout, "*** to delete the tables, answer YES, and give password ***\n");
+    fprintf (stdout, "*** WARNING: this action is permanent ***\n\n");
+
+    fprintf (stdout, "delete the P2 tables [n]:  \n");
+    fgets (line, 128, stdin);
+    sscanf (line, "%s", answer);
+    if (strcmp (answer, "YES")) goto escape;
+
+    fprintf (stdout, "enter password:  \n");
+    fgets (line, 128, stdin);
+    sscanf (line, "%s", answer);
+    if (strcmp (answer, "*ipp*")) goto escape;
+
+    p2PendingImageDropTable (config->database);
+    p2PendingExposureDropTable (config->database);
+
+    return true;
+
+
+escape:
+    fprintf (stdout, "tables NOT deleted\n");
+    return false;
+}
Index: /trunk/archive/p2tools/src/p2insertDoneFrames.c
===================================================================
--- /trunk/archive/p2tools/src/p2insertDoneFrames.c	(revision 5869)
+++ /trunk/archive/p2tools/src/p2insertDoneFrames.c	(revision 5869)
@@ -0,0 +1,19 @@
+# include "p2search.h"
+
+// select pending frames (exposure+images) which are done/not done
+bool p2insertDoneFrames (p2SearchConfig *config, psArray *doneFrames) {
+
+    for (int i = 0; i < doneFrames->n; i++) {
+	p2DoneFrame *doneFrame = doneFrames->data[i];
+	p2DoneExposure *doneExposure = doneFrame->exposure;
+	
+	psArray *doneImages = doneFrame->images;
+	
+	p2DoneExposureInsertOneRow (config->database, doneExposure);
+	p2DoneImageInsertRows (config->database, doneImages);
+    }
+    return true;
+} 
+
+// XXX : must remove the done frames from the pending table, or we'll get duplicates
+// XXX : add P3pending insert function? selected on recipe type? 
Index: /trunk/archive/p2tools/src/p2insertPendingFrames.c
===================================================================
--- /trunk/archive/p2tools/src/p2insertPendingFrames.c	(revision 5869)
+++ /trunk/archive/p2tools/src/p2insertPendingFrames.c	(revision 5869)
@@ -0,0 +1,62 @@
+# include "p2search.h"
+
+// select pending frames (exposure+images) which are done/not done
+// NOTE this function converts the rawFrames to pendingFrames AND inserts them
+//      this is useful since the table must be locked the whole time, to get the versions
+bool p2insertPendingFrames (p2SearchConfig *config, psArray *rawFrames) {
+
+    psMetadata *where = psMetadataAlloc ();
+
+    for (int i = 0; i < rawFrames->n; i++) {
+	ppRawFrame *rawFrame = rawFrames->data[i];
+
+	// find the next available version numbers
+	psMetadataAddStr (where, PS_LIST_TAIL, "EXP_ID", PS_META_REPLACE, "==", rawFrame->exposure->expID);
+	psArray *exposures = p2PendingExposureSelectRows (config->database, where, MAX_ROWS);
+	int version = -1;
+	for (int j = 0; j < exposures->n; j++) {
+	    p2PendingExposure *exposure = exposures->data[j];
+	    version = PS_MAX (version, exposure->P2version);
+	}
+	version ++;
+
+	p2PendingExposure *pendingExposure = p2PendingExposureAlloc ();
+	strcpy (pendingExposure->expID, rawFrame->exposure->expID);
+	pendingExposure->class = rawFrame->exposure->class;
+	pendingExposure->Nclass = rawFrame->exposure->Nclass;
+	pendingExposure->Ndone = 0;
+	pendingExposure->P1version = 0xff;
+	pendingExposure->P2version = version;
+	pendingExposure->state = P2_STATE_PENDING;
+
+	psArray *pendingImages = psArrayAlloc (rawFrame->images->n);
+	pendingImages->n = 0;
+	for (int j = 0; j < rawFrame->images->n; j++) {
+	    ppRawImage *rawImage = rawFrame->images->data[j];
+	    p2PendingImage *pendingImage = p2PendingImageAlloc ();
+
+	    strcpy (pendingImage->expID, rawImage->expID);
+	    pendingImage->P2version = version;
+	    pendingImage->class = rawImage->class;
+	    strcpy (pendingImage->classID, rawImage->classID);
+
+	    // XXX cleanup the url somehow
+	    strcpy (pendingImage->urlroot = rawImage->url);
+	    strcpy (pendingImage->input, "raw.fits");
+	    strcpy (pendingImage->output, "flt.fits");
+	    strcpy (pendingImage->log, "log");
+	    strcpy (pendingImage->smf, "smf");
+	    pendingImage->state = P2_STATE_PENDING;
+
+	    psArrayAdd (pendingImages, 100, pendingImage);
+	}
+	
+	p2PendingExposureInsertOneRow (config->database, pendingExposure);
+	p2PendingImageInsertRows (config->database, pendingImages);
+    }
+    return true;
+} 
+
+// XXX the filename layout is defined by this code
+// XXX have the SQL command update the version number?
+// XXX EAM : need to lock the table : inner or outer loop?
Index: /trunk/archive/p2tools/src/p2pendingToDone.c
===================================================================
--- /trunk/archive/p2tools/src/p2pendingToDone.c	(revision 5869)
+++ /trunk/archive/p2tools/src/p2pendingToDone.c	(revision 5869)
@@ -0,0 +1,51 @@
+# include "p2search.h"
+
+// select pending frames (exposure+images) which are done/not done
+psArray *p2pendingToDone (p2SearchConfig *config, psArray *pendingFrames) {
+
+    psArray *doneFrames = psArrayAlloc (frames->n);
+    doneFrames->n = 0;
+
+    for (int i = 0; i < pendingFrames->n; i++) {
+	ppPendingFrame *pendingFrame = pendingFrames->data[i];
+	if (pendingFrame->exposure->state != P2_STATE_DONE) continue;
+
+	p2DoneExposure *doneExposure = p2DoneExposureAlloc ();
+	strcpy (doneExposure->expID, pendingFrame->exposure->expID);
+	doneExposure->class = pendingFrame->exposure->class;
+	doneExposure->Nclass = pendingFrame->exposure->Nclass;
+	doneExposure->Ndone = pendingFrame->exposure->Nclass;
+	doneExposure->P1version = pendingFrame->exposure->P1version;
+	doneExposure->P2version = pendingFrame->exposure->P2version;
+	doneExposure->state = P2_STATE_DONE;
+
+	psArray *doneImages = psArrayAlloc (pendingFrame->images->n);
+	doneImages->n = 0;
+	for (int j = 0; j < pendingFrame->images->n; j++) {
+	    ppPendingImage *pendingImage = pendingFrame->images->data[j];
+	    if (pendingImage->state != P2_STATE_DONE) {
+		psAbort ("p2search", "programming error!");
+	    }
+
+	    p2DoneImage *doneImage = p2DoneImageAlloc ();
+
+	    strcpy (doneImage->expID, pendingImage->expID);
+	    doneImage->P2version = pendingImage->P2version;
+	    doneImage->class = pendingImage->class;
+	    strcpy (doneImage->classID, pendingImage->classID);
+	    strcpy (doneImage->urlroot, pendingImage->urlroot);
+	    strcpy (doneImage->input,   pendingImage->input);
+	    strcpy (doneImage->output,  pendingImage->output);
+	    strcpy (doneImage->log,     pendingImage->log);
+	    strcpy (doneImage->smf,     pendingImage->smf);
+	    doneImage->state = P2_STATE_DONE;
+	    psArrayAdd (doneImages, 100, doneImage);
+	}
+	
+	p2DoneFrame *doneFrame = p2DoneFrameAlloc (doneExposure, doneImages);
+	psArrayAdd (doneFrames, 100, doneFrame);
+    }
+    return doneFrames;
+} 
+
+// XXX the filename layout is defined by this code
Index: /trunk/archive/p2tools/src/p2rawToPending.c
===================================================================
--- /trunk/archive/p2tools/src/p2rawToPending.c	(revision 5869)
+++ /trunk/archive/p2tools/src/p2rawToPending.c	(revision 5869)
@@ -0,0 +1,48 @@
+# include "p2search.h"
+
+// select pending frames (exposure+images) which are done/not done
+psArray *p2rawToPending (p2SearchConfig *config, psArray *rawFrames) {
+
+    psArray *pendingFrames = psArrayAlloc (frames->n);
+    pendingFrames->n = 0;
+
+    for (int i = 0; i < rawFrames->n; i++) {
+	ppRawFrame *rawFrame = rawFrames->data[i];
+
+	p2PendingExposure *pendingExposure = p2PendingExposureAlloc ();
+	strcpy (pendingExposure->expID, rawFrame->exposure->expID);
+	pendingExposure->class = rawFrame->exposure->class;
+	pendingExposure->Nclass = rawFrame->exposure->Nclass;
+	pendingExposure->Ndone = 0;
+	pendingExposure->P1version = 0xff;
+	pendingExposure->P2version = 0xff;
+	pendingExposure->state = P2_STATE_PENDING;
+
+	psArray *pendingImages = psArrayAlloc (rawFrame->images->n);
+	pendingImages->n = 0;
+	for (int j = 0; j < rawFrame->images->n; j++) {
+	    ppRawImage *rawImage = rawFrame->images->data[j];
+	    p2PendingImage *pendingImage = p2PendingImageAlloc ();
+
+	    strcpy (pendingImage->expID, rawImage->expID);
+	    pendingImage->P2version = 0xff;
+	    pendingImage->class = rawImage->;
+	    strcpy (pendingImage->classID, rawImage->classID);
+
+	    pendingImage->urlroot = rawImage->;
+	    strcpy (pendingImage->input, "raw.fits");
+	    strcpy (pendingImage->output, "flt.fits");
+	    strcpy (pendingImage->log, "log");
+	    strcpy (pendingImage->smf, "smf");
+	    pendingImage->state = P2_STATE_PENDING;
+
+	    psArrayAdd (pendingImages, 100, pendingImage);
+	}
+	
+	p2PendingFrame *pendingFrame = p2PendingFrameAlloc (pendingExposure, pendingImages);
+	psArrayAdd (pendingFrames, 100, pendingFrame);
+    }
+    return pendingFrames;
+} 
+
+// XXX the filename layout is defined by this code
Index: /trunk/archive/p2tools/src/p2search.c
===================================================================
--- /trunk/archive/p2tools/src/p2search.c	(revision 5868)
+++ /trunk/archive/p2tools/src/p2search.c	(revision 5869)
@@ -1,78 +1,36 @@
 # include "p2search.h"
-
-typedef enum {
-    P2_MODE_NONE,		      	// grab from raw, output for ppImage
-    P2_MODE_QUICK,		      	// grab from raw, output for ppImage
-    P2_MODE_DEFINE,			// grab from raw, create pending
-    P2_MODE_PENDING,			// grab from pending, output for ppImage
-    P2_MODE_UPDATE,			// set the current state
-} p2Mode;
-
-typedef struct {
-    p2Mode mode;
-    psTime start;
-    psTime stop;
-    psSphere r1;
-    psSphere r2;
-    char *camera;
-    char *filter;
-} p2Config;
-
-// this structure should be defined using the mddb api tools
-typedef struct {
-    char expID[32];			// free-form exposure ID string
-    char class;				// class of file: fpa (0), chip (1), cell (2), readout (3)?
-    int Nclass;				// number of files of this class
-    char camera[32];			// free-form camera ID string
-    char filter[32];			// free-form filter ID string
-    psTime time_start;			// exposure start time
-    psTime time_stop;			// exposure stop time
-    psTime exptime;			// exposure duration (seconds)
-    char exptype;			// type of exposure: object (0), bias (1), dark (2), flat (3), etc
-    float sky;				// measure sky brightness
-    float seeing;			// measured image quality 
-    float dettemp;			// temperature of detector
-} p2RawExposure;
-
-// this structure should be defined using the mddb api tools
-typedef struct {
-    char expID[32];			// free-form exposure ID string
-    char class;				// class of file: fpa (0), chip (1), cell (2), readout (3)?
-    char classID[32];			// identifier for class (chip00, cell00, etc)
-    char url[128];			// locator for file (neb / file)
-    char state;				// current load state
-} p2RawImage;
-
-typedef struct {
-    p2RawExposure *exposure;
-    psArray *images;
-} p2RawSet;
 
 int main (int argc, char **argv) {
 
-    p2SearchConfig (&config, argc, argv);
+    psArray *rawFrames;
+    psArray *doneFrames;
+    psArray *pendingFrames;
 
-    if ((config->mode == P2_MODE_QUICK) || (config->mode == P2_MODE_DEFINE)) {
-	rawSet = p2SearchRawImages (config);
+    p2searchConfig (&config, argc, argv);
+
+    if (config->mode == P2_MODE_QUICK) {
+	rawFrames = p2searchRawFrames (config);
+	pendingFrames = p2rawToPending (config, rawFrames);
+	p2writePendingFrames (config, pendingFrames);
+    }	
+
+    if (config->mode == P2_MODE_DEFINE) {
+	rawFrames = p2searchRawFrames (config);
+	p2insertPendingFrames (config, rawFrames);
     }
 
-    if (config->mode == P2_MODE_DEFINE) {
-	p2InsertRawSet (config, rawSet);
-    }
-
-    if ((config->mode == P2_MODE_PENDING) || (config->mode == P2_MODE_UPDATE)) {
-	pendingSet = p2SearchPendingImages (config);
-    }
-
-    if (config->mode == P2_MODE_QUICK) {
-	pendingSet = p2RawToPending (config, rawSet);
-    }
-
-    if ((config->mode == P2_MODE_QUICK) || (config->mode == P2_MODE_PENDING)) {
-	p2WritePending (config, pendingSet);
+    if (config->mode == P2_MODE_PENDING) {
+	pendingFrames = p2searchPendingFrames (config, FALSE);
+	p2writePendingImages (config, pendingFrames);
     }
 
     if (config->mode == P2_MODE_UPDATE) {
-	p2UpdatePending (config, pendingSet);
+	p2updatePendingFrames (config, pendingFrames);
+    }
+
+    if (config->mode == P2_MODE_DONE) {
+	pendingFrames = p2searchPendingFrames (config, TRUE);
+	doneFrames = p2pendingToDone (config);
+	p2insertDoneFrames (config, doneFrames);
     }
 
Index: /trunk/archive/p2tools/src/p2search.h
===================================================================
--- /trunk/archive/p2tools/src/p2search.h	(revision 5869)
+++ /trunk/archive/p2tools/src/p2search.h	(revision 5869)
@@ -0,0 +1,125 @@
+# include <stdio.h>
+# include <strings.h>  // for strcasecmp
+# include <unistd.h>   // for unlink
+# include <pslib.h>
+# include <pmObjects.h>
+# include <pmPSF.h>
+# include <pmPSFtry.h>
+# include <pmModelGroup.h>
+
+// load these values from the db in the init stage
+# define P2_TYPE_OBJECT 1
+# define P2_STATE_READY 2
+
+typedef enum {
+    P2_MODE_NONE,		      	// grab from raw, output for ppImage
+    P2_MODE_QUICK,		      	// grab from raw, output for ppImage
+    P2_MODE_DEFINE,			// grab from raw, create pending
+    P2_MODE_PENDING,			// grab from pending, output for ppImage
+    P2_MODE_UPDATE,			// set the current state
+    P2_MODE_DONE,			// set the current state
+    P2_MODE_CREATE,			// set the current state
+    P2_MODE_DELETE,			// set the current state
+} p2mode;
+
+typedef struct {
+    p2mode mode;
+    psTime start;
+    psTime stop;
+    psSphere r1;
+    psSphere r2;
+    char *camera;
+    char *filter;
+    psDB *database;
+} p2config;
+
+// this structure should be defined using the mddb api tools
+typedef struct {
+    char expID[32];			// free-form exposure ID string
+    char class;				// class of file: fpa (0), chip (1), cell (2), readout (3)?
+    int Nclass;				// number of files of this class
+    char camera[32];			// free-form camera ID string
+    char filter[32];			// free-form filter ID string
+    psTime time_start;			// exposure start time
+    psTime time_stop;			// exposure stop time
+    psTime exptime;			// exposure duration (seconds)
+    char exptype;			// type of exposure: object (0), bias (1), dark (2), flat (3), etc
+    float sky;				// measure sky brightness
+    float seeing;			// measured image quality 
+    float dettemp;			// temperature of detector
+} ppRawExposure;
+
+// this structure should be defined using the mddb api tools
+typedef struct {
+    char expID[32];			// free-form exposure ID string
+    char class;				// class of file: fpa (0), chip (1), cell (2), readout (3)?
+    char classID[32];			// identifier for class (chip00, cell00, etc)
+    char url[128];			// locator for file (neb / file)
+    char state;				// current load state
+} ppRawImage;
+
+// this structure should be defined using the mddb api tools
+typedef struct {
+    char expID[32];			// free-form exposure ID string
+    char class;				// class of file: fpa (0), chip (1), cell (2), readout (3)?
+    int Nclass;				// number of files of this class
+    int Ndone;				// number of files of this class
+    char P1version;
+    char P2version;
+    char state;
+} p2PendingExposure;
+
+// this structure should be defined using the mddb api tools
+typedef struct {
+    char expID[32];			// free-form exposure ID string
+    char P2version;
+    char class;				// class of file: fpa (0), chip (1), cell (2), readout (3)?
+    char classID[32];			// identifier for class (chip00, cell00, etc)
+    char urlroot[128];			// locator for file (neb / file)
+    char input[16];			// extension for input image
+    char output[16];			// extension for output image
+    char log[16];			// extension for log file
+    char smf[16];			// extension for object table
+    char state;				// current P2 state
+} p2PendingImage;
+
+// this structure should be defined using the mddb api tools
+typedef struct {
+    char expID[32];			// free-form exposure ID string
+    char class;				// class of file: fpa (0), chip (1), cell (2), readout (3)?
+    int Nclass;				// number of files of this class
+    int Ndone;				// number of files of this class
+    char P1version;
+    char P2version;
+    char state;
+} p2DoneExposure;
+
+// this structure should be defined using the mddb api tools
+typedef struct {
+    char expID[32];			// free-form exposure ID string
+    char P2version;
+    char class;				// class of file: fpa (0), chip (1), cell (2), readout (3)?
+    char classID[32];			// identifier for class (chip00, cell00, etc)
+    char urlroot[128];			// locator for file (neb / file)
+    char input[16];			// extension for input image
+    char output[16];			// extension for output image
+    char log[16];			// extension for log file
+    char smf[16];			// extension for object table
+    char state;				// current P2 state
+} p2DoneImage;
+
+typedef struct {
+    ppRawExposure *exposure;
+    psArray *images;
+} ppRawFrame;
+
+typedef struct {
+    ppPendingExposure *exposure;
+    psArray *images;
+} p2PendingFrame;
+
+typedef struct {
+    ppDoneExposure *exposure;
+    psArray *images;
+} p2DoneFrame;
+
Index: /trunk/archive/p2tools/src/p2searchConfig.c
===================================================================
--- /trunk/archive/p2tools/src/p2searchConfig.c	(revision 5868)
+++ /trunk/archive/p2tools/src/p2searchConfig.c	(revision 5869)
@@ -1,5 +1,5 @@
 # include "p2search.h"
 
-bool p2SearchConfig (psConfig *config, int argc, char **argv) {
+bool p2searchConfig (psConfig *config, int argc, char **argv) {
 
     // Parse the configurations (re-org a la ppImage)
@@ -36,4 +36,9 @@
 	config->mode = P2_MODE_UPDATE;
     }
+    if ((N = psArgumentGet (*argc, argv, "-done"))) {
+	psArgumentRemove (N, argc, argv);
+	if (config->mode) psAbort ("p2search", "only one mode selection is allowed");
+	config->mode = P2_MODE_UPDATE;
+    }
 
     // paul's argument parsing convention requires: -key value 
Index: /trunk/archive/p2tools/src/p2searchPendingFrames.c
===================================================================
--- /trunk/archive/p2tools/src/p2searchPendingFrames.c	(revision 5869)
+++ /trunk/archive/p2tools/src/p2searchPendingFrames.c	(revision 5869)
@@ -0,0 +1,52 @@
+# include "p2search.h"
+
+// select pending frames (exposure+images) which are done/not done
+psArray *p2searchPendingFrames (p2SearchConfig *config, bool isDone) {
+
+    // build 'where' structure
+    psMetadata *where = psMetadataAlloc ();
+
+    if (isDone) {
+	psMetadataAddStr (where, PS_LIST_TAIL, "STATE", 0, "==", P2_STATE_DONE);
+    } else {
+	psMetadataAddStr (where, PS_LIST_TAIL, "STATE", 0, "==", P2_STATE_PENDING);
+    }
+
+    // in order to include these restrictions, we need to define these table columns
+    if (config->camera != NULL) {
+	psMetadataAddStr (where, PS_LIST_TAIL, "CAMERA", 0, "==", config->camera);
+    }
+    if (config->filter != NULL) {
+	psMetadataAddStr (where, PS_LIST_TAIL, "FILTER", 0, "==", config->filter);
+    }
+    if (!psTimeIsZero(config->start) && !psTimeIsZero(config->stop)) {
+	psMetadataAddTime (where, PS_LIST_TAIL, "TIME_START", 0, "<", config->time_stop);
+	psMetadataAddTime (where, PS_LIST_TAIL, "TIME_STOP", 0, ">", config->time_start);
+    }
+
+    psArray *exposures = p2PendingExposureSelectRows (config->database, where, MAX_ROWS);
+    psFree (where);
+
+    // output array of rawSet
+    psArray *frames = psArrayAlloc (exposures->n);
+
+    // 'where' to select each exposure
+    psMetadata *where = psMetadataAlloc ();
+    for (int i = 0; i < exposures->n; i++) {
+	p2PendingExposure *exposure = exposures->data[i];
+	
+	psMetadataAddStr (where, PS_LIST_TAIL, "EXP_ID", PS_META_REPLACE, "==", exposure->expID);
+	psMetadataAddStr (where, PS_LIST_TAIL, "P2_VERSION", PS_META_REPLACE, "==", exposure->P2version);
+
+	psArray *images = ppPendingImageSelectRows (config->database, where, MAX_ROWS);
+
+	ppPendingFrame *frame = ppPendingFrameAlloc (exposure, images);
+
+	psArrayAdd (frames, 100, frame);
+    }
+    return frames;
+} 
+
+// XXX EAM : this may be more efficient if we just select all p2PendingImages which
+// have the appropriate state.  that would limit the ability to filter the selection.
+// test to see how well/poorly this performs
Index: /trunk/archive/p2tools/src/p2searchRawFrames.c
===================================================================
--- /trunk/archive/p2tools/src/p2searchRawFrames.c	(revision 5869)
+++ /trunk/archive/p2tools/src/p2searchRawFrames.c	(revision 5869)
@@ -0,0 +1,42 @@
+# include "p2search.h"
+
+// select raw frames (exposure+images) which match the given config options
+psArray p2searchRawImages (p2SearchConfig *config) {
+
+    // build 'where' structure
+    psMetadata *where = psMetadataAlloc ();
+
+    psMetadataAddU8  (where, PS_LIST_TAIL, "TYPE",  0, "==", P2_TYPE_OBJECT);
+    psMetadataAddStr (where, PS_LIST_TAIL, "STATE", 0, "==", P2_START_READY);
+
+    if (config->camera != NULL) {
+	psMetadataAddStr (where, PS_LIST_TAIL, "CAMERA", 0, "==", config->camera);
+    }
+    if (config->filter != NULL) {
+	psMetadataAddStr (where, PS_LIST_TAIL, "FILTER", 0, "==", config->filter);
+    }
+    if (!psTimeIsZero(config->start) && !psTimeIsZero(config->stop)) {
+	psMetadataAddTime (where, PS_LIST_TAIL, "TIME_START", 0, "<", config->time_stop);
+	psMetadataAddTime (where, PS_LIST_TAIL, "TIME_STOP", 0, ">", config->time_start);
+    }
+
+    psArray *exposures = ppRawExposureSelectRows (config->database, where, MAX_ROWS);
+    psFree (where);
+
+    // output array of ppRawFrame
+    psArray *frames = psArrayAlloc (exposures->n);
+
+    // 'where' to select each exposure
+    psMetadata *where = psMetadataAlloc ();
+    for (int i = 0; i < exposures->n; i++) {
+	ppRawExposure *exposure = exposures->data[i];
+	
+	psMetadataAddStr (where, PS_LIST_TAIL, "EXP_ID", PS_META_REPLACE, "==", exposure->expID);
+
+	psArray *images = ppRawImageSelectRows (config->database, where, MAX_ROWS);
+
+	ppRawFrame *frame = ppRawFrameAlloc (exposure, images);
+	psArrayAdd (frames, 100, frame);
+    }
+    return frames;
+} 
Index: unk/archive/p2tools/src/p2searchRawImages.c
===================================================================
--- /trunk/archive/p2tools/src/p2searchRawImages.c	(revision 5868)
+++ 	(revision )
@@ -1,49 +1,0 @@
-# include "p2search.h"
-
-// load these values from the db in the init stage
-# define P2_TYPE_OBJECT 1
-# define P2_STATE_READY 2
-
-bool p2SearchRawImages (p2SearchConfig *config) {
-
-    // build 'where' structure
-
-    psMetadata *where = psMetadataAlloc ();
-
-    psMetadataAddU8  (where, PS_LIST_TAIL, "TYPE",  0, "==", P2_TYPE_OBJECT);
-    psMetadataAddStr (where, PS_LIST_TAIL, "STATE", 0, "==", P2_START_READY);
-
-    if (config->camera != NULL) {
-	psMetadataAddStr (where, PS_LIST_TAIL, "CAMERA", 0, "==", config->camera);
-    }
-
-    if (config->filter != NULL) {
-	psMetadataAddStr (where, PS_LIST_TAIL, "FILTER", 0, "==", config->filter);
-    }
-
-    if (!psTimeIsZero(config->start) && !psTimeIsZero(config->stop)) {
-	psMetadataAddTime (where, PS_LIST_TAIL, "TIME_START", 0, "<", config->time_stop);
-	psMetadataAddTime (where, PS_LIST_TAIL, "TIME_STOP", 0, ">", config->time_start);
-    }
-
-    psArray *exposures = p2RawExposureSelectRows (config->database, where, MAX_ROWS);
-
-    psFree (where);
-
-    psMetadata *where = psMetadataAlloc ();
-
-    for (int i = 0; i < exposures->n; i++) {
-	p2RawExposure *exposure = exposures->data[i];
-	
-	psMetadataAddStr (where, PS_LIST_TAIL, "EXP_ID", PS_META_REPLACE, "==", exposure->expID);
-
-	psArray *images = p2RawImageSelectRows (config->database, where, MAX_ROWS);
-
-	p2rawSet->exposure = exposure;
-	p2rawSet->images = images;
-
-	psArrayAdd (rawSet, 100, p2rawSet);
-    }
-
-    return true;
-} 
Index: /trunk/archive/p2tools/src/p2updatePending.c
===================================================================
--- /trunk/archive/p2tools/src/p2updatePending.c	(revision 5869)
+++ /trunk/archive/p2tools/src/p2updatePending.c	(revision 5869)
@@ -0,0 +1,31 @@
+# include "p2search.h"
+
+// select pending frames (exposure+images) which are not done, select their done images, count, update
+bool p2updatePendingFrames (p2SearchConfig *config, psArray *pendingFrames) {
+
+    psMetadata *where = psMetadataAlloc ();
+
+    // select all of the exposures which are still pending
+    psMetadataAddStr (where, PS_LIST_TAIL, "STATE", 0, "==", P2_STATE_PENDING);
+    psArray *exposures = p2PendingExposureSelectRows (config->database, where, MAX_ROWS);
+
+    // we will now select all of the matching images which are done
+    psMetadataAddStr (where, PS_LIST_TAIL, "STATE", PS_META_REPLACE, "==", P2_STATE_DONE);
+    for (int i = 0; i < exposures->n; i++) {
+	p2PendingExposure *exposure = exposures->data[i];
+
+	// find the next available version numbers
+	psMetadataAddStr (where, PS_LIST_TAIL, "EXP_ID",     PS_META_REPLACE, "==", exposure->expID);
+	psMetadataAddStr (where, PS_LIST_TAIL, "P2_VERSION", PS_META_REPLACE, "==", exposure->P2version);
+	psArray *images = p2PendingImageSelectRows (config->database, where, MAX_ROWS);
+	if (images->n != exposure->Nclass) {
+	    // free things
+	    continue;
+	}
+	// frame is complete, set exposure state to done
+	// XXX add P2 stats here?
+	exposure->state = P2_STATE_DONE;
+	p2PendingExposureUpdateRows (config->database, exposure);
+    }
+    return true;
+} 
Index: /trunk/archive/p2tools/src/p2writePendingFrames.c
===================================================================
--- /trunk/archive/p2tools/src/p2writePendingFrames.c	(revision 5869)
+++ /trunk/archive/p2tools/src/p2writePendingFrames.c	(revision 5869)
@@ -0,0 +1,25 @@
+# include "p2search.h"
+
+// select pending frames (exposure+images) which are done/not done
+bool p2writePendingImages (p2SearchConfig *config, psArray *frames) {
+
+    for (int i = 0; i < frames->n; i++) {
+	p2PendingFrame *frame = frames->data[i];
+	
+	for (int j = 0; j < frame->images->n; j++) {
+	    p2PendingImage *image = frame->images->data[j];
+	    fprintf (stdout, "%s %c %c %s %s %s %s %s %s %c\n",
+		     image->expID,
+		     image->P2version,
+		     image->class,
+		     image->classID,
+		     image->urlroot,
+		     image->input,
+		     image->output,
+		     image->log,
+		     image->smf,
+		     image->state);
+	}
+    }
+    return true;
+} 
