package org.opengroupware.jope.eocontrol;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.opengroupware.jope.foundation.NSKeyValueCodingAdditions;

/*
 * EOSQLQualifier
 * 
 * Used to represent raw SQL sections in a parsed EOQualifier.
 * 
 * Sample:
 *   <qualifier>login = %@ OR SQL[balance IN $balance1, $balance2]</qualifier> 
 */
public class EOSQLQualifier extends EOQualifier {
  
  protected Object[] parts;

  public EOSQLQualifier(Object... _parts) {
    this.parts = _parts;
  }
  public EOSQLQualifier(List<Object> _qs) {
    this(_qs.toArray(new Object[0]));
  }
  
  /* accessors */
  
  public Object[] parts() {
    return this.parts;
  }
  
  /* bindings */
  
  public void addBindingKeysToSet(Set<String> _keys) {
    if (this.parts == null)
      return;

    for (int i = 0; i < this.parts.length; i++) {
      if (this.parts[i] instanceof EOQualifierVariable)
        _keys.add(((EOQualifierVariable)this.parts[i]).key());
    }
  }
  
  public EOQualifier qualifierWithBindings(Object _vals, boolean _requiresAll) {
    if (this.parts == null || this.parts.length == 0)
      return this;
    
    boolean  didReplace = false;
    Object[] bound = new Object[this.parts.length];
    for (int i = 0; i < this.parts.length; i++) {
      if (!(this.parts[i] instanceof EOQualifierVariable))
        bound[i] = this.parts[i];
      
      EOQualifierVariable v = (EOQualifierVariable)this.parts[i];
      didReplace = true;
      
      /* bind */
      
      if (_vals != null) {
        if (_vals instanceof NSKeyValueCodingAdditions) {
          bound[i] =
            ((NSKeyValueCodingAdditions)_vals).valueForKeyPath(v.key());
        }
        else if (_vals instanceof Map) {
          bound[i] = ((Map)_vals).get(v.key());
        }
        else {
          bound[i] =
            NSKeyValueCodingAdditions.Utility.valueForKeyPath(_vals, v.key());
        }
      }
      
      /* check if the value was found */
      
      if (bound[i] == null) {
        if (_requiresAll)
          throw new EOQualifierBindingNotFoundException(v.key());
        return null;
      }
    }
    
    return (didReplace) ? new EOSQLQualifier(bound) : this;
  }
  
  /* string representation */

  public boolean appendStringRepresentation(StringBuffer _sb) {
    if (this.parts == null)
      return false;
    
    for (int i = 0; i < this.parts.length; i++) {
      Object o = this.parts[i];
      if (o instanceof EOQualifierVariable) {
        _sb.append("$");
        _sb.append(((EOQualifierVariable)o).key());
      }
      else
        _sb.append(o);
    }
    return true;
  }
  
  /* description */

  public void appendAttributesToDescription(StringBuffer _d) {
    super.appendAttributesToDescription(_d);
    _d.append(" parts=" + Arrays.asList(this.parts));
  }
}
