// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.prelude.query;

import com.yahoo.protect.Validator;

import java.util.Collection;

/**
 * An Item where each child is an <i>alternative</i> which can be matched.
 * Produces the same recall as Or, but differs in that the relevance of a match
 * does not increase if more than one children is matched: With Equiv, matching one child perfectly is a perfect match.
 * <p>
 * This can only have Word, Int or Phrase children.
 *
 * @author havardpe
 */
public class EquivItem extends CompositeTaggableItem {

    public ItemType getItemType() {
        return ItemType.EQUIV;
    }

    public String getName() {
        return "EQUIV";
    }

    @Override
    protected void adding(Item item) {
        super.adding(item);
        Validator.ensure("Could not add an item of type " + item.getItemType() + 
                         ": Equiv can only have word/int/phrase as children",
                         item.getItemType() == ItemType.WORD ||
                         item.getItemType() == ItemType.EXACT ||
                         item.getItemType() == ItemType.INT ||
                         item.getItemType() == ItemType.PHRASE);
    }

    /** make an EQUIV item with no children */
    public EquivItem() {}

    /**
     * create an EQUIV with the given item as child.
     * The new EQUIV will take connectivity,
     * significance and weight from the given item.
     *
     * @param item Will be modified and added as a child.
     **/
    public EquivItem(Item item) {
        addItem(item);

        // steal other item's connectivity:
        if (item.connectedItem != null) {
            setConnectivity(item.connectedItem, item.connectivity);
            item.connectedItem = null;
            item.connectivity = 0.0;
        }
        TaggableItem back = (TaggableItem)item.connectedBacklink;
        if (back != null) {
            back.setConnectivity(this, back.getConnectivity());
            item.connectedBacklink = null;
        }

        // steal other item's significance:
        if (item.explicitSignificance) {
            setSignificance(item.significance);
        }

        // steal other item's weight:
        setWeight(item.getWeight());

        // we have now stolen all of the other item's unique id needs:
        item.setHasUniqueID(false);
    }

    /**
     * create an EQUIV with the given item and a set
     * of alternate words as children.
     * The new EQUIV will take connectivity,
     * significance and weight from the given item.
     *
     * @param item Will be modified and added as a child.
     * @param words Set of words to create WordItems from.
     **/
    public EquivItem(Item item, Collection<String> words) {
        this(item);
        String idx = ((IndexedItem)item).getIndexName();
        for (String word : words) {
            WordItem witem = new WordItem(word, idx);
            addItem(witem);
        }
    }
}

@@ -526,16 +526,41 @@
 ve Word,
+ WordAlternatives, Exact,
  Int or 
@@ -663,656 +663,16 @@
  %7B%0A%0A
-    public ItemType getItemType() %7B%0A        return ItemType.EQUIV;%0A    %7D%0A%0A    public String getName() %7B%0A        return %22EQUIV%22;%0A    %7D%0A%0A    @Override%0A    protected void adding(Item item) %7B%0A        super.adding(item);%0A        Validator.ensure(%22Could not add an item of type %22 + item.getItemType() + %0A                         %22: Equiv can only have word/int/phrase as children%22,%0A                         item.getItemType() == ItemType.WORD %7C%7C%0A                         item.getItemType() == ItemType.EXACT %7C%7C%0A                         item.getItemType() == ItemType.INT %7C%7C%0A                         item.getItemType() == ItemType.PHRASE);%0A    %7D%0A%0A
     /** 
 make
@@ -671,12 +671,13 @@
 /** 
-m
+M
 ake
+s
  an 
@@ -741,38 +741,39 @@
 %0A    /**%0A     * 
-c
+C
 reate
+s
  an EQUIV with t
@@ -795,23 +795,17 @@
 s child.
-%0A
  
-    *
  The new
@@ -905,33 +905,33 @@
   * @param item 
-W
+w
 ill be modified 
@@ -950,24 +950,22 @@
  a child
-.
 %0A     
-*
 */%0A    p
@@ -1818,22 +1818,23 @@
 %0A     * 
-c
+C
 reate
+s
  an EQUI
@@ -1864,23 +1864,16 @@
 nd a set
-%0A     *
  of alte
@@ -1933,39 +1933,32 @@
 ke connectivity,
-%0A     *
  significance an
@@ -2013,17 +2013,17 @@
 am item 
-W
+w
 ill be m
@@ -2050,17 +2050,16 @@
  a child
-.
 %0A     * 
@@ -2071,17 +2071,17 @@
 m words 
-S
+s
 et of wo
@@ -2108,24 +2108,22 @@
 ems from
-.
 %0A     
-*
 */%0A    p
@@ -2388,10 +2388,785 @@
 %7D%0A    %7D%0A
+%0A    @Override%0A    public ItemType getItemType() %7B%0A        return ItemType.EQUIV;%0A    %7D%0A%0A    @Override%0A    public String getName() %7B%0A        return %22EQUIV%22;%0A    %7D%0A%0A    @Override%0A    protected void adding(Item item) %7B%0A        super.adding(item);%0A        Validator.ensure(%22Could not add an item of type %22 + item.getItemType() +%0A                         %22: Equiv can only have word, wordAlternatives, int, exact, or phrase as children%22,%0A                         item.getItemType() == ItemType.WORD %7C%7C%0A                         item.getItemType() == ItemType.WORD_ALTERNATIVES %7C%7C%0A                         item.getItemType() == ItemType.INT %7C%7C%0A                         item.getItemType() == ItemType.EXACT %7C%7C%0A                         item.getItemType() == ItemType.PHRASE);%0A    %7D%0A%0A
 %7D%0A

Allow word alternatives under Equiv