/*
 *    Copyright 2016 West Coast Informatics, LLC
 */
package com.wci.tt.services.filters;

import java.io.File;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import com.wci.tt.helpers.TypeKeyValue;
import com.wci.tt.jpa.services.CoordinatorServiceJpa;
import com.wci.tt.services.CoordinatorService;
import com.wci.umls.server.helpers.ConfigUtility;

/**
 * Abstract {@link Filter} to be used as a superclass.
 */
public abstract class AbstractFilter {

  /** The config map. */
  private Map<String, Map<String, String>> configMap = new HashMap<>();

  /** Filtered results. */
  private Map<String, List<String>> filteredMap = new HashMap<>();

  /** The writer map. */
  private Map<String, PrintWriter> writerMap = new HashMap<>();

  /**
   * Cache type.
   *
   * @param type the type
   * @throws Exception the exception
   */
  protected void cacheType(String type) throws Exception {
    final CoordinatorService service = new CoordinatorServiceJpa();
    try {
      configMap.put(type, new HashMap<String, String>());
      final Map<String, String> keyValueMap = configMap.get(type);
      for (final TypeKeyValue tkv : service
          .findTypeKeyValuesForQuery("type:" + type)) {
        keyValueMap.put(tkv.getKey(), tkv.getValue());
      }

    } catch (Exception e) {
      throw e;
    } finally {
      service.close();
    }
  }

  /**
   * Returns the value.
   *
   * @param type the type
   * @param key the key
   * @return the value
   */
  protected String getValue(String type, String key) {
    return configMap.get(type).get(key);
  }

  /**
   * Exists.
   *
   * @param type the type
   * @param key the key
   * @return true, if successful
   */
  protected boolean exists(String type, String key) {
    return configMap.get(type).containsKey(key);
  }

  /**
   * Adds the filtered result.
   *
   * @param category the category
   * @param inputStr the input str
   * @throws Exception the exception
   */
  protected void addFilteredResult(String category, String inputStr)
    throws Exception {
    if (!filteredMap.containsKey(category)) {
      filteredMap.put(category, new ArrayList<String>());
    }
    filteredMap.get(category).add(inputStr);

    // Write the result to a file if filters.directory.output is set
    // and analysis.mode is set
    final Properties prop = ConfigUtility.getConfigProperties();
    if (ConfigUtility.isAnalysisMode()
        && prop.containsKey("filter.directory.output")) {

      if (!writerMap.containsKey(category)) {
        final File file =
            new File(prop.getProperty("filter.directory.output").toString()
                + "/" + "filter-" + category + ".txt");
        if (file.exists()) {
          file.delete();
        }
        final PrintWriter out = new PrintWriter(new FileWriter(file));
        writerMap.put(category, out);
      }

      writerMap.get(category).println(inputStr);
      writerMap.get(category).flush();
    }

  }

  /**
   * Returns the filtered results.
   *
   * @param type the type
   * @return the filtered results
   */
  protected List<String> getFilteredResults(String type) {
    return filteredMap.get(type);
  }

  /**
   * Checks whether the input string is filtered for the specified type. If so,
   * adds a filtered result and returns true. Otherwise it returns false.
   *
   * @param type the type
   * @param inputStr the input str
   * @return true, if successful
   * @throws Exception
   */
  protected boolean checkFilterType(String type, String inputStr)
    throws Exception {
    if (configMap.get(type).containsKey(inputStr)) {
      addFilteredResult(configMap.get(type).get(inputStr), inputStr);
      return true;
    }
    return false;
  }

  /**
   * Close.
   *
   * @throws Exception the exception
   */
  public void close() throws Exception {
    for (final PrintWriter out : writerMap.values()) {
      out.close();
    }
  }

}

@@ -3440,24 +3440,155 @@
 urns false.%0A
+   * %0A   * Filters on: 1) Exact matches (to handle blacklists) 2) Word-based%0A   * instances(to handle specified keywords or types)%0A
    *%0A   * @p
@@ -3688,32 +3688,46 @@
 throws Exception
+ the exception
 %0A   */%0A  protect
@@ -3798,32 +3798,69 @@
 ows Exception %7B%0A
+    boolean filterRequired = false;%0A%0A
     if (configMa
@@ -3891,20 +3891,420 @@
 inputStr
-)) %7B
+.toLowerCase())) %7B%0A      // Exact match found%0A      filterRequired = true;%0A    %7D else %7B%0A      // Look for keyword matches%0A      for (String item : configMap.get(type).keySet()) %7B%0A        if (inputStr.toLowerCase().contains(item.toLowerCase())) %7B%0A          filterRequired = true;%0A          break;%0A        %7D%0A      %7D%0A    %7D%0A%0A    if (filterRequired) %7B%0A      // Must be filtered, add to set of filtered results
 %0A      a
@@ -4364,24 +4364,29 @@
 nputStr);%0A  
+  %7D%0A%0A
     return t
@@ -4388,36 +4388,22 @@
 urn 
-true;%0A    %7D%0A    return false
+filterRequired
 ;%0A  

Add ability for preChecks to filter on partial matches (ie inputs with the word VITAMIN)