/*
 * t4open.cpp --
 *
 *	Implementation of the the T4Graph command to open a storage.
 *
 *	Authors: Jacob Levy and Jean-Claude Wippler.
 *		 jyl@best.com	jcw@equi4.com
 *
 * Copyright (c) 2000-2003, JYL Software Inc.
 * 
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 * 
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE, EVEN IF
 * JYL SOFTWARE INC. IS MADE AWARE OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "t4graphrep.h"

/*
 * This procedure is called when the interpreter is deleted, to close
 * all storages that were registered with this interpreter.
 */

static void
interpDelete(ClientData *ignored, Tcl_Interp *interp)
{
    Tcl_HashSearch search;
    T4Storage *sp;

    for (sp = T4Graph_FirstStorage(&search);
	 sp != NULL;
	 sp = T4Graph_NextStorage(&search)) {
	sp->UnregisterStoragePerInterp(interp);
    }
}

/*
 * T4Graph_OpenStorageProc --
 *
 *	This procedure is called when "tgraph::open" is invoked.
 *	Syntax:
 *		tgraph::open name ?opt val ..?
 *
 * Results:
 *	A standard Tcl result. The interpreter result will contain the
 *	name of the opened storage if successful.
 *
 * Side effects:
 *	May open a new storage.
 */

int
T4Graph_OpenStorageProc(ClientData cd,
			Tcl_Interp *interp,
			int objc,
			Tcl_Obj *CONST objv[])
{
    T4StorageOptions storageOptions;
    char *fnm = NULL;
    T4Storage *sp;

    /*
     * An even number of arguments is expected, and at least two
     * arguments are expected.
     */

    if ((objc < 2) || ((objc % 2) != 0)) {
	Tcl_WrongNumArgs(interp, 1, objv, (char *) "name ?opt val ..?");
	return TCL_ERROR;
    }

    /*
     * The second argument is the storage name. The rest of the arguments
     * are opt-val pairs.
     */

    fnm = Tcl_GetString(objv[1]);

    /*
     * Initialize the storage options to the default values:
     */

    storageOptions.driver = E4_METAKIT;
    storageOptions.rwmode = "rw";
    storageOptions.modes = E4_DEFAULTSTATE;      

    /*
     * Parse the rest of the arguments:
     */

    if (!T4Graph_ParseStorageOptions(interp, objc-2, objv+2,
				     &storageOptions)) {
	return TCL_ERROR;
    }

    /*
     * Attempt to open the requested storage.
     */

    e4_Storage s(fnm, storageOptions.driver, storageOptions.modes);

    /*
     * If the storage was not opened successfully, bail out
     * right away.
     */

    if (!s.IsValid()) {
	Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
			       fnm, ": cannot open with ",
			       storageOptions.driver, NULL);
	return TCL_ERROR;
    }

    /*
     * Register this storage in the global storages registry. If it already
     * exists, the globally registered instance is returned.
     */

    sp = T4Graph_RegisterStorage(s, fnm, storageOptions.driver);

    /*
     * Register the storage with this interpreter.
     */

    sp->RegisterStoragePerInterp(interp);

    /*
     * Return the Tcl name as the result and export it as a command.
     */

    if (T4Graph_MakeStorageCommand(interp, sp) == TCL_ERROR) {
	return TCL_ERROR;
    }

    /*
     * Ensure that this interpreter is set up so that all storages that
     * are registered within it are closed when the interpreter is deleted.
     */

    T4Graph_RegisterInterp(interp);

    /*
     * Success -- return the name of the storage command.
     */

    Tcl_ResetResult(interp);
    Tcl_SetStringObj(Tcl_GetObjResult(interp), sp->GetName(), -1);

    return TCL_OK;
}

/*
 * Register this interpreter so that all storages registered within it
 * will be properly closed when the interpreter is deleted.
 */

void
T4Graph_RegisterInterp(Tcl_Interp *interp)
{
    int key;

    /*
     * If the key hasn't been registered yet, do it now.
     */

    key = (int) Tcl_GetAssocData(interp, T4_ASSOCKEY, NULL);
    if (key == 0) {
	Tcl_SetAssocData(interp,
			 T4_ASSOCKEY, 
			 (Tcl_InterpDeleteProc *) interpDelete, 
			 (ClientData) 1);
    }
}
