package yacs.parser;

import yacs.domain.*;

import java.util.*;

/**
 * <p>Klasse zur Repräsentation eines unären Operators innerhalb einer
 * rekursiven Struktur zur Repräsentation eines algebraischen
 * Constraint-Problems (Dokumentation siehe <code>Expression</code>).</p>
 *
 * <p>Copyright (C) 2005  Wolfgang Runte
 * <br><br>
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * <br><br>
 * This library 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
 * Lesser General Public License for more details.
 * <br><br>
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
 * USA</p>
 *
 * @author Wolfgang Runte (woru@tzi.org)
 * @version YACS 0.1.1
 */
public class UnaryOperator extends Expression {

// ********** private attributs **********

  /** Bezeichnet den Typ des Operators (vgl. <code>yacs.parser.sym</code>). */
  private int type;

  /** Der "Name" des Operators (für die Ausgabe mit <code>toString()</code>). */
  private String name;

  /**
   * Der Constraint-Ausdruck, auf den der Operator angewendet wird.
   * @supplierCardinality 1
   * @clientCardinality 1
   * @link aggregation
   */
  private Expression expr;

// ********** public attributs **********

// ********** private methods **********

// ********** public methods **********

  /**
   * Konstruktor -- Instantiiert den Operator mit seinem Typ, seinem "Namen" und
   * dem zugehörigen Constraint-Ausdruck.
   * @param type int
   * @param name String
   * @param expr Expression
   */
  public UnaryOperator(int type, String name, Expression expr) {
    this.type = type;
    this.name = name;
    this.expr = expr;
  }

  public boolean setDomain(String variableName, Domain domain) {
    return this.expr.setDomain(variableName, domain);
  }

  public Domain getDomain(String variableName) {
    return this.expr.getDomain(variableName);
  }

  public List getVariables() {
    // Variablen aus dem "Zweig" holen:
    List variableList = this.expr.getVariables();
    // ... doppelte dabei löschen: (Verbesserungsvorschlag: Klasse "Set" nutzen)
    if (variableList.size() > 1) {
      for (int i = 0; i < variableList.size()-1; i++) {
        for (int j = i+1; j < variableList.size(); j++) {
          if (((String)variableList.get(i)).equals((String)variableList.get(j))) {
            variableList.remove(j);
            j--;
          }
        }
      }
    }
    return variableList;
  }

  public List getUnsetVariables() {
    // Variablen aus dem "Zweig" holen:
    List variableList = this.expr.getUnsetVariables();
    // ... doppelte dabei löschen: (Verbesserungsvorschlag: Klasse "Set" nutzen)
    if (variableList.size() > 1) {
      for (int i = 0; i < variableList.size()-1; i++) {
        for (int j = i+1; j < variableList.size(); j++) {
          if (((String)variableList.get(i)).equals((String)variableList.get(j))) {
            variableList.remove(j);
            j--;
          }
        }
      }
    }
    return variableList;
  }

  public boolean unsetVariablesLeft() {
    if (this.getUnsetVariables().isEmpty()) {
      return false;
    }
    return true;
  }

  public boolean set(String variableName, DomainElement element) {
    return this.expr.set(variableName, element);
  }

  public DomainElement get(String variableName) {
    return this.expr.get(variableName);
  }

  public boolean satisfiable() {
    return this.expr.satisfiable();
  }

  public DomainElement evaluate() {
    switch (this.type) {
      case sym.UMINUS : return (DomainElement)((DomainElement)this.expr.evaluate()).uminus();
      default:
        System.err.println("Error in UnaryOperator.evaluate(): unknown operator with type " + this.type);
        return null;
    }
  }

  public List getPrimitiveExpressions() {
    return new LinkedList();
  }

  public Variable getVariableReference(String variableName) {
    return this.expr.getVariableReference(variableName);
  }

  public boolean containsVariable(String variableName) {
    return expr.containsVariable(variableName);
  }

  public boolean hasFalseDomain() {
    return this.expr.hasFalseDomain();
  }

  public boolean hasValuationDomain() {
    return this.expr.hasFalseDomain();
  }

  public boolean setValuationDomain() {
    return this.expr.setValuationDomain();
  }

  public void singletons() {
    this.expr.singletons();
  }

  public int count(String variableName) {
    return expr.count(variableName);
  }

  public void init() {
    this.expr.init();
  }

  public String toString() {
    if (this.name == null || this.name == "") {
      return ("op_"+this.type+"("+this.expr+")");
    }
    return (this.name+"("+this.expr+")");
  }

}
