// $Id: AddAxiom.java,v 1.7 2004/02/27 16:29:56 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.logic.rule;


import com.meyling.principia.argument.AbstractArgumentList;
import com.meyling.principia.argument.Argument;
import com.meyling.principia.argument.ArgumentException;
import com.meyling.principia.argument.Text;
import com.meyling.principia.logic.basic.Formula;
import com.meyling.principia.logic.paragraph.Axiom;
import com.meyling.principia.logic.paragraph.ParagraphCreator;
import com.meyling.principia.logic.paragraph.ProofLineList;
import com.meyling.principia.logic.paragraph.RuleDeclaration;
import com.meyling.principia.module.Module;
import com.meyling.principia.module.Version;


/**
 * Implementation of adding an Axiom:
 * <p>
 * <code>---------</code><p>
 * <code>       A0</code><p>
 * @version $Revision: 1.7 $
 * @author  Michael Meyling
 */
public class AddAxiom extends AbstractArgumentList
        implements Argument, Rule {

    /** minimum version required for using this rule */
    private final static Version version;

    /** reference to axiom that should be added */
    private final String axiomLabel;


    /**
     * Initialize version information.
     */
    static {
        try {
            version = new Version(
                    new Argument[] {new Text("1.00.00")});
        } catch (ArgumentException e) {
            throw new IllegalArgumentException(e.toString());
        }
    }


    /**
     * Constructs an add axiom rule by an axiom reference.
     *
     * @param  arguments    axiom reference
     * @throws ArgumentException if there is not exactly one
     *         argument or the argument is not an instance of
     *         {@link LinkLabel}
     */
    public AddAxiom(final Argument[] arguments)
            throws ArgumentException {
        super (arguments);
        if (arguments.length != 1) {
            throw new ArgumentException(
                RuleConstants.CODE_CONSTRUCTOR_WRONG_ARGUMENT_NUMBER,
                RuleCreator.getName(this.getClass())
                + RuleConstants.OPERATOR_WITH_ONE_ARGUMENT);
        }
        if (!(arguments[0] instanceof LinkReference)) {
            throw new ArgumentException(
                RuleConstants.CODE_CONSTRUCTOR_WRONG_ARGUMENT_TYPE,
                RuleCreator.getName(this.getClass())
                + RuleConstants.FIRST_ARGUMENT_TYPE
                + RuleCreator.getName(LinkReference.class),
                arguments[0]);
        }
        this.axiomLabel = ((LinkReference) arguments[0]).getReference();

    }


    /**
     * Check if proof could be extended with <code>formula</code>.
     * This is true
     * if formula is equivalent to the referenced axiom formula.
     *
     * @param   module    module
     * @param   proofLines  proof lines
     * @param   position number of proof lines that could be used
     *                    in the rule
     * @param   formula  formula to add
     * @throws  ArgumentException    if <code>formula</code> is not
     *          equal to the formula referenced by this object
     *          or a version conflict occurs
     */
    public final void check(final Module module,
            final ProofLineList proofLines,
            final int position,
            final Formula formula) throws ArgumentException {

        if (version.greaterThan(module.getRuleVersion())) {
            throw new ArgumentException(
                RuleConstants.CODE_METHOD_ARGUMENT_CHECK_FAILED,
                RuleCreator.getName(this.getClass())
                    + " " + RuleConstants.RULE_VERSION_CONFLICT
                    + version.getText(),
                this);
        }
        final Axiom axiom;
        try {
            axiom = module.getAxiom(axiomLabel);
        } catch (IllegalArgumentException e) {
            throw new ArgumentException(
                RuleConstants.CODE_METHOD_ARGUMENT_CHECK_FAILED,
                RuleCreator.getName(this.getClass())
                    + " " + e.getMessage(),
                this.getArgument(0));
        }
        if (!formula.equals(axiom.getArgument(0))) {
            throw new ArgumentException(
                RuleConstants.CODE_METHOD_ARGUMENT_CHECK_FAILED,
                RuleCreator.getName(this.getClass())
                    + RuleConstants.RESULT_NOT_EQUAL_WITH_EXPECTED,
                this);
        }
    }


    /** @inherited */
    public ProofLineList extendWithout(final Module module,
            final ProofLineList proofLines, final int position)
            throws UnsupportedOperationException {
        throw new UnsupportedOperationException (
            "this rule is neccessary: "
            + RuleCreator.getName(this.getClass()));
    }


    /** @inherited */
    public int[] getProofLines() {
        return new int[] {};
    }


    /** @inherited */
    public Rule changeProofLines(final int[] mapping) {
        return this;
    }


    /**
     * Check this rule could be declared.
     *
     * @param   module      the module context
     * @param   declaration the declaration that shall declare this rule
     * @throws  IllegalArgumentException    if an programming error occured
     * @throws  ArgumentException    if declaration failed
     */
    public final static void checkDeclaration(final Module module,
        final RuleDeclaration declaration) throws ArgumentException {
        if (declaration.getArgumentSize() > 2) {
            throw new ArgumentException(
                RuleConstants.CODE_METHOD_ARGUMENT_CHECK_FAILED,
                ParagraphCreator.getName(RuleDeclaration.class)
                    + RuleConstants.OPERATOR_WITH_TWO_ARGUMENTS,
                declaration);
        }
    }


    /** @inherited */
    public final Version getVersion() {
        return version;
    }


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


    /** @inherited */
    public final String toString() {
        return "Add Axiom " + getArgument(0);
    }


}
