/*
 * TclIndex.java
 *
 *	This file implements objects of type "index".  This object type
 *	is used to lookup a keyword in a table of valid values and cache
 *	the index of the matching entry.
 *
 * Copyright (c) 1997 Sun Microsystems, Inc.
 *
 * See the file "license.terms" for information on usage and
 * redistribution of this file, and for a DISCLAIMER OF ALL
 * WARRANTIES.
 * 
 * RCS: @(#) $Id: TclIndex.java,v 1.6 2005/10/11 20:03:23 mdejong Exp $
 */

package tcl.lang;

public class TclIndex implements InternalRep {

    /**
     * The variable slots for this object.
     */
    private int index;

    /**
     * Table of valid options.
     */

    private String[] table;

    /**
     * Construct a TclIndex representation with the given index & table.
     */
    private TclIndex(int i, String[] tab) {
	index = i;
	table = tab;
    }

    /**
     * Returns a dupilcate of the current object.
     * @param obj the TclObject that contains this internalRep.
     */
    public InternalRep duplicate() {
	return new TclIndex(index, table);
    }

    /**
     * Implement this no-op for the InternalRep interface.
     */

    public void dispose() {}

    /**
     * Called to query the string representation of the Tcl object. This
     * method is called only by TclObject.toString() when
     * TclObject.stringRep is null.
     *
     * @return the string representation of the Tcl object.
     */
    public String toString() {
	return table[index];
    }

    /**
     * Tcl_GetIndexFromObj -> get
     *
     * Gets the index into the table of the object.  Generate an error
     * it it doesn't occur.  This also converts the object to an index
     * which should catch the lookup for speed improvement.
     *
     * @param interp the interperter or null
     * @param tobj the object to operate on.
     * @paran table the list of commands
     * @paran msg used as part of any error messages
     * @paran flags may be TCL.EXACT.
     */

    public static int get(Interp interp, TclObject tobj, String[] table,
	    String msg, int flags) throws TclException {
	InternalRep rep = tobj.getInternalRep();

	if (rep instanceof TclIndex) {
	    if (((TclIndex) rep).table == table) {
		return ((TclIndex) rep).index;
	    }
	}

	String str = tobj.toString();
	int strLen = str.length();
	int tableLen = table.length;
	int index = -1;
	int numAbbrev = 0;

	checking: {
	    if (strLen > 0) {

		for (int i = 0; i < tableLen; i++) {
		    String option = table[i];

		    if (((flags & TCL.EXACT) == TCL.EXACT) && 
		            (option.length() != strLen)) {
			continue;
		    }
		    if (option.equals(str)) {
			// Found an exact match already. Return it.

			index = i;
			break checking;
		    }
		    if (option.startsWith(str)) {
			numAbbrev++;
			index = i;
		    }
		}
	    }
	    if (numAbbrev != 1) {
		StringBuffer sbuf = new StringBuffer();
		if (numAbbrev > 1) {
		    sbuf.append("ambiguous ");
		} else {
		    sbuf.append("bad ");
		}
		sbuf.append(msg);
		sbuf.append(" \"");
		sbuf.append(str);
		sbuf.append("\"");
		sbuf.append(": must be ");
		sbuf.append(table[0]);
		for (int i = 1; i < tableLen; i++) {
		    if (i == (tableLen - 1)) {
			sbuf.append((i>1) ? ", or " : " or ");
		    } else {
			sbuf.append(", ");
		    }
		    sbuf.append(table[i]);
		}
		throw new TclException(interp, sbuf.toString());
	    }
	}

	// Create a new index object.

	tobj.setInternalRep(new TclIndex(index, table));
	return index;
    }

    /**
     * Invoked only when testing the TclIndex implementation in TestObjCmd.java
     */
    void testUpdateIndex(int index) {
        this.index = index;
    }

}

