/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\

File: octvc1_msg_event.c

Copyright (c) 2014 Octasic Inc. All rights reserved.

Description: Routines for vocallonet dissection

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.

Release: Octasic Application Development Framework OCTADF-01.00.01-B497 (2014/01/09)

$Octasic_Revision: $

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
 #include <config.h>
#include <epan/packet.h>
#include <epan/prefs.h>
#include <epan/expert.h>

#include "../include/module.h"
#include "../include/octvc1_common.h"
#include "../include/plugin_info.h"
#include "../../../include/oct_ws_macro.h"

#include <color.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <gmodule.h>

#include <octvc1_msg.h>
#include <octvc1_base.h>

#include <main/octvc1_main_evt.h>
#include <ctrl/octvc1_ctrl_api.h>



/* Define version if we are not building Wireshark statically */
/* Initialize the protocol and registered fields */
int proto_octvc1_event = -1;

extern int g_fIsRegistered;

/* Event packet data fields */
static int hf_octvc1_event_header_ulLength = -1;
static int hf_octvc1_event_header_ulEventId = -1;
static int hf_octvc1_event_header_ulUserEventId = -1;
static int hf_octvc1_event_header_ulEventId_Base = -1;
static int hf_octvc1_event_header_ulEventId_Type = -1;
static int hf_octvc1_event_header_ulEventId_Code = -1;

#define mWD_OCTVC1_EID_BASE(uint32)					((uint32) & 0x00ff0000)
#define mWD_OCTVC1_EID_2_UID(uint32)				(((uint32)& 0x000f0000)>>16)
#define mWD_OCTVC1_EID_CODE(uint32)					((uint32) & 0x0000ffff)


/* fields defining a subtree */
static gint ett_octvc1_event_header       	= -1;
static gint ett_octvc1_event_id	       		= -1;

/*************************************************************************
*
*  Code to actually dissect the Vocallo event packet header
*
**************************************************************************/
void dissect_octvc1_event(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
	unsigned int	packet_offset = 0;
	guint32			evt_length;
	guint32			event_id;
	guint32			event_id_base;
	guint32			event_id_code;
	guint32			user_event_id;
	proto_tree*		evt_tree = NULL;
	gint32			module_index = -1;
	const gchar*	pszValueStringEID=NULL;
	gint32			iRegistered = 1;

	if (check_col(pinfo->cinfo, COL_PROTOCOL))
		col_set_str(pinfo->cinfo, COL_PROTOCOL, "OCTVC1_EVT");

	/* parse the event header */
	evt_length = tvb_get_ntohl( tvb, packet_offset );
	packet_offset += sizeof(evt_length);
	event_id = tvb_get_ntohl( tvb, packet_offset );
	event_id_base = mWD_OCTVC1_EID_BASE(event_id);
	event_id_code = mWD_OCTVC1_EID_CODE(event_id);
	packet_offset += sizeof(event_id_code);
	user_event_id = tvb_get_ntohl( tvb, packet_offset );
	packet_offset += sizeof(user_event_id);

	/* Find Tbl Module Index */
	OCT_MATCH_STRVAL_IDX( mWD_OCTVC1_EID_2_UID(event_id_base), vals_OCTVC1_module_UID, &module_index );

	if ( check_col( pinfo->cinfo, COL_INFO) )
	{
		col_clear(pinfo->cinfo, COL_INFO);

		if( module_index < 0 )
		{
			col_add_fstr( pinfo->cinfo, COL_INFO,
				"%s, CID=0x%04X",
				val_to_str( mWD_OCTVC1_EID_2_UID(event_id_base), vals_OCTVC1_module_UID, "Unknown (%x)" ),
				event_id_code );
		}
		else
		{
			pszValueStringEID = val_to_str( event_id_code, aOCTVC1ModuleColInfo[module_index].apEvtIdValueString, cOCTVC1_UNKNOWN_STRING );

			// look for private
			if( strcmp( pszValueStringEID, cOCTVC1_PRIVATE_ID_STRING ) == 0 )
			{
				iRegistered = 0;
				// look if somebody register
				if( g_fIsRegistered )
				{
					pszValueStringEID = octvc1_chck_private( event_id_code, aOCTVC1ModuleColInfo[module_index].apPrivateEvtIdValueString, &iRegistered );
				}
				else
					pszValueStringEID = cOCTVC1_UNKNOWN_STRING;
			}

			col_add_fstr( pinfo->cinfo, COL_INFO,
					"%s_MSG_%s(0x%04X)",
					aOCTVC1ModuleColInfo[module_index].pszModuleName,
					pszValueStringEID,
					event_id_code );

		}
	}

	if (tree)
	{
		proto_item *ti;
		proto_item *tf = NULL;


		packet_offset = 0;

		/* Add the subtree for struct octvc1 evt */
		ti = proto_tree_add_item( tree, proto_octvc1_event, tvb, 0, -1, FALSE );
		evt_tree = proto_item_add_subtree( ti, ett_octvc1_event_header );

		proto_tree_add_uint( evt_tree, hf_octvc1_event_header_ulLength, tvb,
		    packet_offset, 4, evt_length );
		packet_offset += sizeof(evt_length);


		/* Validate the cmd */
		if( module_index < 0 )
		{
			proto_tree_add_uint(evt_tree, hf_octvc1_event_header_ulEventId, tvb, packet_offset, 4, event_id );
		}
		else
		{
			if( pszValueStringEID == NULL )
			{
				pszValueStringEID = val_to_str( event_id_code, aOCTVC1ModuleColInfo[module_index].apEvtIdValueString, cOCTVC1_UNKNOWN_STRING );

				// look for private
				if( strcmp( pszValueStringEID, cOCTVC1_PRIVATE_ID_STRING ) == 0 )
				{
					iRegistered = 0;

					// look if somebody register
					if( g_fIsRegistered )
					{
						pszValueStringEID = octvc1_chck_private( event_id_code, aOCTVC1ModuleColInfo[module_index].apPrivateEvtIdValueString, &iRegistered );
					}
					else
						pszValueStringEID = cOCTVC1_UNKNOWN_STRING;
				}
			}

			tf = proto_tree_add_uint_format(evt_tree, hf_octvc1_event_header_ulEventId, tvb,
					packet_offset, 4, event_id,
					"Event Id(0x%08X): cOCTVC1_%s_MSG_%s_EID",
					event_id,
					aOCTVC1ModuleColInfo[module_index].pszModuleName,
					pszValueStringEID );
		}

		if( tf )
		{
			proto_tree *field_tree;

			field_tree = proto_item_add_subtree(tf, ett_octvc1_event_id);

			proto_tree_add_uint( field_tree, hf_octvc1_event_header_ulEventId_Type, tvb,
				packet_offset+1, 1, event_id_base );

			proto_tree_add_uint( field_tree, hf_octvc1_event_header_ulEventId_Base, tvb,
				packet_offset+1, 1, event_id_base );

			proto_tree_add_uint_format_value(field_tree, hf_octvc1_event_header_ulEventId_Code, tvb,
					packet_offset+2, 2, event_id_code,
					"%s(0x%04X)",
					pszValueStringEID, event_id_code );
		}

		packet_offset += sizeof(event_id_code);

		proto_tree_add_uint( evt_tree, hf_octvc1_event_header_ulUserEventId, tvb,
		    packet_offset, 4, user_event_id );
		packet_offset += sizeof(user_event_id);
	}

	{
		int fDoData = 1;
		int reported_length = evt_length ? (evt_length - sizeof(tOCTVC1_EVENT_HEADER)) : 0;
		int available_length = tvb_length_remaining(tvb, packet_offset);
		tvbuff_t *tvbData;

		tvbData = tvb_new_subset(tvb, packet_offset, available_length, reported_length);

		if( ( module_index >= 0 ) && iRegistered )
		{
			/* Call the module dissector */
			fDoData = aOCTVC1ModuleColInfo[module_index].Dissector_fnc( cOCTVC1_MSG_TYPE_NOTIFICATION,
							event_id_base | event_id_code,
							tvbData, pinfo, evt_tree );
		}

		if( fDoData )
		{
			/* Dump the rest in raw format */
			call_dissector(data_handle, tvbData, pinfo, evt_tree);
		}
	}

//	return tvb_length(tvb);

}







/*************************************************************************
*
*  Code to register the protocol with Wireshark
*
**************************************************************************/
void proto_register_octvc1_event(void)
{
	static hf_register_info hf_octvc1_event[] =
	{
		/* Packet format F event fields */
		{ &hf_octvc1_event_header_ulLength,
			{ "Event Length",			"octvc1.event_header.ulLength",
			FT_UINT32, BASE_HEX, NULL, 0x0,
			"Event Length", HFILL }
		},

		{ &hf_octvc1_event_header_ulEventId,
			{ "Event ID",			"octvc1.event_header.ulEventId", FT_UINT32, BASE_HEX, NULL, 0x0,
			"", HFILL }},

		{ &hf_octvc1_event_header_ulUserEventId,
			{ "User Event ID",			"octvc1.event_header.ulUserEventId",
			FT_UINT32, BASE_HEX, NULL, 0x0,
			"User Event ID", HFILL }
		},

		{ &hf_octvc1_event_header_ulEventId_Type,
			{ "Message Type Base",           "octvc1.event_header.type_base",
			FT_UINT32, BASE_HEX, NULL, 0x00f00000,
			"Message identifier", HFILL }
		},

		{ &hf_octvc1_event_header_ulEventId_Base,
			{ "Module ID",           "octvc1.event_header.module_id",
			FT_UINT32, BASE_HEX, VALS(vals_OCTVC1_module_UID), 0x000f0000,
			"Module identifier", HFILL }
		},
		{ &hf_octvc1_event_header_ulEventId_Code,
			{ "Event Code Id",           "octvc1.event_header.code_id",
			FT_UINT32, BASE_HEX, NULL, 0x0000ffff,
			"Event code", HFILL }
		},
	};

	/* Setup protocol subtree array */
	static gint* ett[] =
	{
		&ett_octvc1_event_header,
		&ett_octvc1_event_id
	};

	proto_octvc1_event = proto_register_protocol(	"OCTVC1 Event Packets",
														"Octasic OCTVC1 Event", "octvc1_event");

	/* Required function calls to register the header fields and subtrees used */
	proto_register_field_array( proto_octvc1_event, hf_octvc1_event, array_length(hf_octvc1_event) );
	proto_register_subtree_array(ett, array_length(ett));
	register_dissector("Octvc1_Event", dissect_octvc1_event, proto_octvc1_event);

}

