package org.opengroupware.jope.eocontrol;

import java.util.Set;

import org.opengroupware.jope.foundation.NSKeyValueCodingAdditions;

/*
 * EOKeyComparisonQualifier
 * 
 * Compares two values of a given object.
 * 
 * Syntax:
 *   lastname = firstname
 *   businessAddress.street = homeAddress.street
 *   
 * TODO: document
 */
// TODO: add operator

public class EOKeyComparisonQualifier extends EOQualifier
  implements EOQualifierEvaluation
{

  protected String leftKey  = null;
  protected String rightKey = null;
  protected ComparisonOperation operation;

  public EOKeyComparisonQualifier
    (String _leftKey, ComparisonOperation _op, String _rightKey)
  {
    this.leftKey   = _leftKey;
    this.rightKey  = _rightKey;
    this.operation = _op;
  }
  public EOKeyComparisonQualifier(String _leftKey, String _rightKey) {
    this(_leftKey, ComparisonOperation.EQUAL_TO, _rightKey);
  }
  public EOKeyComparisonQualifier
    (String _leftKey, String _op, String _rightKey)
  {
    this(_leftKey, operationForString(_op), _rightKey);
  }
  
  /* accessors */
  
  public String leftKey() {
    return this.leftKey;
  }
  
  public String rightKey() {
    return this.rightKey;
  }
  
  public ComparisonOperation operation() {
    return this.operation;
  }
  
  /* evaluation */
  
  public boolean evaluateWithObject(Object _object) {
    Object lv, rv;
    
    if (_object == null) {
      lv = null;
      rv = null;
    }
    else if (_object instanceof NSKeyValueCodingAdditions) {
      NSKeyValueCodingAdditions ko = (NSKeyValueCodingAdditions)_object;
      lv = ko.valueForKeyPath(this.leftKey);
      rv = ko.valueForKeyPath(this.rightKey);
    }
    else {
      lv = NSKeyValueCodingAdditions.Utility
            .valueForKeyPath(_object, this.leftKey);
      rv = NSKeyValueCodingAdditions.Utility
            .valueForKeyPath(_object, this.rightKey);
    }
    
    EOQualifier.ComparisonSupport comparisonSupport;
    if (lv != null)
      comparisonSupport = supportForClass(lv.getClass());
    else
      comparisonSupport = supportForClass(null);

    return comparisonSupport.compareOperation(this.operation, lv, rv);
  }

  /* keys */
  
  public void addQualifierKeysToSet(Set<String> _keys) {
    if (_keys == null) return;
    if (this.leftKey  != null) _keys.add(this.leftKey);
    if (this.rightKey != null) _keys.add(this.rightKey);
  }
  
  /* bindings */
  
  public EOQualifier qualifierWithBindings(Object _vals, boolean _requiresAll) {
    /* Hm, we can't replace keys? Might make sense, because a JDBC prepared
     *     statement can't do this either.
     */
    return this;
  }
  
  /* string representation */
  
  public boolean appendStringRepresentation(StringBuffer _sb) {
    this.appendIdentifierToStringRepresentation(_sb, this.leftKey);
    _sb.append(" ");
    _sb.append(stringForOperation(this.operation));
    _sb.append(" ");
    this.appendIdentifierToStringRepresentation(_sb, this.rightKey);
    return true;
  }
  
  /* description */

  public void appendAttributesToDescription(StringBuffer _d) {
    super.appendAttributesToDescription(_d);
    _d.append(" lhs=" + this.leftKey);
    _d.append(" op='"  + stringForOperation(this.operation) + "'");
    _d.append(" rhs=" + this.rightKey);
  }
}
