// Copyright 2014-2015 Boundary, Inc.
//
// 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 com.boundary.sdk.event.syslog;

import java.io.IOException;
import java.util.Properties;
import org.apache.camel.Exchange;
import org.apache.camel.Message;
import org.apache.camel.Processor;
import org.apache.camel.component.syslog.SyslogMessage;
import org.apache.camel.component.syslog.SyslogSeverity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.boundary.sdk.event.RawEvent;
import com.boundary.sdk.event.Severity;
import com.boundary.sdk.event.Status;

/**
 * Responsible for translating a {@link SyslogMessage} to {@link RawEvent}.
 * 
 * @author davidg
 * 
 */
public class SyslogToEventProcessor implements Processor {

	private static Logger LOG = LoggerFactory.getLogger(SyslogToEventProcessor.class);
	
	// Flag to indicated if the event should be translated into a {@link RawEvent} or not
	private boolean convertToEvent;

	public SyslogToEventProcessor() {
		this(true);
	}
	public SyslogToEventProcessor(boolean convertToEvent) {
		this.convertToEvent = convertToEvent;
	}
	
	private void logSyslogMessage(SyslogMessage slm) {
		LOG.debug(slm.getTimestamp()
				+ "|" + slm.getFacility()
				+ "|" + slm.getSeverity()
				+ "|" + slm.getHostname()
				+ "|" + slm.getRemoteAddress()
				+ "|" + slm.getLogMessage());
	}

	@Override
	public void process(Exchange exchange) throws Exception {
		
		LOG.info("Converting SyslogMessage to {}",this.convertToEvent ? "RawEvent" : "SyslogMessageEvent");
		
		// Conditionally translate {@link SyslogMessage} to {@link RawEvent}
		if (this.convertToEvent) {
			LOG.debug("CONVERTING to RawEvent");
			Message message = exchange.getIn();
	
			// Extract SyslogMessage from the message body.
			SyslogMessage syslogMessage = (SyslogMessage) message.getBody(SyslogMessage.class);
			logSyslogMessage(syslogMessage);
	
			// Create new event to translate the syslog message to
			RawEvent event = new RawEvent();
	
			// Delegate to member method call to perform the translation
			syslogMessageToEvent(syslogMessage, event);
			
			LOG.trace("{} {}",event.getClass().getName(),event);
	
			// Set the message body to the RawEvent
			message.setBody(event, RawEvent.class);
		}
		else {
			Message message = exchange.getIn();
			SyslogMessage syslogMessage = message.getBody(SyslogMessage.class);
			SyslogMessageEvent syslogEvent = new SyslogMessageEvent(syslogMessage);
			LOG.trace("{} {}",syslogEvent.getClass().getName(),syslogEvent);
			message.setBody(syslogEvent);
		}
	}

	/**
	 * Converts a {@link SyslogMessage} to {@link RawEvent}
	 * 
	 * @param sm
	 * @param e
	 */
	private void syslogMessageToEvent(SyslogMessage sm, RawEvent e) {

		// Add facility
		e.getProperties().put("facility", sm.getFacility());
		e.addTag(sm.getFacility().toString());
		
		// Add the hostname
		e.getSource().setRef(sm.getHostname()).setType("host");
		e.getProperties().put("hostname", sm.getHostname());
		e.addTag(sm.getHostname());
		
		// Add the message
		e.setMessage(sm.getLogMessage());
		e.getProperties().put("message", sm.getLogMessage());
		
		// Add the remote address
		// e.getProperties().put("remote_address", sm.getRemoteAddress());
		// e.addTag(sm.getRemoteAddress());
		
		// Map the syslog severity to Boundary event severity
		Severity severity = getEventSeverity(sm.getSeverity());
		e.setSeverity(severity);
		
		// Set event status based on Severity
		Status status = getEventStatus(sm.getSeverity());
		e.setStatus(status);
		
		// Set the uniqueness of the event by hostname, facility, and message.
		// TBD: These fields need to be split out in a configuration file
		e.addFingerprintField("hostname");
		e.addFingerprintField("facility");
		e.addFingerprintField("message");
		
		// Set the time at which the Syslog record was created
		e.setCreatedAt(sm.getTimestamp().getTime());

		// Set Title
		e.setTitle("Syslog message from: " + sm.getHostname());
		
		// Set Sender
		e.getSender().setRef("Syslog");
		e.getSender().setType("Boundary Event SDK");
	}

	/**
	 * Set the Event from the severity in the Message
	 * 
	 * @param m
	 * @param e
	 */
	private Severity getEventSeverity(SyslogSeverity severity) {
		getProperties(severityMap,"syslog.severity.properties");
		String strSeverity = severityMap.getProperty(severity.toString());
		return Severity.valueOf(strSeverity);
	}
	
	/**
	 * 
	 * @param severity
	 * @return {@link Status}
	 */
	private Status getEventStatus(SyslogSeverity severity) {
		getProperties(statusMap,"syslog.status.properties");
		String strStatus = statusMap.getProperty(severity.toString());
		return Status.valueOf(strStatus);
	}


	private static Properties severityMap = new Properties();
	private static Properties statusMap = new Properties();

	public static void getProperties(Properties properties, String propertyFileName) {
		if (properties.isEmpty()) {
			try {
				properties.load(Thread.currentThread()
						.getContextClassLoader()
						.getResourceAsStream(propertyFileName));
			} catch (IOException e) {
				e.printStackTrace();
				LOG.error(e.getStackTrace().toString());
			}
		}
	}
	public boolean isConvertToEvent() {
		return this.convertToEvent;
	}
	public void setConvertToEvent(boolean convertToEvent) {
		this.convertToEvent = convertToEvent;
	}
}

@@ -1938,12 +1938,13 @@
 LOG.
-info
+debug
 (%22Co
@@ -2138,48 +2138,8 @@
 ) %7B%0A
-%09%09%09LOG.debug(%22CONVERTING to RawEvent%22);%0A
 %09%09%09M

Modify logging