/*
 * (C) Copyright IBM Corp. 1997-1998  All rights reserved.
 *
 * US Government Users Restricted Rights Use, duplication or
 * disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
 *
 * The program is provided "as is" without any warranty express or
 * implied, including the warranty of non-infringement and the implied
 * warranties of merchantibility and fitness for a particular purpose.
 * IBM will not be liable for any damages suffered by you as a result
 * of using the Program. In no event will IBM be liable for any
 * special, indirect or consequential damages or lost profits even if
 * IBM has been advised of the possibility of their occurrence. IBM
 * will not be liable for any third party claims against you.
 */

package com.ibm.xml.parser;

import java.util.*;

/**
 * CM1op provides content model support for content model nodes that contain the &quot;*&quot;,
 * &quot;?&quot;, and &quot;+&quot; language primitives.  Refer to ElementDecl for an overview
 * of the content model, and how these language primitives are used to express relationships.
 *
 * @version 1.1
 * @author TAMURA Kent &lt;kent@trl.ibm.co.jp&gt;
 * @see com.ibm.xml.parser.ElementDecl
 * @see com.ibm.xml.parser.CMNode
 * @see com.ibm.xml.parser.CMLeaf
 */
public class CM1op extends CMNode {
    
            int     type    =   0;      // '*' or `+' or '?'
            CMNode  node    =   null;
    
    /**
     * Constructor.
     * @param type  The language primitive associated with this content model node.  Must
     *              be &quot;*&quot;, &quot;?&quot;, or &quot;+&quot;.
     * @param node  The content model node to associate with <var>type</var>, or <var>null</var>
     *              if <var>node</var> will be set later.
     */
    public CM1op(int type, CMNode node) {
        this.type = type;
        this.node = node;
    }
    
    /**
     * Returns the language primitive associated with this content model node.  
     * @return          &quot;*&quot;, &quot;?&quot;, or &quot;+&quot; 
     *                  (should never be <var>null</var>). 
     */
    public int getType() {
        return this.type;
    }
    
    /**
     * Returns the content model node associated with <var>type</var>.  
     * @return          The content model node associated with <var>type</var>, or 
     *                  <var>null</var> if no node currently exists.
     * @see #setNode
     */
    public CMNode getNode() {
        return this.node;
    }
    
    /**
     * Sets the content model node associated with <var>type</var>.  
     * @param   node    The content model node to associate with <var>type</var>. 
     * @see #getNode
     */
    public void setNode(CMNode node) {
        this.node = node;
    }
    
    /**
     * Returns the string representation of this content model node and its associated
     * language primitive.
     * Example: <code><var>elementX</var>*</code>
     * @return          The string representation of this content model node
     *                  (should never be <var>null</var>). 
     */
    public String toString() {
        return this.node.toString()+(char)this.type;
    }
    
    boolean nullable() {
        if (null == this.nullable) {
            boolean ret = false;
            switch (this.type) {
              case '*':
                ret = true;
                break;
              case '+':
                ret = this.node.nullable();
                break;
              case '?':
                ret = true;
                break;
            }
            this.nullable = new Boolean(ret);
        }
        return this.nullable.booleanValue();
    }
    
    CMNode cloneNode() {
        return new CM1op(this.type, this.node.cloneNode());
    }
    
    BitSet firstpos() {
        if (null == this.firstPos) {
            this.firstPos = this.node.firstpos();
        }
        return this.firstPos;
    }
    
    BitSet lastpos() {
        if (null == this.lastPos) {
            this.lastPos = this.node.lastpos();
        }
        return this.lastPos;
    }
    
    void prepare(int n) {
        this.node.prepare(n);
    }
    
    void setFollowpos(BitSet[] fp) throws LibraryException {
        this.node.setFollowpos(fp);
        if ('+' == this.type) {
            throw new LibraryException("com.ibm.xml.parser.CM1op#setFollowpos(): This method should not have been called for plus (+) operator.");
        } else if ('*' == this.type) {
            for (int i = 0;  i < fp.length;  i ++) {
                if (lastpos().get(i))
                    fp[i].or(firstpos());
            }
        } else if ('?' == this.type) {
        }
    }
}

