package de.renew.net.inscription.transition;

import java.util.Collection;
import java.util.List;
import java.util.Vector;

import de.renew.engine.searcher.Occurrence;
import de.renew.engine.searcher.Searcher;
import de.renew.expression.Expression;
import de.renew.expression.VariableMapper;
import de.renew.net.NetInstance;
import de.renew.net.Transition;
import de.renew.net.inscription.TransitionInscription;

/**
 * A {@code DownlinkInscription} is used to indicate that the corresponding transition is the downlink of a certain
 * synchronous channel. For example, a {@code DownlinkInscription} is created for a transition inscribed with
 * "this:lookup(x,y)". Then the transition is an initiating transition of the synchronous channel "lookup", whose
 * uplink is located in the same net instance, with the parameters x and y.
 */
public class DownlinkInscription implements TransitionInscription {
    /**
     * The name of the synchronous channel.
     */
    private final String _name;

    /**
     * The {@code Expression} evaluating to variables that will be unified with the synchronous
     * channel's parameters.
     */
    private final Expression _params;

    /**
     * The {@code Expression} evaluating to a variable containing the reference to a net instance
     * that contains the channel's uplink.
     */
    private final Expression _callee;

    /**
     * The {@code Transition} that contains the {@code DownlinkInscription}.
     */
    private final Transition _transition;

    /**
     * {@code true} if the downlink is optional.
     */
    private final boolean _isOptional;


    /**
     * Constructs a new {@code DownlinkInscription} with the given parameters.
     *
     * @param name the name of the synchronous channel
     * @param params the {@code Expression} representing the parameters of the synchronous channel
     * @param callee the {@code Expression} representing the net instance containing the channel's uplink
     * @param isOptional {@code true} if the downlink is optional
     * @param transition the {@code Transition} that contains the {@code DownlinkInscription}
     */
    public DownlinkInscription(
        String name, Expression params, Expression callee, boolean isOptional,
        Transition transition)
    {
        _name = name;
        _params = params;
        _callee = callee;
        _isOptional = isOptional;
        _transition = transition;
    }

    // Refactoring
    /**
     * The start index of the downlink line.
     */
    private int _downlinkBeginLine;

    /**
     * The start index of the downlink column.
     */
    private int _downlinkBeginColumn;

    /**
     * The end index of the downlink line.
     */
    private int _downlinkEndLine;

    /**
     * The end index of the downlink column.
     */
    private int _downlinkEndColumn;

    /**
     * The start index of the name line.
     */
    private int _nameBeginLine;

    /**
     * The start index of the name column.
     */
    private int _nameBeginColumn;

    /**
     * The end index of the name column.
     */
    private int _nameEndColumn;

    /**
     * The end index of the name line.
     */
    private int _nameEndLine;

    @Override
    public Collection<Occurrence> makeOccurrences(
        VariableMapper mapper, NetInstance netInstance, Searcher searcher)
    {
        return new Vector<>(
            List.of(
                new DownlinkOccurrence(
                    _params, _callee, _name, _isOptional, mapper,
                    netInstance.getInstance(_transition))));
    }

    /**
     * Getter for {@code name}.
     * @return {@code name}.
     */
    public String getName() {
        return _name;
    }

    /**
     * Getter for {@code params}.
     * @return {@code params}.
     */
    public Expression getParameterExpression() {
        return _params;
    }

    /**
     * Getter for {@code callee}.
     * @return {@code callee}.
     */
    public Expression getCallee() {
        return _callee;
    }

    /**
     * Getter for {@code transition}.
     * @return {@code transition}.
     */
    public Transition getTransition() {
        return _transition;
    }

    /**
     * Getter for {@code downlinkBeginLine}.
     * @return {@code downlinkBeginLine}.
     */
    public int getDownlinkBeginLine() {
        return _downlinkBeginLine;
    }

    /**
     * Getter for {@code downlinkBeginColumn}.
     * @return {@code downlinkBeginColumn}.
     */
    public int getDownlinkBeginColumn() {
        return _downlinkBeginColumn;
    }

    /**
     * Getter for {@code downlinkEndLine}.
     * @return {@code downlinkEndLine}.
     */
    public int getDownlinkEndLine() {
        return _downlinkEndLine;
    }

    /**
     * Getter for {@code downlinkEndColumn}.
     * @return {@code downlinkEndColumn}.
     */
    public int getDownlinkEndColumn() {
        return _downlinkEndColumn;
    }

    /**
     * Getter for {@code nameBeginLine}.
     * @return {@code nameBeginLine}.
     */
    public int getNameBeginLine() {
        return _nameBeginLine;
    }

    /**
     * Getter for {@code nameBeginColumn}.
     * @return {@code nameBeginColumn}.
     */
    public int getNameBeginColumn() {
        return _nameBeginColumn;
    }

    /**
     * Getter for {@code nameEndColumn}.
     * @return {@code nameEndColumn}.
     */
    public int getNameEndColumn() {
        return _nameEndColumn;
    }

    /**
     * Getter for {@code nameEndLine}.
     * @return {@code nameEndLine}.
     */
    public int getNameEndLine() {
        return _nameEndLine;
    }

    /**
     * Setter for {@code downlinkBeginLine}.
     * @param downlinkBeginLine the value to set for {@code downlinkBeginLine}.
     */
    public void setDownlinkBeginLine(int downlinkBeginLine) {
        _downlinkBeginLine = downlinkBeginLine;
    }

    /**
     * Setter for {@code downlinkBeginColumn}.
     * @param downlinkBeginColumn the value to set for {@code downlinkBeginColumn}.
     */
    public void setDownlinkBeginColumn(int downlinkBeginColumn) {
        _downlinkBeginColumn = downlinkBeginColumn;
    }

    /**
     * Setter for {@code downlinkEndLine}.
     * @param downlinkEndLine the value to set for {@code downlinkEndLine}.
     */
    public void setDownlinkEndLine(int downlinkEndLine) {
        _downlinkEndLine = downlinkEndLine;
    }

    /**
     * Setter for {@code downlinkEndColumn}.
     * @param downlinkEndColumn the value to set for {@code downlinkEndColumn}.
     */
    public void setDownlinkEndColumn(int downlinkEndColumn) {
        _downlinkEndColumn = downlinkEndColumn;
    }

    /**
     * Setter for {@code nameBeginLine}.
     * @param nameBeginLine the value to set for {@code nameBeginLine}.
     */
    public void setNameBeginLine(int nameBeginLine) {
        _nameBeginLine = nameBeginLine;
    }

    /**
     * Setter for {@code nameBeginColumn}.
     * @param nameBeginColumn the value to set for {@code nameBeginColumn}.
     */
    public void setNameBeginColumn(int nameBeginColumn) {
        _nameBeginColumn = nameBeginColumn;
    }

    /**
     * Setter for {@code nameEndColumn}.
     * @param nameEndColumn the value to set for {@code nameEndColumn}.
     */
    public void setNameEndColumn(int nameEndColumn) {
        _nameEndColumn = nameEndColumn;
    }

    /**
     * Setter for {@code nameEndLine}.
     * @param nameEndLine the value to set for {@code nameEndLine}.
     */
    public void setNameEndLine(int nameEndLine) {
        _nameEndLine = nameEndLine;
    }
}