/*
 * Zed Attack Proxy (ZAP) and its related class files.
 * 
 * ZAP is an HTTP/HTTPS proxy for assessing web application security.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * you may not use this file except in compliance with the License. 
 * You may obtain a copy of the License at 
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0 
 *   
 * Unless required by applicable law or agreed to in writing, software 
 * distributed under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 * See the License for the specific language governing permissions and 
 * limitations under the License. 
 */
package org.zaproxy.zap.extension.websocket.brk;

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

import org.parosproxy.paros.Constant;
import org.zaproxy.zap.extension.brk.AbstractBreakPointMessage;
import org.zaproxy.zap.extension.httppanel.Message;
import org.zaproxy.zap.extension.websocket.WebSocketMessage.Direction;
import org.zaproxy.zap.extension.websocket.ui.WebSocketMessageDAO;

public class WebSocketBreakpointMessage extends AbstractBreakPointMessage {

    private static final String TYPE = "WebSocket";
    
    /**
     * Break on specified opcode or on all if null.
     */
	private String opcode;
	
	/**
	 * Break on specified channel id or on all channels if null.
	 */
	private Integer channelId;
	
	/**
	 * Break on specified pattern that has to match on the
	 * {@link WebSocketMessageDAO#payload} or arbitrary payload if null.
	 */
	private Pattern payloadPattern;

	/**
	 * Break on specified directions {@link Direction#INCOMING} or/and
	 * {@link Direction#OUTGOING} or on arbitrary directions if null.
	 */
	private Direction direction;

	public WebSocketBreakpointMessage(String opcode, Integer channelId, String payloadPattern, Direction direction) {
		setOpcode(opcode);
		setChannelId(channelId);
		setPayloadPattern(payloadPattern);
		setDirection(direction);
	}

	@Override
    public String getType() {
        return TYPE;
    }
	
	public String getOpcode() {
		return opcode;
	}

	public void setOpcode(String opcode) {
	    this.opcode = opcode;
	}

	public Integer getChannelId() {
		return channelId;
	}

	public void setChannelId(Integer channelId) {
		this.channelId = channelId;
	}

	public String getPayloadPattern() {
		if (payloadPattern != null) {
			return payloadPattern.pattern();
		}
		return null;
	}

	public void setPayloadPattern(String payloadPattern) {
		if (payloadPattern == null || payloadPattern.length() == 0) {
			this.payloadPattern = null;
		} else {
			this.payloadPattern = Pattern.compile(payloadPattern, Pattern.MULTILINE);
		}
	}

	public Direction getDirection() {
		return direction;
	}

	public void setDirection(Direction direction) {
		if (direction == null) {
			this.direction = null;
		} else {
			this.direction = direction;
		}
	}

	@Override
	public boolean match(Message aMessage) {
		boolean isMatch = false;
		
	    if (aMessage instanceof WebSocketMessageDAO) {			
	        WebSocketMessageDAO msg = (WebSocketMessageDAO)aMessage;
	        
	        if (opcode != null) {
		        if (msg.readableOpcode.equals(opcode)) {
		        	isMatch = true;
		        } else {
		        	return false;
		        }
	        }
	        
	        if (channelId != null) {
	        	if (msg.channelId == channelId) {
	        		isMatch = true;
	        	} else {
		        	return false;
		        }
	        }
	        
	        if (payloadPattern != null) {
	        	Matcher m = payloadPattern.matcher(msg.payload);
	        	if (m.find()) {
	        		// when m.matches() is used, the whole string has to match
	        		isMatch = true;
	        	} else {
		        	return false;
		        }
	        }
	        
	        if (direction != null) {
	        	if (direction == msg.direction) {
	        		isMatch = true;
	        	} else {
		        	return false;
		        }
	        }
	    }
	    
		return isMatch;
	}

    @Override
    public String getDisplayMessage() {
    	ResourceBundle msgs = Constant.messages;
    	String message = "";
    	
    	if (opcode != null) {
    		message += msgs.getString("websocket.brk.add.opcode") + " " + opcode + "; ";
        }
        
        if (channelId != null) {
    		message += msgs.getString("websocket.brk.add.channel") + " #" + channelId + "; ";
        }
        
        if (payloadPattern != null) {
    		message += msgs.getString("websocket.brk.add.pattern") + " " + payloadPattern.pattern() + "; ";
        }
        
        if (direction != null) {
    		message += msgs.getString("websocket.brk.add.direction") + " " + direction + "; ";
        }
        
        if (message.isEmpty()) {
        	return msgs.getString("websocket.brk.add.break_on_all");
        }
        
        return msgs.getString("websocket.brk.add.break_on_custom") + " " + message;
    }
}

@@ -3131,40 +3131,8 @@
  %7B%0D%0A
-%09%09boolean isMatch = false;%0D%0A%09%09%0D%0A
 %09   
@@ -3303,24 +3303,25 @@
         if (
+!
 msg.readable
@@ -3350,56 +3350,8 @@
  %7B%0D%0A
-%09%09        %09isMatch = true;%0D%0A%09%09        %7D else %7B%0D%0A
 %09%09  
@@ -3471,17 +3471,17 @@
 annelId 
-=
+!
 = channe
@@ -3492,56 +3492,8 @@
  %7B%0D%0A
-%09        %09%09isMatch = true;%0D%0A%09        %09%7D else %7B%0D%0A
 %09%09  
@@ -3664,16 +3664,17 @@
    %09if (
+!
 m.find()
@@ -3753,56 +3753,8 @@
 ch%0D%0A
-%09        %09%09isMatch = true;%0D%0A%09        %09%7D else %7B%0D%0A
 %09%09  
@@ -3870,17 +3870,17 @@
 rection 
-=
+!
 = msg.di
@@ -3887,24 +3887,25 @@
 rection) %7B%0D%0A
+%09
 %09        %09%09i
@@ -3906,26 +3906,24 @@
    %09
-%09isMatch = tru
+return fals
 e;%0D%0A
+%09
 %09   
@@ -3927,28 +3927,19 @@
         
-%09%7D else %7B
+%7D
 %0D%0A
-%09
 %09       
@@ -3939,33 +3939,19 @@
         
-%09return false;
+%7D
 %0D%0A
-%09
 %09       
@@ -3943,33 +3943,32 @@
     %7D%0D%0A%09        
-%7D
 %0D%0A%09        %7D%0D%0A%09 
@@ -3958,25 +3958,36 @@
  %0D%0A%09        
-%7D
+return true;
 %0D%0A%09    %7D%0D%0A%09 
@@ -4004,15 +4004,13 @@
 urn 
-isMatch
+false
 ;%0D%0A%09

break on every WebSocket message (if nothing is entered to 'Add custom breakpoint'-dialog)