/*
 * Node.cs
 *
 * This work is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published
 * by the Free Software Foundation; either version 2 of the License,
 * or (at your option) any later version.
 *
 * This work is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software 
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 * USA
 *
 * As a special exception, the copyright holders of this library give
 * you permission to link this library with independent modules to
 * produce an executable, regardless of the license terms of these
 * independent modules, and to copy and distribute the resulting
 * executable under terms of your choice, provided that you also meet,
 * for each linked independent module, the terms and conditions of the
 * license of that module. An independent module is a module which is
 * not derived from or based on this library. If you modify this
 * library, you may extend this exception to your version of the
 * library, but you are not obligated to do so. If you do not wish to
 * do so, delete this exception statement from your version.
 *
 * Copyright (c) 2003 Per Cederberg. All rights reserved.
 */

using System.Collections;
using System.IO;

namespace PerCederberg.Grammatica.Parser {

    /**
     * An abstract parse tree node. This class is inherited by all
     * nodes in the parse tree, i.e. by the token and production
     * classes.
     *
     * @author   Per Cederberg, <per at percederberg dot net>
     * @version  1.2
     */
    public abstract class Node {

        /**
         * The parent node. 
         */
        private Node parent = null;

        /**
         * The computed node values. 
         */
        private ArrayList values = null;

        /**
         * Checks if this node is hidden, i.e. if it should not be
         * visible outside the parser.
         * 
         * @return true if the node should be hidden, or
         *         false otherwise
         */
        internal virtual bool IsHidden() {
            return false;
        }

        /**
         * Returns the node type id. This value is set as a unique
         * identifier for each type of node, in order to simplify
         * later identification.
         * 
         * @return the node type id
         */
        public abstract int GetId();

        /**
         * Returns the node name.
         * 
         * @return the node name
         */
        public abstract string GetName();

        /**
         * The line number of the first character in this node. If the
         * node has child elements, this value will be fetched from
         * the first child.
         * 
         * @return the line number of the first character, or
         *         -1 if not applicable
         */
        public virtual int GetStartLine() {
            int  line;
            
            for (int i = 0; i < GetChildCount(); i++) {
                line = GetChildAt(i).GetStartLine();
                if (line >= 0) {
                    return line;
                }
            }
            return -1;
        }
    
        /**
         * The column number of the first character in this node. If
         * the node has child elements, this value will be fetched
         * from the first child.
         * 
         * @return the column number of the first token character, or
         *         -1 if not applicable
         */
        public virtual int GetStartColumn() {
            int  col;
            
            for (int i = 0; i < GetChildCount(); i++) {
                col = GetChildAt(i).GetStartColumn();
                if (col >= 0) {
                    return col;
                }
            }
            return -1;
        }
    
        /**
         * The line number of the last character in this node. If the
         * node has child elements, this value will be fetched from
         * the last child.
         * 
         * @return the line number of the last token character, or
         *         -1 if not applicable
         */
        public virtual int GetEndLine() {
            int  line;
            
            for (int i = GetChildCount() -1; i >= 0; i--) {
                line = GetChildAt(i).GetEndLine();
                if (line >= 0) {
                    return line;
                }
            }
            return -1;
        }
    
        /**
         * The column number of the last character in this node. If
         * the node has child elements, this value will be fetched
         * from the last child.
         * 
         * @return the column number of the last token character, or
         *         -1 if not applicable
         */
        public virtual int GetEndColumn() {
            int  col;
            
            for (int i = GetChildCount() -1; i >= 0; i--) {
                col = GetChildAt(i).GetEndColumn();
                if (col >= 0) {
                    return col;
                }
            }
            return -1;
        }

        /**
         * Returns the parent node. 
         * 
         * @return the parent parse tree node
         */
        public Node GetParent() {
            return parent;
        }

        /**
         * Sets the parent node.
         * 
         * @param parent         the new parent node
         */
        internal void SetParent(Node parent) {
            this.parent = parent;
        }

        /**
         * Returns the number of child nodes.
         * 
         * @return the number of child nodes
         */
        public virtual int GetChildCount() {
            return 0;
        }

        /**
         * Returns the child node with the specified index.
         * 
         * @param index          the child index, 0 <= index < count
         * 
         * @return the child node found, or 
         *         null if index out of bounds
         */
        public virtual Node GetChildAt(int index) {
            return null; 
        }
    
        /**
         * Returns the number of descendant nodes.
         * 
         * @return the number of descendant nodes
         * 
         * @since 1.2
         */
        public int GetDescendantCount() {
            int  count = 0;
        
            for (int i = 0; i < GetChildCount(); i++) {
                count += 1 + GetChildAt(i).GetDescendantCount();
            }
            return count;
        }

        /**
         * Returns the number of computed values associated with this
         * node. Any number of values can be associated with a node
         * through calls to AddValue().
         *
         * @return the number of values associated with this node
         */
        public int GetValueCount() {
            if (values == null) {
                return 0;
            } else {
                return values.Count;
            }
        }

        /**
         * Returns a computed value of this node, if previously set. A
         * value may be used for storing intermediate results in the
         * parse tree during analysis.
         *
         * @param pos             the value position, 0 <= pos < count 
         *
         * @return the computed node value, or
         *         null if not set
         */
        public object GetValue(int pos) {
            if (values == null || pos < 0 || pos >= values.Count) {
                return null;
            } else {
                return values[pos];
            }
        }
    
        /**
         * Returns the list with all the computed values for this
         * node. Note that the list is not a copy, so changes will
         * affect the values in this node (as it is the same object).
         *
         * @return a list with all values, or
         *         null if no values have been set 
         */
        public ArrayList GetAllValues() {
            return values;
        }

        /**
         * Adds a computed value to this node. The computed value may
         * be used for storing intermediate results in the parse tree
         * during analysis.
         * 
         * @param value          the node value
         */
        public void AddValue(object value) {
            if (value != null) {
                if (values == null) {
                    values = new ArrayList();
                }
                values.Add(value);
            }
        }
    
        /**
         * Adds a set of computed values to this node.
         *
         * @param values         the vector with node values
         */
        public void AddValues(ArrayList values) {
            if (values != null) {
                for (int i = 0; i < values.Count; i++) {
                    AddValue(values[i]);
                }
            }
        }
        
        /**
         * Removes all computed values stored in this node.
         */
        public void RemoveAllValues() {
            values = null;
        }

        /**
         * Prints this node and all subnodes to the specified output 
         * stream.
         * 
         * @param output         the output stream to use
         */
        public void PrintTo(TextWriter output) {
            PrintTo(output, "");
            output.Flush();
        }
    
        /**
         * Prints this node and all subnodes to the specified output 
         * stream.
         * 
         * @param output         the output stream to use
         * @param indent         the indentation string
         */
        private void PrintTo(TextWriter output, string indent) {
            output.WriteLine(indent + ToString());
            indent = indent + "  ";
            for (int i = 0; i < GetChildCount(); i++) {
                GetChildAt(i).PrintTo(output, indent);
            }
        }
    }
}