// $Id: PatternVariable.java,v 1.5 2004/02/27 16:30:00 m31 Exp $
//
// This file is part of the program suite "Principia Mathematica II"
// which is a working prototype for the main project:
// "Hilbert II" - http://www.qedeq.org
//
// Copyright 2001-2004  Michael Meyling <mime@qedeq.org>.
//
// "Principia Mathematica II" 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 program 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.

package com.meyling.principia.argument;


/**
 * Pattern variable, for matching purposes.
 *
 * @version $Revision: 1.5 $
 * @author  Michael Meyling
 */
public class PatternVariable extends AbstractArgument implements CounterMarker, Comparable {

    /** number of pattern variable */
    private final Counter number;

    /** remember constructor argument */
    private Argument arguments[] = null;

    /** assignment of pattern variable */
    private Argument content = null;


    /**
     * Constructs a pattern variable.
     *
     * @param   arguments  first argument is number of this pattern
     *          variable
     * @throws  ArgumentException    if there is not exactly one
     *          argument that is an instance of {@link Counter}
     */
    public PatternVariable(final Argument[] arguments)
            throws ArgumentException {
        this.arguments = arguments;
        if (arguments.length == 0) {
            throw new ArgumentException(
                ArgumentConstants.CODE_CONSTRUCTOR_WRONG_ARGUMENT_NUMBER,
                ArgumentConstants.AT_LEAST_ONE_ARGUMENT_EXPECTED);
        }
        if (!(arguments[0] instanceof Counter)) {
            throw new ArgumentException(
                ArgumentConstants.CODE_CONSTRUCTOR_WRONG_ARGUMENT_TYPE,
                ArgumentConstants.PATTERN_VARIABLE
                + ArgumentConstants.FIRST_ARGUMENT_TYPE
                + ArgumentConstants.COUNTER,
                arguments[0]);
        }
        this.number = (Counter) arguments[0];
    }


    /** @inherited */
    public final int getArgumentSize() {
        return this.arguments.length;
    };


    /** @inherited */
    public final Argument getArgument(final int i)
            throws IllegalArgumentException {
        if (i >= 0 && i < this.arguments.length) {
            return this.arguments[i];
        } else {
            if (this.arguments.length == 0)  {
                throw new IllegalArgumentException(
                    ArgumentConstants.NO_ARGUMENT_NUMBER);
            } else {
                throw new IllegalArgumentException(
                    ArgumentConstants.WRONG_ARGUMENT_NUMBER + "{0"
                    + (this.arguments.length > 1 ? ", .. "
                    + (this.arguments.length - 1) : "")
                    + "}");
            }
        }
    }


    /** @inherited */
    public Argument copy() {
        final Argument result;
        try {
            result = create(this.arguments);
        } catch (ArgumentException e) { //  should not occur
            throw new IllegalArgumentException(e.getMessage());
        }
        if (this.content != null) {
            ((PatternVariable) result).setContent(content.copy());
        }
        return result;
    }


    /**
     * Sets argument of pattern variable.
     *
     * @param   content assignment of pattern variable
     * @throws  IllegalArgumentException if there is already an
     *          assignment
     */
    public final void setContent(final Argument content) {
        if (this.content != null) {
            throw new IllegalArgumentException(
                ArgumentConstants.ALREADY_ASSIGNED);
        }
        this.content = content;
    }


    /**
     * Sets argument of pattern variable.
     *
     * @return  argument assignment of pattern variable,
     * @throws  IllegalArgumentException    if no value was assigned
     */
    public final Argument getContent() {
        if (this.content != null) {
            return this.content;
        } else {
            throw new IllegalArgumentException(
                ArgumentConstants.NOT_ASSIGNED);
        }
    }


    /**
     * Get number of pattern variable.
     *
     * @return  number of pattern variable
     */
    public final int getNumber() {
        return number.getNumber();
    }


    /**
     * @inherited
     * @return always returns true
     */
    public final boolean containsPatternVariables() {
        return true;
    }


    /** @inherited */
    public Argument create(final Argument[] arguments)
            throws ArgumentException {
        return new PatternVariable(arguments);
    }


    /**
     * Is the argument matching the pattern variable?
     * Here always true is returned.
     *
     * @param   argument    argument to match pattern variable
     * @return  <code>true</code>
     */
    public boolean isMatching(final Argument argument) {
        return true;
    }


    /** @inherited */
    public int compareTo(Object o) {
        if (o == null) {
            new NullPointerException("couldn't compare to null");
        }
        if (this.getClass().equals(o.getClass())) {
            final int delta = getNumber() - ((PatternVariable) o).getNumber();
            if (delta > 0) {
                return 1;
            } else if (delta < 0) {
                return -1;
            } else {
                return 0;
            }
        } else {
            return this.toString().compareTo(o.toString());
        }
    }


    /** @inherited */
    public String toString() {
        return "@" + number.toString();
    }


}
