package cn.com.lemon.base.util;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.Charsets;
import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnel;
import com.google.common.hash.PrimitiveSink;
import com.hankcs.hanlp.seg.Segment;
import com.hankcs.hanlp.seg.Dijkstra.DijkstraSegment;
import com.hankcs.hanlp.seg.common.Term;

import static cn.com.lemon.base.Preasserts.checkArgument;

/**
 * Sensitive word filter based on bloem algorithm
 * 
 * @author shaobo shih
 * @version 1.0
 */
public class BloomFilters {
	private final static Logger LOG = LoggerFactory.getLogger(BloomFilters.class.getName());
	private BloomFilter<String> bloomFilter;
	private File file;
	private Segment segment;

	// initialize bloom filter
	private final BloomFilter<String> filter = BloomFilter.create(new Funnel<String>() {
		private static final long serialVersionUID = 1L;

		@Override
		public void funnel(String arg0, PrimitiveSink arg1) {
			arg1.putString(arg0, Charsets.UTF_8);
		}
	}, 1024 * 1024 * 32);

	// Bloom filter based on flunt style
	/**
	 * Instantiate the class
	 * 
	 * @return this
	 */
	public BloomFilters build() {
		return new BloomFilters();
	}

	/**
	 * Sensitive word file
	 * 
	 * @return this
	 */
	public BloomFilters file(File file) {
		checkArgument(file != null && !file.isFile());
		this.file = file;
		return this;
	}

	/**
	 * Bloom filter
	 * 
	 * @return this
	 */
	public BloomFilters filter() {
		InputStreamReader read = null;
		BufferedReader bufferedReader = null;
		try {
			read = new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8);
			bufferedReader = new BufferedReader(read);
			for (String txt = null; (txt = bufferedReader.readLine()) != null;) {
				filter.put(txt);
			}
			this.bloomFilter = filter;
		} catch (FileNotFoundException e) {
			LOG.error("The File " + file.getPath() + " not find!", e);
		} catch (IOException e) {
			LOG.error("The File I/O error occurs!", e);
		} finally {
			if (bufferedReader != null) {
				try {
					bufferedReader.close();
				} catch (IOException e) {
					LOG.error("BufferedReader close error occurs!", e);
				}
			}
			if (read != null) {
				try {
					read.close();
				} catch (IOException e) {
					LOG.error("InputStreamReader close error occurs!", e);
				}
			}
		}
		return this;
	}

	/**
	 * Chinese word splitter
	 * 
	 * @return this
	 */
	public BloomFilters segment(Segment segment) {
		if (segment != null) {
			this.segment = segment;
		} else {
			// Shortest path splitter
			this.segment = new DijkstraSegment().enableCustomDictionary(false).enablePlaceRecognize(true)
					.enableOrganizationRecognize(true);
		}
		return this;
	}

	/**
	 * Get the sensitive words of the input document
	 * 
	 * @param words
	 *            input content
	 * @return {@link List}
	 */
	public List<String> sensitive(String... words) {
		if (words == null)
			return null;
		List<String> result = new ArrayList<String>();
		for (String word : words) {
			List<Term> termList = this.segment.seg(word);
			for (Term term : termList) {
				if (bloomFilter.mightContain(term.word)) {
					result.add(term.word);
				}
			}
		}
		return result;
	}
}

@@ -269,21 +269,16 @@
 va.util.
-Array
 List;%0Aim
@@ -292,19 +292,44 @@
 va.util.
-Lis
+Set;%0Aimport java.util.TreeSe
 t;%0A%0Aimpo
@@ -685,83 +685,132 @@
 m;%0A%0A
-import static cn.com.lemon.base.Preasserts.checkArgument;%0A%0A/**%0A * S
+/**%0A * Sensitive word filter based on bloem algorithm%0A * %3Cp%3E%0A * %3Cblockquote%3E%0A * %0A * %3Cpre%3E%0A * File file = new File(%22s
 ensitive
  wor
@@ -809,45 +809,206 @@
 tive
- 
 word
- filter based on bloem algorithm
+s.txt%22);;%0A * String content = %22%E7%A4%BE%E4%BC%9A%E6%9C%89%E6%AD%A3%E6%B0%94%EF%BC%8C%E6%B0%91%E6%97%8F%E6%89%8D%E4%BC%9A%E7%94%9F%E7%94%9F%E4%B8%8D%E6%81%AF%EF%BC%8C%E5%9B%BD%E5%AE%B6%E6%89%8D%E4%BC%9A%E5%85%B4%E6%97%BA%E5%8F%91%E8%BE%BE%E3%80%82%22;%0A * Set%3CString%3E result = BloomFilters.build().file(file).filter().segment(null).sensitive(content);%0A * %3C/pre%3E%0A * %0A * %3C/blockquote%3E%0A * %3Cp%3E
 %0A * 
@@ -1657,32 +1657,39 @@
 is%0A%09 */%0A%09public 
+static 
 BloomFilters bui
@@ -1827,57 +1827,8 @@
 ) %7B%0A
-%09%09checkArgument(file != null && !file.isFile());%0A
 %09%09th
@@ -3321,19 +3321,18 @@
 %09public 
-Lis
+Se
 t%3CString
@@ -3401,19 +3401,18 @@
 null;%0A%09%09
-Lis
+Se
 t%3CString
@@ -3430,16 +3430,14 @@
 new 
-ArrayLis
+TreeSe
 t%3CSt
@@ -3552,24 +3552,74 @@
 termList) %7B%0A
+%09%09%09%09System.out.println(%22term.word=%22 + term.word);%0A
 %09%09%09%09if (bloo

add test BloomFilter case