// Copyright (c) Trend Micro Inc. 2004-2012, All Rights Reserved

package com.trendmicro.webserviceclient.samples;

import java.net.URL;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import java.text.SimpleDateFormat;

import com.trendmicro.webserviceclient.generated.*;
import com.trendmicro.webserviceclient.utils.ClientUtils;

/*
 * DpiEvents: This sample application is designed demonstrate how to correctly retrieve
 * Deep Packet Inspection (DPI) events from the Deep Security Manager WebService.
 */
public class DpiEvents extends ClientUtils {
	public static int arg_count = 6;
	public static String arg_usage =
		" <webservice url> <username> <password> <host id/name/all> <event [eq|gt|lt]/id or all> <last X hours>\n" +
		"This sample application can be used to retrieve DPI events from the last\n" +
        "specified number of hours, and/or by event ID, for a specified Computer by\n" +
        "ID or Name, or all Computers.\n";
	public static int arg_endpoint = 0;
	public static int arg_user = 1;
	public static int arg_pass = 2;
	public static int arg_host = 3;
	public static int arg_event = 4;
	public static int arg_hours = 5;

	public static String ARG_ALL = "all";

	public static String sid = null;

	SimpleDateFormat date_format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");

	public DpiEvents(String app_name, String[] args) throws Exception {
		super(app_name, arg_count, arg_usage, args);
	}

	public void doRetrieveEvents() throws Exception {
		String endpoint = this.getArg(arg_endpoint);
		String user = this.getArg(arg_user);
		String pass = this.getArg(arg_pass);
		String hostidentifier = this.getArg(arg_host);
		String eventidentifier = this.getArg(arg_event);
        String eventoperator = null;
        if (!eventidentifier.equals(ARG_ALL))
        {
        	Pattern pattern = Pattern.compile("^(gt|lt|eq)(\\d+)$");
        	Matcher eventMatch = pattern.matcher(eventidentifier);
            if (eventMatch.matches()) {
            	eventoperator = eventMatch.group(0);
                eventidentifier = eventMatch.group(1);
            } else {
                this.log("Error: Event identifier must either be \"all\" or include the event ID and operator in the format gt|lt|eq/id. For example, gt1050 or greater than event id 1050.");
                return;
            }
        }
		int lastXhours = Integer.parseInt(this.getArg(arg_hours));

		_ManagerService = _Service.getManager(new URL(endpoint));
		try {
            /*
             * It is recommended that during initalization or start up, a version test of the
             * Web Service API be performed to ensure that Web Service API client implementations
             * built against a mis-matched version of the Deep Security Manager Web Service end
             * point does not unexpectedly break the client application.
             */
            this.log("Manager Web Service API Version: " + _ManagerService.getApiVersion());

            /*
             * When making any manager service call, such as attempting to authenticate,
             * ensure the Exception is caught. The resulting Exception message will contain
             * an explaination of any failures.
             */
			this.log("Attempting to authenticate to Manager WebService...");
			sid = _ManagerService.authenticate(user, pass);
			this.log("Authentication successful.");
			this.log("Authentication session ID string recieved: " + sid);

			this.log("Event retrieval parameters:");

			/*
			 * When requiring a TimeFilterTransport for any event retrieval calls, the
			 * Type property must be always set with an EnumTimeFilterType. If a custom
			 * time range (EnumTimeFilterType.CUSTOM_RANGE) is desired, the range "from"
			 * and "to" dates must also be specified.
			 */
			TimeFilterTransport timeFilter = new TimeFilterTransport();
			timeFilter.setType(EnumTimeFilterType.CUSTOM_RANGE);
			timeFilter.setRangeFrom(this.getRangeDate((0 - lastXhours)));
			timeFilter.setRangeTo(this.getRangeDate());

			this.log(" - View events from the past " + lastXhours + " hours.");
			this.log(" - Time filter range from: " + date_format.format(timeFilter.getRangeFrom().getTime()));
			this.log(" - Time filter range to: " + date_format.format(timeFilter.getRangeTo().getTime()));

			/*
			 * When requiring a HostFilterTransport for a service call, the Type property
			 * set with an EnumHostFilterType and the corresponding property containing
			 * the criteria value must be set.
			 *
			 * For example, to filter by a single Host ID:
			 *   hostFilter.setType(EnumHostFilterType.SPECIFIC_HOST);
			 *   hostFilter.setHostID(hostID);
			 *
			 * For example, to filter by a Security Profile ID:
			 *   hostFilter.setType(EnumHostFilterType.HOSTS_USING_SECURITY_PROFILE);
			 *   hostFilter.setSecurityProfileID(securityProfileID);
			 *
			 * For example, to filter for all Hosts:
			 *   hostFilter.setType(EnumHostFilterType.ALL_HOSTS);
			 */
			HostFilterTransport hostFilter = new HostFilterTransport();
			if(hostidentifier.equals(ARG_ALL)) {
				hostFilter.setType(EnumHostFilterType.ALL_HOSTS);
				this.log(" - Filtering for host: ALL");
			} else {
				HostTransport host;
				if(this.testForId(hostidentifier)) {
					this.log(" - Retrieving Host by ID: " + hostidentifier);
					host = _ManagerService.hostRetrieve(Integer.parseInt(hostidentifier), sid);
				} else {
					this.log(" - Retrieving Host by Name: " + hostidentifier);
					host = _ManagerService.hostRetrieveByName(hostidentifier, sid);
				}
				if(host == null) {
					throw new Exception("Host could not be found.");
				}
				hostFilter.setType(EnumHostFilterType.SPECIFIC_HOST);
				hostFilter.setHostID(host.getID());
				this.log(" - Filtering for host: " + host.getName() + "(ID: " + host.getID() + ")");
			}

			/*
             * When requiring a IDFilterTransport for a service call, the @operator property
             * is set with an EnumOperator and the id property must be set. IDFilterTransport
             * is used to filter events where the @operator is greater than, less than or equal
             * to the event ID. To not filter by event ID, specify an event ID of 0 and an
             * operator of EnumOperator.GREATER_THAN. This is allow for all events to be subject
             * to any other filtering, such as computer or time filters.
             */
            IDFilterTransport eventIdFilter = new IDFilterTransport();
            if (eventidentifier.equals(ARG_ALL))
            {
                eventIdFilter.setOperator(EnumOperator.GREATER_THAN);
                eventIdFilter.setId(0);
                this.log(" - Filtering for events: ALL");
            }
            else
            {
            	eventIdFilter.setOperator(EnumOperator.GREATER_THAN); // Default
                if(eventoperator.equals("gt")) {
                	eventIdFilter.setOperator(EnumOperator.GREATER_THAN);
                }
                if(eventoperator.equals("lt")) {
                	eventIdFilter.setOperator(EnumOperator.LESS_THAN);
                }
                if(eventoperator.equals("eq")) {
                	eventIdFilter.setOperator(EnumOperator.EQUAL);
                }
                eventIdFilter.setId(Integer.valueOf(eventidentifier));
                this.log(" - Filtering events " + eventIdFilter.getOperator().getValue() + " event ID: " + eventidentifier);
            }
            this.log("");

			/*
			 * Respective event Transport classes, such as a DPIEventListTransport, will
			 * contain all the same captured properties of the event which are viewable in
			 * the Deep Security Manager.
			 *
			 * To gather more information on the DPI Rule which
			 * triggered a given event, the DPIRuleID property can be used to with the
			 * manager.DPIRuleRetrieve(id, sid) service call.
			 */
			this.log("Retrieving events...");
			DPIEventListTransport eventList = _ManagerService.DPIEventRetrieve(timeFilter, hostFilter, eventIdFilter, sid);
			DPIEventTransport[] events = eventList.getDPIEvents();
			String eventPrintable;
			for(DPIEventTransport event : events) {
				eventPrintable =
					date_format.format(event.getStartTime().getTime()) + "|" +
					event.getDPIEventID() + "|" + // Event ID
					event.getHostName() + "(ID:" + event.getHostID() + ")|" +
					event.getReason() + "|" +
					event.getDPIRuleID() + "|" +
					event.getAction() + "|" +
					event.getRank() + "|" +
					event.getDirection() + "|" +
					event.getIface() + "|" +
					event.getProtocol() + "|" +
					event.getFlags() + "|" +
					event.getSourceIP() + "|" +
					event.getSourceMAC() + "|" +
					event.getSourcePort() + "|" +
					event.getDestinationIP() + "|" +
					event.getDestinationMAC() + "|" +
					event.getDestinationPort() + "|" +
					event.getPacketSize();
				this.log(eventPrintable);
			}
		} catch(ManagerException em) {
			/*
			 * Any manager service call failures will be explained in the
			 * ManagerException fault string property.
			 */
			this.log(em.getFaultString());
		} catch(Exception e) {
			this.log("Error: " + e.getMessage());
		} finally {
			/*
			 * Always attempt to end the manager service session.
			 */
			if (sid != null)
			{
				this.log("");
				this.log("Ending session...");
				_ManagerService.endSession(sid);
				this.log("End session successful.");
			}
		}
	}

   /**
    * The main entry point.
    */
	public static void main(String[] args) throws Exception {
		DpiEvents client = new DpiEvents("DpiEvents", args);
		if(!client.validateArgs()) {
			client.printUsage("Invalid number of arguments found.");
			return;
		}
		client.doRetrieveEvents();
	}
}
