package com.bbn.kbp.events2014.validation;


import com.bbn.bue.common.symbols.Symbol;
import com.bbn.kbp.events2014.KBPRealis;
import com.bbn.kbp.events2014.Response;
import com.bbn.kbp.events2014.ResponseLinking;
import com.bbn.kbp.events2014.ResponseSet;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Multimap;

import java.util.List;

public class LinkingValidators {

  public static LinkingValidator validatorFromMap(final Multimap<Symbol, Symbol> linkableTypes) {
    return MapLinkingValidator.create(linkableTypes);
  }

  public static LinkingValidator alwaysValidValidator() {
    return AlwaysValid.create();
  }

  public static LinkingValidator banGeneric() {
    return BanGenericValidator.create();
  }

  public static LinkingValidator compose(LinkingValidator... validators) {
    return ValidatorComposer.create(ImmutableList.copyOf(validators));
  }
}

final class AlwaysValid implements LinkingValidator {

  private AlwaysValid() {

  }

  public static AlwaysValid create() {
    return new AlwaysValid();
  }

  @Override
  public boolean validate(final ResponseLinking linking) {
    return true;
  }

  @Override
  public boolean validToLink(final Response a, final Response b) {
    return true;
  }
}

final class ValidatorComposer implements LinkingValidator {

  final ImmutableList<LinkingValidator> validators;

  private ValidatorComposer(final List<LinkingValidator> validators) {
    this.validators = ImmutableList.copyOf(validators);
  }

  static ValidatorComposer create(final List<LinkingValidator> validators) {
    return new ValidatorComposer(validators);
  }

  @Override
  public boolean validate(final ResponseLinking linking) {
    for(final LinkingValidator v: validators) {
      if(!v.validate(linking)) {
        return false;
      }
    }
    return true;
  }

  @Override
  public boolean validToLink(final Response a, final Response b) {
    for(final LinkingValidator v: validators) {
      if(!v.validToLink(a, b)) {
        return false;
      }
    }
    return true;
  }
}

final class BanGenericValidator implements LinkingValidator {

  private BanGenericValidator() {

  }

  public static BanGenericValidator create() {
    return new BanGenericValidator();
  }

  @Override
  public boolean validate(final ResponseLinking linking) {
    for (final ResponseSet rs : linking.responseSets()) {
      for (final Response r : rs) {
        if (r.realis().equals(KBPRealis.Generic)) {
          return false;
        }
      }
    }
    return true;
  }

  @Override
  public boolean validToLink(final Response a, final Response b) {
    return !a.realis().equals(KBPRealis.Generic) && !b.realis().equals(KBPRealis.Generic);
  }
}

final class MapLinkingValidator implements LinkingValidator {

  private final ImmutableMultimap<Symbol, Symbol> linkableTypes;

  private MapLinkingValidator(final Multimap<Symbol, Symbol> linkableTypes) {
    this.linkableTypes = ImmutableMultimap.copyOf(linkableTypes);
  }

  public static MapLinkingValidator create(final Multimap<Symbol, Symbol> linkableTypes) {
    return new MapLinkingValidator(linkableTypes);
  }

  @Override
  public boolean validate(final ResponseLinking linking) {
    for (final ResponseSet rs : linking.responseSets()) {
      for (final Response r : rs) {
        for (final Response s : rs) {
          if (!validToLink(r, s)) {
            return false;
          }
        }
      }
    }
    return true;
  }

  @Override
  public boolean validToLink(final Response a, final Response b) {
    return linkableTypes.get(a.type()).contains(b.type()) && linkableTypes.get(b.type())
        .contains(a.type());
  }

}


@@ -692,24 +692,24 @@
 ysValid.
-create()
+INSTANCE
 ;%0A  %7D%0A%0A 
@@ -954,27 +954,20 @@
 %0A  %7D%0A%7D%0A%0A
-final class
+enum
  AlwaysV
@@ -1008,111 +1008,20 @@
 %0A%0A  
-private AlwaysValid() %7B%0A%0A  %7D%0A%0A  public static AlwaysValid create() %7B%0A    return new AlwaysValid()
+INSTANCE
 ;%0A  
-%7D%0A
 %0A  @
@@ -1657,32 +1657,33 @@
 nking) %7B%0A    for
+ 
 (final LinkingVa
@@ -1683,32 +1683,33 @@
 nkingValidator v
+ 
 : validators) %7B%0A
@@ -1708,32 +1708,33 @@
 tors) %7B%0A      if
+ 
 (!v.validate(lin
@@ -1886,16 +1886,17 @@
 %0A    for
+ 
 (final L
@@ -1912,16 +1912,17 @@
 idator v
+ 
 : valida
@@ -1937,16 +1937,17 @@
       if
+ 
 (!v.vali

switch to an enum pattern instance of static factory