/*
!=======================================================================
!
!  PROGRAM  PHASE-Viewer  (PHASE-Viewer 2014.01 ver.3.3.0)
!
!  Created on ----
!  AUTHOR(S): KOGA, Junichiro
!  File : KeywordMap.java
!  
!  Contact address :  Phase System Consortium
!                     E-mail: phase_system@nims.go.jp URL https://azuma.nims.go.jp
!
!
!   Since 2002, this program set had been intensively developed as a part of the following 
!  national projects supported by the Ministry of Education, Culture, Sports, Science and
!  Technology (MEXT) of Japan; "Frontier Simulation Software for Industrial Science
!  (FSIS)" from 2002 to 2005, "Revolutionary Simulation Software (RSS21)" from 2006 to
!  2008. "Research and Development of Innovative Simulation Software (RISS)" from 2008
!  to 2013. These projects is lead by the Center for Research on Innovative Simulation 
!  Software (CISS), the Institute of Industrial Science (IIS), the University of Tokyo.
!   Since 2013, this program set has been further developed centering on PHASE System
!  Consortium. 
!   The activity of development of this program set has been supervised by Takahisa Ohno.
!
!=======================================================================
 */

package ciss.phase_viewer.pub.jeditsyntax;

import javax.swing.text.Segment;

/**
 * A <code>KeywordMap</code> is similar to a hashtable in that it maps keys to
 * values. However, the `keys' are Swing segments. This allows lookups of text
 * substrings without the overhead of creating a new string object.
 * <p>
 * This class is used by <code>CTokenMarker</code> to map keywords to ids.
 * 
 * @author Slava Pestov, Mike Dillon
 * @version $Id: KeywordMap.java,v 1.16 1999/12/13 03:40:30 sp Exp $
 */
public class KeywordMap {
    /**
     * Creates a new <code>KeywordMap</code>.
     * 
     * @param ignoreCase
     *            True if keys are case insensitive
     */
    public KeywordMap(boolean ignoreCase) {
        this(ignoreCase, 52);
        this.ignoreCase = ignoreCase;
    }

    /**
     * Creates a new <code>KeywordMap</code>.
     * 
     * @param ignoreCase
     *            True if the keys are case insensitive
     * @param mapLength
     *            The number of `buckets' to create. A value of 52 will give
     *            good performance for most maps.
     */
    public KeywordMap(boolean ignoreCase, int mapLength) {
        this.mapLength = mapLength;
        this.ignoreCase = ignoreCase;
        map = new Keyword[mapLength];
    }

    /**
     * Looks up a key.
     * 
     * @param text
     *            The text segment
     * @param offset
     *            The offset of the substring within the text segment
     * @param length
     *            The length of the substring
     */
    public byte lookup(Segment text, int offset, int length) {
        if (length == 0)
            return Token.NULL;
        Keyword k = map[getSegmentMapKey(text, offset, length)];
        while (k != null) {
            if (length != k.keyword.length) {
                k = k.next;
                continue;
            }
            if (SyntaxUtilities.regionMatches(ignoreCase, text, offset,
                    k.keyword))
                return k.id;
            k = k.next;
        }
        return Token.NULL;
    }

    /**
     * Adds a key-value mapping.
     * 
     * @param keyword
     *            The key
     * @Param id The value
     */
    public void add(String keyword, byte id) {
        int key = getStringMapKey(keyword);
        map[key] = new Keyword(keyword.toCharArray(), id, map[key]);
    }

    /**
     * Returns true if the keyword map is set to be case insensitive, false
     * otherwise.
     */
    public boolean getIgnoreCase() {
        return ignoreCase;
    }

    /**
     * Sets if the keyword map should be case insensitive.
     * 
     * @param ignoreCase
     *            True if the keyword map should be case insensitive, false
     *            otherwise
     */
    public void setIgnoreCase(boolean ignoreCase) {
        this.ignoreCase = ignoreCase;
    }

    // protected members
    protected int mapLength;

    protected int getStringMapKey(String s) {
        return (Character.toUpperCase(s.charAt(0)) + Character.toUpperCase(s
                .charAt(s.length() - 1))) % mapLength;
    }

    protected int getSegmentMapKey(Segment s, int off, int len) {
        return (Character.toUpperCase(s.array[off]) + Character
                .toUpperCase(s.array[off + len - 1])) % mapLength;
    }

    // private members
    class Keyword {
        public Keyword(char[] keyword, byte id, Keyword next) {
            this.keyword = keyword;
            this.id = id;
            this.next = next;
        }

        public char[] keyword;
        public byte id;
        public Keyword next;
    }

    private Keyword[] map;
    private boolean ignoreCase;
}
