/**
 * 
 */
package edu.brandeis.flow.core.operator.filter;

import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;

import org.json.JSONException;
import org.json.JSONObject;

import edu.brandeis.flow.core.operator.JSONOperator;

/**
 * @author Yahui
 * 
 * Filter: has two mood: Regex or numerical
 *
 */
public final class Filter extends JSONOperator {
	String exp;
	String key;
	String target;
	String mode;
	boolean drop;

	public Filter() {
		super();
		this.exp = "";
		this.key = "";
		this.target = "";
		this.mode = "";
	}
	
	public void setup(String key, String target, String mode, String exp, boolean drop){
		this.setKey(key);
		this.setMode(mode);
		this.setTarget(target);
		this.setExpression(exp);
		this.drop = drop;
		
	}
	
	@Override
	public void run() {
		if (isNumerical()) {
			numMode();
		}else {
			regexMode();
		}
	}
	
	public void regexMode(){ //accept only the "=" relational operator --> match
		JSONObject top;
		//Match patterns
		Pattern pattern = null;
		try {
            pattern = Pattern.compile(target);

            while (true) {
            	
    			if((top = read()) != null) {
    				//if no key is specified, then sends all json objects
        			if(key.equals("")) send(top);
        			//else, filter out all json object that matches the pattern
        			else{   
        				if(!top.has(key)) send(top);
        				else{
        					Matcher matcher = pattern.matcher(top.getString(key));
                            //if not match, send; else, drop
        					if(matcher.matches() && !drop) {
        						send(top);
        					}
        					else if(!matcher.matches() && drop) send(top);
                            //else System.out.println("FILTER:::" + top.toString());
        				}
                        
        			}
    			}

    		} 
        } catch (PatternSyntaxException exception) {
            System.err.println(exception.getDescription());
        } catch (JSONException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} 

	}
	
	public void numMode() {
		JSONObject top;
		while (true) {
			if ((top = read()) != null) {
				//if no key is specified, then sends all json objects
    			if(key.equals("")) send(top);
    			//else if term is not specified, filter out all json objects that contain the key specified
    			else if(target.equals("") && !top.has(key) && drop) send(top);
    			else if(target.equals("") && top.has(key) && !drop) send(top);
    			//if the term is specified
    			else {
    				try {
						int termInt = Integer.parseInt(top.getString(key));
						int targetInt = Integer.parseInt(target);
						if(drop){
							if(exp.equals("=") && targetInt != termInt) send(top); //send if not equal
							else if(exp.equals(">") && targetInt >= termInt) send(top); //drop if target < term
							else if(exp.equals("<") && targetInt <= termInt) send(top); //drop if target > term
						}else {
							if(exp.equals("=") && targetInt == termInt) send(top); //send if not equal
							else if(exp.equals(">") && targetInt < termInt) send(top); //drop if target < term
							else if(exp.equals("<") && targetInt > termInt) send(top); //drop if target > term
						}
						
					} catch (NumberFormatException | JSONException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
    				
    			}
			}
		}
	}
	
	public String getExpression(){
		return exp;
	}
	
	private void setExpression(String exp) {
		this.exp = exp;
	}

	public String getKey() {
		return key;
	}

	private void setKey(String key) {
		this.key = key;
	}

	public String getTarget() {
		return target;
	}

	private void setTarget(String target) {
		this.target = target;
	}
	
	public String getMode(){
		return mode;
	}
	
	private void setMode(String mode){
		this.mode = mode;
	}

	

	
	public boolean isRegex() {
		return mode.equalsIgnoreCase("regex");
	}
	
	public boolean isNumerical() {
		return mode.equalsIgnoreCase("numerical");
	}



}


@@ -855,18 +855,128 @@
 %0A%09%09%09
-numMode();
+try %7B%0A%09%09%09%09numMode();%0A%09%09%09%7D catch (JSONException e) %7B%0A%09%09%09%09// TODO Auto-generated catch block%0A%09%09%09%09e.printStackTrace();%0A%09%09%09%7D
 %0A%09%09%7D
@@ -1200,16 +1200,30 @@
 e(target
+.toLowerCase()
 );%0A%0A    
@@ -1485,24 +1485,102 @@
 %09%09%09else%7B   %0A
+        %09%09%09%09JSONObject tmpTop = new JSONObject(top.toString().toLowerCase());%0A
         %09%09%09%09
@@ -1584,16 +1584,19 @@
 %09%09%09if(!t
+mpT
 op.has(k
@@ -1597,16 +1597,30 @@
 .has(key
+.toLowerCase()
 )) send(
@@ -1691,16 +1691,19 @@
 atcher(t
+mpT
 op.getSt
@@ -1706,24 +1706,38 @@
 etString(key
+.toLowerCase()
 ));%0A        
@@ -2335,16 +2335,37 @@
 umMode()
+ throws JSONException
  %7B%0A%09%09JSO
@@ -2423,24 +2423,94 @@
  != null) %7B%0A
+%09%09%09%09JSONObject tmpTop = new JSONObject(top.toString().toLowerCase());%0A
 %09%09%09%09//if no 
@@ -2729,16 +2729,19 @@
 %22) && !t
+mpT
 op.has(k
@@ -2738,24 +2738,38 @@
 pTop.has(key
+.toLowerCase()
 ) && drop) s
@@ -2815,16 +2815,19 @@
 %22%22) && t
+mpT
 op.has(k
@@ -2828,16 +2828,30 @@
 .has(key
+.toLowerCase()
 ) && !dr
@@ -2965,16 +2965,19 @@
 rseInt(t
+mpT
 op.getSt
@@ -2984,16 +2984,30 @@
 ring(key
+.toLowerCase()
 ));%0A%09%09%09%09

not case sensitive