using Google.Protobuf;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Tango.Core.ExtensionMethods;
using Tango.PMR;
using Tango.PMR.Common;
using Tango.PMR.DataStore;
namespace Tango.DataStore
{
///
/// Contains data store helper methods.
///
public static class DataStoreHelper
{
///
/// Gets the data store data type by the specified object type.
///
/// The value.
///
public static DataType GetDataType(Object value)
{
return GetDataType(value.GetType());
}
///
/// Gets data store data type by the specified .net type.
///
/// The type.
///
///
public static DataType GetDataType(Type type)
{
if (type == typeof(int))
{
return DataType.Int32;
}
else if (type == typeof(Int64))
{
return DataType.Int32;
}
else if (type == typeof(float))
{
return DataType.Float;
}
else if (type == typeof(double))
{
return DataType.Double;
}
else if (type == typeof(String))
{
return DataType.String;
}
else if (type == typeof(bool))
{
return DataType.Boolean;
}
else if (type == typeof(byte[]))
{
return DataType.Bytes;
}
else if (type == typeof(DataStoreProtoObject))
{
return DataType.Proto;
}
else if (typeof(IMessage).IsAssignableFrom(type))
{
return DataType.Proto;
}
throw new NotSupportedException($"The specified type '{type.Name}' is not supported by the data store.");
}
///
/// Formats the data store item as a string.
///
/// The item.
///
public static String FormatDataStoreItem(IDataStoreItem item)
{
return FormatDataStoreValue(item.Type, item.Value);
}
///
/// Formats the data store value.
///
/// The type.
/// The object.
///
public static String FormatDataStoreValue(DataType type, object obj)
{
if (type == DataType.Bytes)
{
return Convert.ToBase64String((byte[])obj);
}
else if (type == DataType.Proto)
{
return (obj as DataStoreProtoObject).Message.ToJsonString();
}
else
{
return obj.ToStringSafe();
}
}
///
/// Parses a data store value from a string.
///
/// The type.
/// The string.
/// Type of the proto message (if type is Proto).
///
/// No PMR message type specified.
/// The specified data store type is not supported.
public static Object ParseDataStoreValue(DataType type, String text, DataStoreMessageType? protoMessageType = null)
{
switch (type)
{
case DataType.String:
return text;
case DataType.Int32:
return int.Parse(text);
case DataType.Float:
return float.Parse(text);
case DataType.Double:
return double.Parse(text);
case DataType.Boolean:
return bool.Parse(text);
case DataType.Proto:
if (protoMessageType == null) throw new ArgumentNullException("No PMR message type specified.");
var messageType = MessageFactory.GetDataStorePMRTypeFromDataStoreMessageType(protoMessageType.Value);
var instance = Activator.CreateInstance(messageType) as IMessage;
instance = instance.GetParser().ParseJson(text);
return DataStoreProtoObject.FromMessage(instance);
case DataType.Bytes:
return Convert.FromBase64String(text);
}
throw new NotSupportedException("The specified data store type is not supported.");
}
///
/// Validates the name of the collection or key.
///
/// The name.
///
public static bool ValidateCollectionOrKeyName(String name)
{
var regexItem = new Regex("^[a-zA-Z0-9_-]*$");
return regexItem.IsMatch(name);
}
///
/// Creates a data store value from byte array that are stored in database.
///
/// The type.
/// The bytes.
///
/// The specified type is not supported.
public static Object CreateObject(DataType type, byte[] bytes)
{
switch (type)
{
case DataType.Int32:
return BitConverter.ToInt32(bytes, 0);
case DataType.Float:
return BitConverter.ToSingle(bytes, 0);
case DataType.Double:
return BitConverter.ToDouble(bytes, 0);
case DataType.Boolean:
return BitConverter.ToBoolean(bytes, 0);
case DataType.String:
return Encoding.Default.GetString(bytes);
case DataType.Bytes:
return bytes;
case DataType.Proto:
return DataStoreProtoObject.FromBytes(bytes);
}
throw new NotSupportedException("The specified type is not supported.");
}
///
/// Creates a byte array that can be stored on database from the specified data store type and value.
///
/// The type.
/// The object.
///
///
/// DataStoreProtoObject
/// or
/// The specified type is not supported.
///
public static byte[] CreateBytes(DataType type, Object obj)
{
switch (type)
{
case DataType.Int32:
return BitConverter.GetBytes((int)obj);
case DataType.Float:
return BitConverter.GetBytes((float)obj);
case DataType.Double:
return BitConverter.GetBytes((double)obj);
case DataType.Boolean:
return BitConverter.GetBytes((bool)obj);
case DataType.String:
return Encoding.Default.GetBytes(obj.ToString());
case DataType.Bytes:
return (byte[])obj;
case DataType.Proto:
if (obj is DataStoreProtoObject protoMessage)
{
return protoMessage.ToBytes();
}
else
{
throw new NotSupportedException($"Data type is 'Proto' but object is not of type '{nameof(DataStoreProtoObject)}'.");
}
}
throw new NotSupportedException("The specified type is not supported.");
}
}
}