/*
* Copyright 2015-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file 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.
*/
using System.Collections;
using System.Collections.Generic;
using System;
using System.Collections.ObjectModel;
using Amazon.MobileAnalytics.MobileAnalyticsManager;
using Amazon.Util;
using Amazon.MobileAnalytics.MobileAnalyticsManager.Internal;
namespace Amazon.MobileAnalytics.MobileAnalyticsManager
{
///
/// Represents any useful event you wish to record in your application.
///
/// The example below shows how to use CustomEvent
///
/// CustomEvent customEvent = new CustomEvent("level_complete");
///
/// customEvent.AddAttribute("LevelName","Level1");
/// customEvent.AddAttribute("Successful","True");
/// customEvent.AddMetric("Score",12345);
/// customEvent.AddMetric("TimeInLevel",64);
///
/// analyticsManager.RecordEvent(customEvent);
///
///
///
public class CustomEvent : IEvent
{
///
/// Event type string that defines event type.
///
internal string EventType { get; set; }
///
/// Dictionary that stores global attribute for specific event type.
///
private static Dictionary> _eventTypeGlobalAttributes = new Dictionary>();
///
/// Dictionary that stores global metric for specific event type.
///
private static Dictionary> _eventTypeGlobalMetrics = new Dictionary>();
///
/// Dictionary that stores global attribute for all event type.
///
private static Dictionary _globalAttributes = new Dictionary();
///
/// Dictionary that stores global metric for all event type.
///
private static Dictionary _globalMetrics = new Dictionary();
///
/// Dictionary that stores attribute for this event only.
///
private Dictionary _attributes = new Dictionary();
///
/// Dictionary that stores metric for this event only.
///
private Dictionary _metrics = new Dictionary();
///
/// Unique Identifier of Session
///
internal string SessionId {get;set;}
///
/// Duration of the session in milliseconds.
///
internal long Duration { get; set; }
///
/// Start time stamp of seesion.
///
internal DateTime StartTimestamp {get;set;}
///
/// Stop time stamp of session.
///
internal DateTime? StopTimestamp { get; set; }
///
/// Timestamp of when event is recorded.
///
internal DateTime Timestamp { get; set; }
///
/// Lock that protects global attribute and metric.
///
private static Object _globalLock = new Object();
///
/// Lock that protects attribute and metric.
///
private Object _lock = new Object();
private const int MAX_KEY_SIZE = 50;
private const int MAX_ATTRIB_VALUE_SIZE = 255;
#region constructor
///
/// Initializes a new instance of the
/// class.
///
/// Event type.
public CustomEvent(string eventType)
{
if (null == eventType)
throw new ArgumentNullException("eventType");
this.EventType = eventType;
}
#endregion
///
/// Converts to mobile analytics model event.
///
/// The to mobile analytics model event.
/// Session.
internal virtual Amazon.MobileAnalytics.Model.Event ConvertToMobileAnalyticsModelEvent(Amazon.MobileAnalytics.MobileAnalyticsManager.Internal.Session session)
{
Amazon.MobileAnalytics.Model.Event modelEvent = new Amazon.MobileAnalytics.Model.Event();
this.StartTimestamp = session.StartTime;
this.SessionId = session.SessionId;
// assign session info from custom event to model event
modelEvent.EventType = this.EventType;
modelEvent.Session = new Amazon.MobileAnalytics.Model.Session();
modelEvent.Session.Id = session.SessionId;
modelEvent.Session.StartTimestampUtc = session.StartTime;
if (session.StopTime != null)
modelEvent.Session.StopTimestampUtc = session.StopTime.Value;
if(this.EventType == Constants.SESSION_STOP_EVENT_TYPE)
{
modelEvent.Session.StopTimestampUtc = this.StopTimestamp.Value;
modelEvent.Session.Duration = this.Duration;
}
lock(_globalLock)
{
AddDict(_globalAttributes,modelEvent.Attributes);
if(_eventTypeGlobalAttributes.ContainsKey(EventType))
{
AddDict(_eventTypeGlobalAttributes[EventType],modelEvent.Attributes);
}
AddDict(_globalMetrics,modelEvent.Metrics);
if(_eventTypeGlobalMetrics.ContainsKey(EventType))
{
AddDict(_eventTypeGlobalMetrics[EventType],modelEvent.Metrics);
}
}
lock(_lock)
{
AddDict(_attributes,modelEvent.Attributes);
AddDict(_metrics,modelEvent.Metrics);
}
modelEvent.TimestampUtc = Timestamp;
modelEvent.Version = "v2.0";
return modelEvent;
}
#region attribute
///
/// Adds the attribute.
///
/// Attribute name. Max name length is 50.
/// Attribute value. Max value length is 255.
public void AddAttribute(string attributeName, string attributeValue)
{
if(string.IsNullOrEmpty(attributeName))
{
throw new ArgumentNullException("attributeName");
}
if (null == attributeValue)
{
throw new ArgumentNullException("attributeValue");
}
if(attributeName.Length > MAX_KEY_SIZE)
{
throw new ArgumentException("Length of attributeName " + attributeName+" is more than " + MAX_KEY_SIZE);
}
if(attributeValue.Length > MAX_ATTRIB_VALUE_SIZE)
{
throw new ArgumentException("Length of attributeValue is more than " + MAX_ATTRIB_VALUE_SIZE);
}
lock(_lock)
{
_attributes[attributeName] = attributeValue;
}
}
///
/// Determines whether this instance has attribute the specified attributeName.
///
/// Attribute name.
/// Return true if the event has the attribute, else false.
public bool HasAttribute(string attributeName)
{
if(string.IsNullOrEmpty(attributeName))
{
throw new ArgumentNullException("attributeName");
}
bool ret = false;
lock(_lock)
{
ret = _attributes.ContainsKey(attributeName);
}
return ret;
}
///
/// Gets the attribute.
///
/// Attribute name.
/// The attribute. Return null of attribute doesn't exist.
public string GetAttribute(string attributeName)
{
if(string.IsNullOrEmpty(attributeName))
{
throw new ArgumentNullException("attributeName");
}
string ret = null;
lock(_lock)
{
if(attributeName.Contains(attributeName))
ret = _attributes[attributeName];
}
return ret;
}
///
/// Gets copy of all attributes.
///
/// Copy of all the attributes.
public IDictionary AllAttributes
{
get
{
IDictionary ret;
lock(_lock)
{
ret = CopyDict(_attributes);
}
return ret;
}
}
#endregion
#region metric
///
/// Adds the metric.
///
/// Metric name. Max length is 50.
/// Metric value.
public void AddMetric(string metricName, double metricValue)
{
if(string.IsNullOrEmpty(metricName))
{
throw new ArgumentNullException("metricName");
}
if(metricName.Length > MAX_KEY_SIZE)
{
throw new ArgumentException("length of the metricName " + metricName+" is more than " + MAX_KEY_SIZE);
}
lock(_lock)
{
_metrics[metricName] = metricValue;
}
}
///
/// Determines whether this instance has metric the specified metricName.
///
/// Metric name.
/// Return true if the event has the attribute, else false.
public bool HasMetric(string metricName)
{
if(string.IsNullOrEmpty(metricName))
{
throw new ArgumentNullException("metricName");
}
bool ret = false;
lock(_lock)
{
ret = _metrics.ContainsKey(metricName);
}
return ret;
}
///
/// Gets the metric.
///
/// Metric name.
/// The metric. Return null of metric doesn't exist.
public double? GetMetric(string metricName)
{
if(string.IsNullOrEmpty(metricName))
{
throw new ArgumentNullException("metricName");
}
double? ret = null;
lock(_lock)
{
if(_metrics.ContainsKey(metricName))
ret = _metrics[metricName];
}
return ret;
}
///
/// Gets copy of all metrics.
///
/// Copy of all the metrics.
public IDictionary AllMetrics
{
get
{
IDictionary ret;
lock(_lock)
{
ret = CopyDict(_metrics);
}
return ret;
}
}
#endregion
#region gloablattribute
///
/// Adds the global attribute, which is valid for all events.
///
/// Attribute name. Max length is 50.
/// Attribute value. Max length is 255.
public void AddGlobalAttribute(string attributeName, string attributeValue)
{
if(string.IsNullOrEmpty(attributeName))
{
throw new ArgumentNullException("attributeName");
}
if( null == attributeValue)
{
throw new ArgumentNullException("attributeValue");
}
if(attributeName.Length > MAX_KEY_SIZE)
{
throw new ArgumentException("Length of attributeName " + attributeName+" is more than " + MAX_KEY_SIZE);
}
if(attributeValue.Length > MAX_ATTRIB_VALUE_SIZE)
{
throw new ArgumentException("Length of attributeValue is more than " + MAX_ATTRIB_VALUE_SIZE);
}
lock(_globalLock)
{
_globalAttributes[attributeName] = attributeValue;
}
}
///
/// Adds the global attribute, which is valid to some specific event type.
///
/// Event type.
/// Attribute name. Max length is 50.
/// Attribute value. Max length is 255.
public void AddGlobalAttribute(string eventType, string attributeName, string attributeValue)
{
if(string.IsNullOrEmpty(eventType))
{
throw new ArgumentNullException("eventType");
}
if(string.IsNullOrEmpty(attributeName))
{
throw new ArgumentNullException("attributeName");
}
if( null == attributeValue)
{
throw new ArgumentNullException("attributeValue");
}
if(attributeName.Length > MAX_KEY_SIZE)
{
throw new ArgumentException("Length of attributeName " + attributeName+" is more than " + MAX_KEY_SIZE);
}
if(attributeValue.Length > MAX_ATTRIB_VALUE_SIZE)
{
throw new ArgumentException("Length of attributeValue is more than " + MAX_ATTRIB_VALUE_SIZE);
}
lock(_globalLock)
{
if(!_eventTypeGlobalAttributes.ContainsKey(eventType))
{
_eventTypeGlobalAttributes.Add(eventType,new Dictionary());
_eventTypeGlobalAttributes[eventType].Add(attributeName, attributeValue);
}
else if(_eventTypeGlobalAttributes.ContainsKey(eventType) && !_eventTypeGlobalAttributes[eventType].ContainsKey(attributeName))
{
_eventTypeGlobalAttributes[eventType].Add(attributeName, attributeValue);
}
}
}
///
/// Removes the global attribute, which is valid for all events.
///
/// Attribute name.
public void RemoveGlobalAttribute(string attributeName)
{
if(string.IsNullOrEmpty(attributeName))
{
throw new ArgumentNullException("attributeName");
}
lock(_globalLock)
{
if(_globalAttributes.ContainsKey(attributeName))
{
_globalAttributes.Remove(attributeName);
}
}
}
///
/// Removes the global attribute, which is valid to some specific event type.
///
/// Event type.
/// Attribute name.
public void RemoveGlobalAttribute(string eventType, string attributeName)
{
if(string.IsNullOrEmpty(eventType))
{
throw new ArgumentNullException("eventType");
}
if(string.IsNullOrEmpty(attributeName))
{
throw new ArgumentNullException("attributeName");
}
lock(_globalLock)
{
if(_eventTypeGlobalAttributes.ContainsKey(eventType) && _eventTypeGlobalAttributes[eventType].ContainsKey(attributeName))
{
_eventTypeGlobalAttributes[eventType].Remove(attributeName);
}
}
}
///
/// Gets the global attribute, which is valid for all events.
///
/// Attribute name.
/// The global attribute. Return null if attribute doesn't exist.
public string GetGlobalAttribute(string attributeName)
{
if(string.IsNullOrEmpty(attributeName))
{
throw new ArgumentNullException("attributeName");
}
string ret = null;
lock(_globalLock)
{
if(_globalAttributes.ContainsKey(attributeName))
{
ret = _globalAttributes[attributeName];
}
}
return ret;
}
///
/// Gets the global attribute, which is valid for some specific event type.
///
/// Event type.
/// Attribute name.
/// The global attribute. Return null if attribute doesn't exist.
public string GetGlobalAttribute(string eventType, string attributeName)
{
if(string.IsNullOrEmpty(eventType))
{
throw new ArgumentNullException("eventType");
}
if(string.IsNullOrEmpty(attributeName))
{
throw new ArgumentNullException("attributeName");
}
string ret = null;
lock(_globalLock)
{
if(_eventTypeGlobalAttributes.ContainsKey(eventType) && _eventTypeGlobalAttributes[eventType].ContainsKey(attributeName))
{
ret = _eventTypeGlobalAttributes[eventType][attributeName];
}
}
return ret;
}
#endregion
#region globalmetric
///
/// Adds the global metric, which is valid for all events.
///
/// Metric name. Max length is 50.
/// Metric value.
public void AddGlobalMetric(string metricName, double metricValue)
{
if(string.IsNullOrEmpty(metricName))
{
throw new ArgumentNullException("metricName");
}
if(metricName.Length > MAX_KEY_SIZE)
{
throw new ArgumentException("Length of the metricName " + metricName+" is more than " + MAX_KEY_SIZE);
}
lock(_globalLock)
{
_globalMetrics[metricName] = metricValue;
}
}
///
/// Adds the global metric, which is valid for some specific event type.
///
/// Event type.
/// Metric name. Max length is 50.
/// Metric value.
public void AddGlobalMetric(string eventType, string metricName, double metricValue)
{
if(string.IsNullOrEmpty(eventType))
{
throw new ArgumentNullException("eventType");
}
if(string.IsNullOrEmpty(metricName))
{
throw new ArgumentNullException("metricName");
}
if(metricName.Length > MAX_KEY_SIZE)
{
throw new ArgumentException("Length of the metricName " + metricName+" is more than " + MAX_KEY_SIZE);
}
lock(_globalLock)
{
if(!_eventTypeGlobalMetrics.ContainsKey(eventType))
{
_eventTypeGlobalMetrics.Add(eventType,new Dictionary());
_eventTypeGlobalMetrics[eventType][metricName] = metricValue;
return;
}
else if(_eventTypeGlobalMetrics.ContainsKey(eventType))
{
_eventTypeGlobalMetrics[eventType][metricName] = metricValue;
return;
}
}
}
///
/// Removes the global metric, which is valid for all events.
///
/// Metric name.
public void RemoveGlobalMetric(string metricName)
{
if(string.IsNullOrEmpty(metricName))
{
throw new ArgumentNullException("metricName");
}
lock(_globalLock)
{
if(_globalMetrics.ContainsKey(metricName))
{
_globalMetrics.Remove(metricName);
}
}
}
///
/// Removes the global metric, which is valid for some specific event type.
///
/// Event type.
/// Metric name.
public void RemoveGlobalMetric(string eventType,string metricName)
{
if(string.IsNullOrEmpty(eventType))
{
throw new ArgumentNullException("eventType");
}
if(string.IsNullOrEmpty(metricName))
{
throw new ArgumentNullException("metricName");
}
lock(_globalLock)
{
if(_eventTypeGlobalMetrics.ContainsKey(eventType) && _eventTypeGlobalMetrics[eventType].ContainsKey(metricName))
{
_eventTypeGlobalMetrics[eventType].Remove(metricName);
}
}
}
///
/// Gets the global metric, which is valid for all events.
///
/// The global metric. Return null if metric doesn't exist.
/// Metric name.
public double? GetGlobalMetric(string metricName)
{
if(string.IsNullOrEmpty(metricName))
{
throw new ArgumentNullException("metricName");
}
double? ret = null;
lock(_globalLock)
{
if(_globalMetrics.ContainsKey(metricName))
ret = _globalMetrics[metricName];
}
return ret;
}
///
/// Gets the global metric, which is valid for some specific event type.
///
/// Event type.
/// Metric name.
/// The global metric. Return null if metric doesn't exist.
public double? GetGlobalMetric(string eventType, string metricName)
{
if(string.IsNullOrEmpty(eventType))
{
throw new ArgumentNullException("eventType");
}
if(string.IsNullOrEmpty(metricName))
{
throw new ArgumentNullException("metricName");
}
double? ret = null;
lock(_globalLock)
{
if(_eventTypeGlobalMetrics.ContainsKey(eventType) && _eventTypeGlobalMetrics[eventType].ContainsKey(metricName))
{
ret = _eventTypeGlobalMetrics[eventType][metricName];
}
}
return ret;
}
#endregion
#region util
private static void AddDict(Dictionary srcDict, Dictionary dstDict)
{
if(srcDict == null)
{
throw new ArgumentNullException("srcDict");
}
if (dstDict == null)
{
throw new ArgumentNullException("dstDict");
}
foreach (var item in srcDict)
{
dstDict[item.Key] = item.Value;
}
}
private static Dictionary CopyDict(Dictionary srcDict)
{
if(srcDict == null)
{
throw new ArgumentNullException("srcDict");
}
Dictionary dstDict = new Dictionary();
foreach (var item in srcDict)
{
dstDict.Add(item.Key, item.Value);
}
return dstDict;
}
#endregion
}
}