MtasCQLParserWordCondition.java

package mtas.parser.cql.util;

import java.util.ArrayList;
import java.util.List;

import mtas.search.spans.MtasSpanAndQuery;
import mtas.search.spans.MtasSpanNotQuery;
import mtas.search.spans.MtasSpanOrQuery;
import mtas.search.spans.util.MtasSpanQuery;

/**
 * The Class MtasCQLParserWordCondition.
 */
public class MtasCQLParserWordCondition {

  /** The Constant TYPE_AND. */
  public static final String TYPE_AND = "and";

  /** The Constant TYPE_OR. */
  public static final String TYPE_OR = "or";

  /** The positive query list. */
  private List<MtasSpanQuery> positiveQueryList;

  /** The negative query list. */
  private List<MtasSpanQuery> negativeQueryList;

  /** The condition list. */
  private List<MtasCQLParserWordCondition> conditionList;

  /** The simplified. */
  private boolean simplified;

  /** The not. */
  private boolean not;

  /** The type. */
  private String type;

  /** The field. */
  private String field;

  /**
   * Instantiates a new mtas CQL parser word condition.
   *
   * @param field the field
   * @param type the type
   */
  public MtasCQLParserWordCondition(String field, String type) {
    this.field = field;
    this.type = type;
    not = false;
    simplified = true;
    positiveQueryList = new ArrayList<MtasSpanQuery>();
    negativeQueryList = new ArrayList<MtasSpanQuery>();
    conditionList = new ArrayList<MtasCQLParserWordCondition>();
  }

  /**
   * Type.
   *
   * @return the string
   */
  public String type() {
    return type;
  }

  /**
   * Field.
   *
   * @return the string
   */
  public String field() {
    return field;
  }

  /**
   * Swap not.
   */
  public void swapNot() {
    not = not ? false : true;
    simplified = false;
  }

  /**
   * Not.
   *
   * @return true, if successful
   */
  public boolean not() {
    return not;
  }

  /**
   * Adds the positive query.
   *
   * @param q the q
   */
  public void addPositiveQuery(MtasSpanQuery q) {
    positiveQueryList.add(q);
  }

  /**
   * Adds the negative query.
   *
   * @param q the q
   */
  public void addNegativeQuery(MtasSpanQuery q) {
    negativeQueryList.add(q);
  }

  /**
   * Gets the positive query.
   *
   * @return the positive query
   */
  public List<MtasSpanQuery> getPositiveQuery() {
    return positiveQueryList;
  }

  /**
   * Gets the positive query.
   *
   * @param index the index
   * @return the positive query
   */
  public MtasSpanQuery getPositiveQuery(int index) {
    if ((index >= 0) && (index < positiveQueryList.size())) {
      return positiveQueryList.get(index);
    } else {
      return null;
    }
  }

  /**
   * Gets the negative query.
   *
   * @return the negative query
   */
  public List<MtasSpanQuery> getNegativeQuery() {
    return negativeQueryList;
  }

  /**
   * Gets the negative query.
   *
   * @param index the index
   * @return the negative query
   */
  public MtasSpanQuery getNegativeQuery(int index) {
    if ((index >= 0) && (index < negativeQueryList.size())) {
      return negativeQueryList.get(index);
    } else {
      return null;
    }
  }

  /**
   * Adds the condition.
   *
   * @param c the c
   */
  public void addCondition(MtasCQLParserWordCondition c) {
    conditionList.add(c);
    simplified = false;
  }

  /**
   * Checks if is single.
   *
   * @return true, if is single
   */
  public boolean isSingle() {
    // assume simplified
    if ((positiveQueryList.size() == 1) && (negativeQueryList.size() == 0)) {
      return true;
    } else if ((positiveQueryList.size() == 0)
        && (negativeQueryList.size() == 1)) {
      return true;
    }
    return false;
  }

  /**
   * Checks if is simple positive.
   *
   * @return true, if is simple positive
   */
  public boolean isSimplePositive() {
    // assume simplified
    if ((positiveQueryList.size() > 0) && (negativeQueryList.size() == 0)) {
      return true;
    }
    return false;
  }

  /**
   * Checks if is simple negative.
   *
   * @return true, if is simple negative
   */
  public boolean isSimpleNegative() {
    // assume simplified
    if ((negativeQueryList.size() > 0) && (positiveQueryList.size() == 0)) {
      return true;
    }
    return false;
  }

  /**
   * Checks if is empty.
   *
   * @return true, if is empty
   */
  public boolean isEmpty() {
    if ((positiveQueryList.size() == 0) && (negativeQueryList.size() == 0)
        && (conditionList.size() == 0)) {
      return true;
    }
    return false;
  }

  /**
   * Swap type.
   */
  public void swapType() {
    if (type.equals(TYPE_AND)) {
      type = TYPE_OR;
    } else if (type.equals(TYPE_OR)) {
      type = TYPE_AND;
    } else {
      throw new Error("unknown type");
    }
    swapNot();
    List<MtasSpanQuery> queryList = positiveQueryList;
    positiveQueryList = negativeQueryList;
    negativeQueryList = queryList;
    for (MtasCQLParserWordCondition c : conditionList) {
      c.swapNot();
    }
    simplified = false;
  }

  /**
   * Simplified.
   *
   * @return the boolean
   */
  public Boolean simplified() {
    return simplified;
  }

  /**
   * Simplify.
   */
  public void simplify() {
    if (!simplified) {
      if (conditionList.size() > 0) {
        for (MtasCQLParserWordCondition c : conditionList) {
          c.simplify();
          // A & B & ( C & !D )
          if (c.type().equals(type) && !c.not()) {
            positiveQueryList.addAll(c.positiveQueryList);
            negativeQueryList.addAll(c.negativeQueryList);
            // A & B & !( C | !D )
          } else if (!c.type().equals(type) && c.not()) {
            positiveQueryList.addAll(c.negativeQueryList);
            negativeQueryList.addAll(c.positiveQueryList);
            // A & B & ( C )
          } else if (c.isSingle() && !c.not()) {
            positiveQueryList.addAll(c.positiveQueryList);
            negativeQueryList.addAll(c.negativeQueryList);
            // A & B & !( C )
          } else if (c.isSingle() && c.not()) {
            positiveQueryList.addAll(c.negativeQueryList);
            negativeQueryList.addAll(c.positiveQueryList);
          } else if (c.isSimplePositive()) {
            // A | B | ( C & D )
            if (c.type().equals(TYPE_AND)) {
              MtasSpanQuery q = new MtasSpanAndQuery(c.positiveQueryList
                  .toArray(new MtasSpanQuery[c.positiveQueryList.size()]));
              if (c.not()) {
                negativeQueryList.add(q);
              } else {
                positiveQueryList.add(q);
              }
              // A & B & ( C | D )
            } else {
              MtasSpanQuery q = new MtasSpanOrQuery(c.positiveQueryList
                  .toArray(new MtasSpanQuery[c.positiveQueryList.size()]));
              if (c.not()) {
                negativeQueryList.add(q);
              } else {
                positiveQueryList.add(q);
              }
            }
          } else if (c.isSimpleNegative()) {
            // A | B | ( !C | !D )
            if (c.type().equals(TYPE_OR)) {
              MtasSpanQuery q = new MtasSpanAndQuery(c.negativeQueryList
                  .toArray(new MtasSpanQuery[c.negativeQueryList.size()]));
              if (c.not()) {
                positiveQueryList.add(q);
              } else {
                negativeQueryList.add(q);
              }
              // A | B | ( !C & !D )
            } else {
              MtasSpanQuery q = new MtasSpanOrQuery(c.negativeQueryList
                  .toArray(new MtasSpanQuery[c.negativeQueryList.size()]));
              if (c.not()) {
                positiveQueryList.add(q);
              } else {
                negativeQueryList.add(q);
              }
            }
          } else {
            // swap if necessary
            if (this.isSimplePositive() && c.not()) {
              c.swapType();
            } else if (this.isSimpleNegative() && !c.not()) {
              c.swapType();
            }
            // A | B | ( C & !D )
            if (c.type().equals(TYPE_AND)) {
              MtasSpanQuery positiveQuery = new MtasSpanAndQuery(
                  c.positiveQueryList
                      .toArray(new MtasSpanQuery[c.positiveQueryList.size()]));
              MtasSpanQuery negativeQuery = new MtasSpanAndQuery(
                  c.negativeQueryList
                      .toArray(new MtasSpanQuery[c.negativeQueryList.size()]));
              MtasSpanQuery q = new MtasSpanNotQuery(positiveQuery,
                  negativeQuery);
              if (c.not()) {
                negativeQueryList.add(q);
              } else {
                positiveQueryList.add(q);
              }
              // A & B & ( C | !D )
            } else {
              MtasSpanQuery positiveQuery = new MtasSpanOrQuery(
                  c.positiveQueryList
                      .toArray(new MtasSpanQuery[c.positiveQueryList.size()]));
              MtasSpanQuery negativeQuery = new MtasSpanOrQuery(
                  c.negativeQueryList
                      .toArray(new MtasSpanQuery[c.negativeQueryList.size()]));
              MtasSpanQuery q = new MtasSpanNotQuery(positiveQuery,
                  negativeQuery);
              if (c.not()) {
                negativeQueryList.add(q);
              } else {
                positiveQueryList.add(q);
              }
            }
          }
        }
        conditionList.clear();
      }
      if (isSimpleNegative()) {
        swapType();
      }
      simplified = true;
    }
  }

  /*
   * (non-Javadoc)
   * 
   * @see java.lang.Object#toString()
   */
  @Override
  public String toString() {
    return toString("", "");
  }

  /**
   * To string.
   *
   * @param firstIndent the first indent
   * @param indent the indent
   * @return the string
   */
  public String toString(String firstIndent, String indent) {
    StringBuilder text = new StringBuilder();
    if (isEmpty()) {
      text.append(firstIndent + "Type: any word");
      text.append(not ? " (not)\n" : "\n");
    } else {
      text.append(firstIndent + "Type: " + type);
      text.append(not ? " (not)\n" : "\n");
      if (positiveQueryList.size() > 0) {
        for (MtasSpanQuery q : positiveQueryList) {
          text.append(
              indent + "List Positive Subqueries: " + q.toString(field) + "\n");
        }
      }
      if (negativeQueryList.size() > 0) {
        for (MtasSpanQuery q : negativeQueryList) {
          text.append(
              indent + "List Negative Queries: " + q.toString(field) + "\n");
        }
      }
      if (conditionList.size() > 0) {
        text.append(indent + "List Conditions\n");
        for (MtasCQLParserWordCondition c : conditionList) {
          text.append(c.toString(indent + "- ", indent + "  ") + "\n");
        }
      }
    }
    return text.toString();
  }

  /*
   * (non-Javadoc)
   * 
   * @see java.lang.Object#equals(java.lang.Object)
   */
  @Override
  public boolean equals(Object object) {
    if (object == null) {
      return false;
    } else if (object instanceof MtasCQLParserWordCondition) {
      MtasCQLParserWordCondition condition = (MtasCQLParserWordCondition) object;
      // basic checks
      if (!field.equals(condition.field) || not ^ condition.not
          || !type.equals(condition.type) || isSingle() ^ condition.isSingle()
          || isSimplePositive() ^ condition.isSimplePositive()
          || isSimpleNegative() ^ condition.isSimpleNegative()
          || isEmpty() ^ condition.isEmpty()) {
        return false;
      } else if (isEmpty()) {
        return true;
      } else {
        if (!positiveQueryList.equals(condition.positiveQueryList)) {
          return false;
        } else {
          for (int i = 0; i < positiveQueryList.size(); i++) {
            if (positiveQueryList.get(i) instanceof MtasCQLParserWordQuery) {
              if (!(condition.positiveQueryList
                  .get(i) instanceof MtasCQLParserWordQuery)) {
                return false;
              } else if (!((MtasCQLParserWordQuery) positiveQueryList.get(i))
                  .equals(condition.positiveQueryList.get(i))) {
                return false;
              }
            }
          }
        }
        if (!negativeQueryList.equals(condition.negativeQueryList)) {
          return false;
        } else {
          for (int i = 0; i < negativeQueryList.size(); i++) {
            if (negativeQueryList.get(i) instanceof MtasCQLParserWordQuery) {
              if (!(condition.negativeQueryList
                  .get(i) instanceof MtasCQLParserWordQuery)) {
                return false;
              } else if (!((MtasCQLParserWordQuery) negativeQueryList.get(i))
                  .equals(condition.negativeQueryList.get(i))) {
                return false;
              }
            }
          }
        }
        return true;
      }
    } else {
      return false;
    }
  }

  /*
   * (non-Javadoc)
   * 
   * @see java.lang.Object#hashCode()
   */
  @Override
  public int hashCode() {
    int h = this.getClass().getSimpleName().hashCode();
    h = (h * 3) ^ field.hashCode();
    h = (h * 5) ^ type.hashCode();
    h += (h * 7) ^ (not ? 3 : 5);
    h += (h * 11) ^ (simplified ? 7 : 13);
    h = (h * 17) ^ conditionList.hashCode();
    h = (h * 19) ^ positiveQueryList.hashCode();
    h = (h * 23) ^ negativeQueryList.hashCode();
    return h;
  }

}