using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Text;
namespace com.itac.mes.imsapi
{
///
/// tool fuer das automatische Mapping von Werten in Strukturen nach String-Arrays und umgekehrt
///
/// Prinzip uebernommen aus dem ImsInterfaces, Klasse ImsApiMapTool
///
///
public class ImsApiMapTool
{
// von einem Typ
private static Dictionary> fieldMapperTable = new Dictionary>();
private static Dictionary> propertyMapperTable = new Dictionary>();
public static void clearClassCache(Type clazz)
{
Dictionary fieldKeyMapper = null;
if (fieldMapperTable.ContainsKey(clazz))
{
fieldKeyMapper = fieldMapperTable[clazz];
fieldMapperTable.Remove(clazz);
}
Dictionary propertyKeyMapper = null;
if (propertyMapperTable.ContainsKey(clazz))
{
propertyKeyMapper = propertyMapperTable[clazz];
propertyMapperTable.Remove(clazz);
}
}
///
/// eine Abbildungstabelle fuer einen Typ ermitteln (Namen von Feldern und IMSAPI-Keys)
///
///
///
protected Dictionary getFieldMapperTable(Type clazz)
{
Dictionary keyMapper = null;
if (fieldMapperTable.ContainsKey(clazz))
{
keyMapper = fieldMapperTable[clazz];
}
else
{
keyMapper = new Dictionary();
// welche ImsApiKeys werden auf welche Fields abgebildet
// iterate over all fields
FieldInfo[] fields = clazz.GetFields();
foreach (FieldInfo field in fields)
{
// get relevant annotation
object[] annotation = field.GetCustomAttributes(typeof(ImsApiKey), true);
if (annotation != null && annotation.Length > 0)
{
// add field mappings
keyMapper.Add(((ImsApiKey)annotation[0]).Key, field);
}
}
fieldMapperTable.Add(clazz, keyMapper);
}
return keyMapper;
}
protected Dictionary getPropertyMapperTable(Type clazz)
{
Dictionary keyMapper = null;
if (propertyMapperTable.ContainsKey(clazz))
{
keyMapper = propertyMapperTable[clazz];
}
else
{
keyMapper = new Dictionary();
// welche ImsApiKeys werden auf welche Fields abgebildet
// iterate over all fields
PropertyInfo[] properties = clazz.GetProperties();
foreach (PropertyInfo property in properties)
{
// get relevant annotation
object[] annotation = property.GetCustomAttributes(typeof(ImsApiKey), true);
if (annotation != null && annotation.Length > 0)
{
// add field mappings
keyMapper.Add(((ImsApiKey)annotation[0]).Key, property);
}
}
propertyMapperTable.Add(clazz, keyMapper);
}
return keyMapper;
}
///
/// aus einem String-Array mit Keys und Werten eine Struktur erzeugen.
/// alle Felder in der Struktur muessen dafuer mit dem Attribut [IMSAPIKEY]
/// versehen sein
///
///
///
///
///
public T getStruct(Type clazz, string[] imsApiKeys, string[] imsApiValues)
{
if (clazz == null)
{
throw new ArgumentException("parameter clazz must not be null");
}
if (imsApiKeys == null)
{
throw new ArgumentException("parameter imsApiKeys must not be null");
}
if (imsApiValues == null)
{
throw new ArgumentException("parameter imsApiValues must not be null");
}
// Anzahl der Werte muss identisch sein mit der Anzahl der Keys
if (imsApiKeys.Length != imsApiValues.Length)
{
throw new ArgumentException("parameter imsApiKeys and imsApiValues must have the same size");
}
Dictionary keyMapper = getFieldMapperTable(clazz);
Dictionary propertyKeyMapper = getPropertyMapperTable(clazz);
T instance = getInstance(clazz, imsApiKeys, imsApiValues, keyMapper, propertyKeyMapper, 0);
return instance;
}
private T getInstance(Type clazz, String[] imsApiKeys, String[] imsApiValues, Dictionary keyMapper,
Dictionary propertyMapper, int baseIndex)
{
T instance = (T)Activator.CreateInstance(clazz);
// now map all keyValues to fields
for (int index = 0; index < imsApiKeys.Length; index++)
{
String key = imsApiKeys[index];
String sValue = imsApiValues[baseIndex + index];
if (!keyMapper.ContainsKey(key))
{
// dieser key ist nicht zur Abbildung definiert, d.h. es gibt keine Annotation in der Zielklasse mit diesem Key
if (!propertyMapper.ContainsKey(key))
{
continue;
}
PropertyInfo propInfo = propertyMapper[key];
safeSetProperty(instance, propInfo, sValue);
continue;
}
FieldInfo f = keyMapper[key];
safeSetField(instance, f, sValue);
}
return instance;
}
///
/// aus einem String-Array mit Keys und Werten ein Array von Strukturen erzeugen.
/// alle Felder in der Struktur muessen dafuer mit dem Attribut [IMSAPIKEY]
/// versehen sein
///
///
///
///
///
public T[] getArray(Type clazz, String[] imsApiKeys, String[] imsApiValues)
{
// Check parameters
if (clazz == null)
{
throw new ArgumentException("parameter clazz must not be null");
}
if (imsApiKeys == null)
{
throw new ArgumentException("parameter imsApiKeys must not be null");
}
if (imsApiValues == null || imsApiValues.Length == 0)
{
throw new ArgumentException("parameter imsApiValues must not be null");
}
// Anzahl der Werte muss ein ganzzahliges Vielfaches der Anzahl der Keys sein
if ((imsApiValues.Length % imsApiKeys.Length) != 0)
{
throw new ArgumentException("parameter imsApiValues must be a multiple of imsApiKeys");
}
Dictionary keyMapper = getFieldMapperTable(clazz);
Dictionary propertyKeyMapper = getPropertyMapperTable(clazz);
int length = imsApiValues.Length / imsApiKeys.Length;
T[] resultArray = (T[])Array.CreateInstance(clazz, length);
for (int baseIndex = 0; baseIndex < imsApiValues.Length; baseIndex += imsApiKeys.Length)
{
T instance = getInstance(clazz, imsApiKeys, imsApiValues, keyMapper, propertyKeyMapper, baseIndex);
resultArray[baseIndex / imsApiKeys.Length] = instance;
}
return resultArray;
}
protected void safeSetField(T instance, FieldInfo field, String sValue)
{
//if ((field.getModifiers() & Modifier.PRIVATE) == Modifier.PRIVATE) {
// field.setAccessible(true);
//}
try
{
if (field.FieldType == typeof(int) || field.FieldType == typeof(Int16) || field.FieldType == typeof(Int32) || field.FieldType == typeof(Int64))
{
try
{
field.SetValue(instance, Int32.Parse(sValue));
}
catch (Exception)
{
// replace all , by .
string s = sValue.Replace(",", ".");
CultureInfo culture = CultureInfo.CreateSpecificCulture("en-US");
field.SetValue(instance, Convert.ToInt32(Double.Parse(s, culture)));
}
}
else if (field.FieldType == typeof(String) || field.FieldType == typeof(string))
{
field.SetValue(instance, sValue);
}
//} else if (field.getType() == Boolean.class || field.getType() == boolean.class) {
// field.setBoolean(instance, Boolean.parseBoolean(sValue));
else if (field.FieldType == typeof(DateTime))
{
field.SetValue(instance, getDateValue(sValue));
}
else
{
throw new ArgumentException("unknown type mapper for " + field.FieldType.Name);
}
}
catch (Exception e)
{
throw new ArgumentException("unknown type mapper or invalid value for " + field.Name + ":" + sValue, e);
}
}
protected void safeSetProperty(T instance, PropertyInfo field, String sValue)
{
//if ((field.getModifiers() & Modifier.PRIVATE) == Modifier.PRIVATE) {
// field.setAccessible(true);
//}
try
{
if (field.PropertyType== typeof(int) || field.PropertyType == typeof(Int16) || field.PropertyType == typeof(Int32) || field.PropertyType == typeof(Int64))
{
try
{
field.SetValue(instance, Int32.Parse(sValue), new object[] { });
}
catch (Exception)
{
// replace all , by .
string s = sValue.Replace(",", ".");
CultureInfo culture = CultureInfo.CreateSpecificCulture("en-US");
field.SetValue(instance, Convert.ToInt32(Double.Parse(s, culture)), new object[] { });
}
}
else if (field.PropertyType == typeof(String) || field.PropertyType == typeof(string))
{
field.SetValue(instance, sValue, new object[] { });
}
//} else if (field.getType() == Boolean.class || field.getType() == boolean.class) {
// field.setBoolean(instance, Boolean.parseBoolean(sValue));
else if (field.PropertyType == typeof(DateTime))
{
field.SetValue(instance, getDateValue(sValue), new object[] { });
}
else
{
throw new ArgumentException("unknown type mapper for " + field.PropertyType.Name);
}
}
catch (Exception e)
{
throw new ArgumentException("unknown type mapper or invalid value for " + field.Name + ":" + sValue, e);
}
}
public DateTime getDateValue(string sDateValue)
{
if (sDateValue == null || sDateValue.Equals(""))
{
return new DateTime(1899, 12, 31, 23, 59, 59, DateTimeKind.Utc);
}
string s = sDateValue.Replace(",", ".");
CultureInfo culture = CultureInfo.CreateSpecificCulture("en-US");
double millies = Double.Parse(sDateValue, culture);
if (millies <= 1000)
{
return new DateTime(1899, 12, 31, 23, 59, 59, DateTimeKind.Utc);
}
// treat date values >= 30.12.3000 as infinite...
if (millies >= 32535039600000)
{
return new DateTime(9999, 12, 31, 23, 59, 59, DateTimeKind.Utc);
}
DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
DateTime expiry = epoch.AddMilliseconds(millies);
return expiry;
}
public String[] getValueArray(T[] value, String[] imsApiKeys)
{
if (value == null)
{
throw new ArgumentException("parameter value must not be null");
}
if (imsApiKeys == null)
{
throw new ArgumentException("parameter imsApiKeys must not be null");
}
if (value.Length == 0)
{
return new String[0];
}
// aus der uebergebenen Struktur ein String Array bilden, unter der Prämisse der Imsapikeys
// Kein Element des ValueArray darf null sein !!!!!
if (value[0] == null)
{
throw new ArgumentException("first element in value array must not be null");
}
Dictionary keyMapper = getFieldMapperTable(value[0].GetType());
String[] resultArray = new String[imsApiKeys.Length * value.Length];
// nicht in der Struktur enthaltene Keys führen zu Fehlern
// in der Struktur enthaltene Keys, die nicht im imsapiKeysArray enthalten sind werden einfach ignoriert
int startIndex = 0;
foreach (T item in value)
{
toImsApiStringArray(item, resultArray, imsApiKeys, keyMapper, startIndex);
startIndex += imsApiKeys.Length;
}
return resultArray;
}
///
/// aus einer Struktur ein String-Array erzeugen; alle als Keys uerbegebenen Felder
/// sind im String-Array in der Reihenfolge der imsApiKeys enthalten
///
///
///
///
public String[] getValueArray(T value, String[] imsApiKeys)
{
if (value == null)
{
throw new ArgumentException("parameter value must not be null");
}
if (imsApiKeys == null)
{
throw new ArgumentException("parameter imsApiKeys must not be null");
}
// aus der uebergebenen Struktur ein String Array bilden, unter der Prämisse der Imsapikeys
Dictionary keyMapper = getFieldMapperTable(value.GetType());
String[] resultArray = new String[imsApiKeys.Length];
// nicht in der Struktur enthaltene Keys führen zu Fehlern
// in der Struktur enthaltene Keys, die nicht im imsapiKeysArray enthalten sind werden einfach ignoriert
toImsApiStringArray(value, resultArray, imsApiKeys, keyMapper, 0);
return resultArray;
}
protected void toImsApiStringArray(T value, String[] resultArray, String[] imsApiKeys,
Dictionary keyMapper, int i)
{
int destinationIndex = i;
foreach (String key in imsApiKeys)
{
if (!keyMapper.ContainsKey(key))
{
throw new ArgumentException("destination key '" + key + "' is not available in structure");
}
FieldInfo field = keyMapper[key];
try
{
String imsapiString = safeGetField(field, value);
resultArray[destinationIndex++] = imsapiString;
}
catch (NullReferenceException)
{
// field is null
destinationIndex++;
}
catch (Exception )
{
destinationIndex++;
}
}
}
protected String safeGetField(FieldInfo field, T value)
{
try
{
Object o = field.GetValue(value);
if (field.FieldType == typeof(int) || field.FieldType == typeof(Int16) || field.FieldType == typeof(Int32) || field.FieldType == typeof(Int64) )
{
return o.ToString();
}
else if (field.FieldType == typeof(string) || field.FieldType == typeof(String))
{
return o.ToString();
}
else if (field.FieldType == typeof(Boolean) || field.FieldType == typeof(bool))
{
bool b = (Boolean)o;
if (b)
{
return "1";
}
else
{
return "0";
}
}
else if (field.FieldType == typeof(DateTime))
{
DateTime d = (DateTime)o;
if (d == null)
{
return "0";
}
return "" + d.Ticks;// todo:correction
}
}
catch (NullReferenceException)
{
return "";
}
catch (AccessViolationException)
{
// einfach ignorieren, dies sollte eigentlich nie vorkommen
}
throw new ArgumentException("unknown type mapper for " + field.FieldType.Name);
}
}
}