using System;
using System.Collections.Generic;
using System.Threading;

namespace LeanCloud.Storage.Internal {
  /// <summary>
  /// A reimplementation of Xamarin's PreserveAttribute.
  /// This allows us to support AOT and linking for Xamarin platforms.
  /// </summary>
  [AttributeUsage(AttributeTargets.All)]
  internal class PreserveAttribute : Attribute {
    public bool AllMembers;
    public bool Conditional;
  }

  [AttributeUsage(AttributeTargets.All)]
  internal class LinkerSafeAttribute : Attribute {
    public LinkerSafeAttribute() { }
  }

  [Preserve(AllMembers = true)]
  internal class PreserveWrapperTypes {
	/// <summary>
	/// Exists to ensure that generic types are AOT-compiled for the conversions we support.
	/// Any new value types that we add support for will need to be registered here.
	/// The method itself is never called, but by virtue of the Preserve attribute being set
	/// on the class, these types will be AOT-compiled.
	///
	/// This also applies to Unity.
	/// </summary>
	private static List<object> CreateWrapperTypes() {
      	return new List<object> {
			typeof(FlexibleListWrapper<object, object>),
			typeof(FlexibleListWrapper<object, bool>),
			typeof(FlexibleListWrapper<object, byte>),
			typeof(FlexibleListWrapper<object, sbyte>),
			typeof(FlexibleListWrapper<object, short>),
			typeof(FlexibleListWrapper<object, ushort>),
			typeof(FlexibleListWrapper<object, int>),
			typeof(FlexibleListWrapper<object, uint>),
			typeof(FlexibleListWrapper<object, long>),
			typeof(FlexibleListWrapper<object, ulong>),
			typeof(FlexibleListWrapper<object, char>),
			typeof(FlexibleListWrapper<object, double>),
			typeof(FlexibleListWrapper<object, float>),

			typeof(FlexibleListWrapper<bool, object>),
			typeof(FlexibleListWrapper<bool, bool>),
			typeof(FlexibleListWrapper<bool, byte>),
			typeof(FlexibleListWrapper<bool, sbyte>),
			typeof(FlexibleListWrapper<bool, short>),
			typeof(FlexibleListWrapper<bool, ushort>),
			typeof(FlexibleListWrapper<bool, int>),
			typeof(FlexibleListWrapper<bool, uint>),
			typeof(FlexibleListWrapper<bool, long>),
			typeof(FlexibleListWrapper<bool, ulong>),
			typeof(FlexibleListWrapper<bool, char>),
			typeof(FlexibleListWrapper<bool, double>),
			typeof(FlexibleListWrapper<bool, float>),

			typeof(FlexibleListWrapper<byte, object>),
			typeof(FlexibleListWrapper<byte, bool>),
			typeof(FlexibleListWrapper<byte, byte>),
			typeof(FlexibleListWrapper<byte, sbyte>),
			typeof(FlexibleListWrapper<byte, short>),
			typeof(FlexibleListWrapper<byte, ushort>),
			typeof(FlexibleListWrapper<byte, int>),
			typeof(FlexibleListWrapper<byte, uint>),
			typeof(FlexibleListWrapper<byte, long>),
			typeof(FlexibleListWrapper<byte, ulong>),
			typeof(FlexibleListWrapper<byte, char>),
			typeof(FlexibleListWrapper<byte, double>),
			typeof(FlexibleListWrapper<byte, float>),

			typeof(FlexibleListWrapper<sbyte, object>),
			typeof(FlexibleListWrapper<sbyte, bool>),
			typeof(FlexibleListWrapper<sbyte, byte>),
			typeof(FlexibleListWrapper<sbyte, sbyte>),
			typeof(FlexibleListWrapper<sbyte, short>),
			typeof(FlexibleListWrapper<sbyte, ushort>),
			typeof(FlexibleListWrapper<sbyte, int>),
			typeof(FlexibleListWrapper<sbyte, uint>),
			typeof(FlexibleListWrapper<sbyte, long>),
			typeof(FlexibleListWrapper<sbyte, ulong>),
			typeof(FlexibleListWrapper<sbyte, char>),
			typeof(FlexibleListWrapper<sbyte, double>),
			typeof(FlexibleListWrapper<sbyte, float>),

			typeof(FlexibleListWrapper<short, object>),
			typeof(FlexibleListWrapper<short, bool>),
			typeof(FlexibleListWrapper<short, byte>),
			typeof(FlexibleListWrapper<short, sbyte>),
			typeof(FlexibleListWrapper<short, short>),
			typeof(FlexibleListWrapper<short, ushort>),
			typeof(FlexibleListWrapper<short, int>),
			typeof(FlexibleListWrapper<short, uint>),
			typeof(FlexibleListWrapper<short, long>),
			typeof(FlexibleListWrapper<short, ulong>),
			typeof(FlexibleListWrapper<short, char>),
			typeof(FlexibleListWrapper<short, double>),
			typeof(FlexibleListWrapper<short, float>),

			typeof(FlexibleListWrapper<ushort, object>),
			typeof(FlexibleListWrapper<ushort, bool>),
			typeof(FlexibleListWrapper<ushort, byte>),
			typeof(FlexibleListWrapper<ushort, sbyte>),
			typeof(FlexibleListWrapper<ushort, short>),
			typeof(FlexibleListWrapper<ushort, ushort>),
			typeof(FlexibleListWrapper<ushort, int>),
			typeof(FlexibleListWrapper<ushort, uint>),
			typeof(FlexibleListWrapper<ushort, long>),
			typeof(FlexibleListWrapper<ushort, ulong>),
			typeof(FlexibleListWrapper<ushort, char>),
			typeof(FlexibleListWrapper<ushort, double>),
			typeof(FlexibleListWrapper<ushort, float>),

			typeof(FlexibleListWrapper<int, object>),
			typeof(FlexibleListWrapper<int, bool>),
			typeof(FlexibleListWrapper<int, byte>),
			typeof(FlexibleListWrapper<int, sbyte>),
			typeof(FlexibleListWrapper<int, short>),
			typeof(FlexibleListWrapper<int, ushort>),
			typeof(FlexibleListWrapper<int, int>),
			typeof(FlexibleListWrapper<int, uint>),
			typeof(FlexibleListWrapper<int, long>),
			typeof(FlexibleListWrapper<int, ulong>),
			typeof(FlexibleListWrapper<int, char>),
			typeof(FlexibleListWrapper<int, double>),
			typeof(FlexibleListWrapper<int, float>),

			typeof(FlexibleListWrapper<uint, object>),
			typeof(FlexibleListWrapper<uint, bool>),
			typeof(FlexibleListWrapper<uint, byte>),
			typeof(FlexibleListWrapper<uint, sbyte>),
			typeof(FlexibleListWrapper<uint, short>),
			typeof(FlexibleListWrapper<uint, ushort>),
			typeof(FlexibleListWrapper<uint, int>),
			typeof(FlexibleListWrapper<uint, uint>),
			typeof(FlexibleListWrapper<uint, long>),
			typeof(FlexibleListWrapper<uint, ulong>),
			typeof(FlexibleListWrapper<uint, char>),
			typeof(FlexibleListWrapper<uint, double>),
			typeof(FlexibleListWrapper<uint, float>),

			typeof(FlexibleListWrapper<long, object>),
			typeof(FlexibleListWrapper<long, bool>),
			typeof(FlexibleListWrapper<long, byte>),
			typeof(FlexibleListWrapper<long, sbyte>),
			typeof(FlexibleListWrapper<long, short>),
			typeof(FlexibleListWrapper<long, ushort>),
			typeof(FlexibleListWrapper<long, int>),
			typeof(FlexibleListWrapper<long, uint>),
			typeof(FlexibleListWrapper<long, long>),
			typeof(FlexibleListWrapper<long, ulong>),
			typeof(FlexibleListWrapper<long, char>),
			typeof(FlexibleListWrapper<long, double>),
			typeof(FlexibleListWrapper<long, float>),

			typeof(FlexibleListWrapper<ulong, object>),
			typeof(FlexibleListWrapper<ulong, bool>),
			typeof(FlexibleListWrapper<ulong, byte>),
			typeof(FlexibleListWrapper<ulong, sbyte>),
			typeof(FlexibleListWrapper<ulong, short>),
			typeof(FlexibleListWrapper<ulong, ushort>),
			typeof(FlexibleListWrapper<ulong, int>),
			typeof(FlexibleListWrapper<ulong, uint>),
			typeof(FlexibleListWrapper<ulong, long>),
			typeof(FlexibleListWrapper<ulong, ulong>),
			typeof(FlexibleListWrapper<ulong, char>),
			typeof(FlexibleListWrapper<ulong, double>),
			typeof(FlexibleListWrapper<ulong, float>),

			typeof(FlexibleListWrapper<char, object>),
			typeof(FlexibleListWrapper<char, bool>),
			typeof(FlexibleListWrapper<char, byte>),
			typeof(FlexibleListWrapper<char, sbyte>),
			typeof(FlexibleListWrapper<char, short>),
			typeof(FlexibleListWrapper<char, ushort>),
			typeof(FlexibleListWrapper<char, int>),
			typeof(FlexibleListWrapper<char, uint>),
			typeof(FlexibleListWrapper<char, long>),
			typeof(FlexibleListWrapper<char, ulong>),
			typeof(FlexibleListWrapper<char, char>),
			typeof(FlexibleListWrapper<char, double>),
			typeof(FlexibleListWrapper<char, float>),

			typeof(FlexibleListWrapper<double, object>),
			typeof(FlexibleListWrapper<double, bool>),
			typeof(FlexibleListWrapper<double, byte>),
			typeof(FlexibleListWrapper<double, sbyte>),
			typeof(FlexibleListWrapper<double, short>),
			typeof(FlexibleListWrapper<double, ushort>),
			typeof(FlexibleListWrapper<double, int>),
			typeof(FlexibleListWrapper<double, uint>),
			typeof(FlexibleListWrapper<double, long>),
			typeof(FlexibleListWrapper<double, ulong>),
			typeof(FlexibleListWrapper<double, char>),
			typeof(FlexibleListWrapper<double, double>),
			typeof(FlexibleListWrapper<double, float>),

			typeof(FlexibleListWrapper<float, object>),
			typeof(FlexibleListWrapper<float, bool>),
			typeof(FlexibleListWrapper<float, byte>),
			typeof(FlexibleListWrapper<float, sbyte>),
			typeof(FlexibleListWrapper<float, short>),
			typeof(FlexibleListWrapper<float, ushort>),
			typeof(FlexibleListWrapper<float, int>),
			typeof(FlexibleListWrapper<float, uint>),
			typeof(FlexibleListWrapper<float, long>),
			typeof(FlexibleListWrapper<float, ulong>),
			typeof(FlexibleListWrapper<float, char>),
			typeof(FlexibleListWrapper<float, double>),
			typeof(FlexibleListWrapper<float, float>),

			typeof(FlexibleListWrapper<object, DateTime>),
			typeof(FlexibleListWrapper<DateTime, object>),

			typeof(FlexibleDictionaryWrapper<object, object>),
			typeof(FlexibleDictionaryWrapper<object, bool>),
			typeof(FlexibleDictionaryWrapper<object, byte>),
			typeof(FlexibleDictionaryWrapper<object, sbyte>),
			typeof(FlexibleDictionaryWrapper<object, short>),
			typeof(FlexibleDictionaryWrapper<object, ushort>),
			typeof(FlexibleDictionaryWrapper<object, int>),
			typeof(FlexibleDictionaryWrapper<object, uint>),
			typeof(FlexibleDictionaryWrapper<object, long>),
			typeof(FlexibleDictionaryWrapper<object, ulong>),
			typeof(FlexibleDictionaryWrapper<object, char>),
			typeof(FlexibleDictionaryWrapper<object, double>),
			typeof(FlexibleDictionaryWrapper<object, float>),

			typeof(FlexibleDictionaryWrapper<bool, object>),
			typeof(FlexibleDictionaryWrapper<bool, bool>),
			typeof(FlexibleDictionaryWrapper<bool, byte>),
			typeof(FlexibleDictionaryWrapper<bool, sbyte>),
			typeof(FlexibleDictionaryWrapper<bool, short>),
			typeof(FlexibleDictionaryWrapper<bool, ushort>),
			typeof(FlexibleDictionaryWrapper<bool, int>),
			typeof(FlexibleDictionaryWrapper<bool, uint>),
			typeof(FlexibleDictionaryWrapper<bool, long>),
			typeof(FlexibleDictionaryWrapper<bool, ulong>),
			typeof(FlexibleDictionaryWrapper<bool, char>),
			typeof(FlexibleDictionaryWrapper<bool, double>),
			typeof(FlexibleDictionaryWrapper<bool, float>),

			typeof(FlexibleDictionaryWrapper<byte, object>),
			typeof(FlexibleDictionaryWrapper<byte, bool>),
			typeof(FlexibleDictionaryWrapper<byte, byte>),
			typeof(FlexibleDictionaryWrapper<byte, sbyte>),
			typeof(FlexibleDictionaryWrapper<byte, short>),
			typeof(FlexibleDictionaryWrapper<byte, ushort>),
			typeof(FlexibleDictionaryWrapper<byte, int>),
			typeof(FlexibleDictionaryWrapper<byte, uint>),
			typeof(FlexibleDictionaryWrapper<byte, long>),
			typeof(FlexibleDictionaryWrapper<byte, ulong>),
			typeof(FlexibleDictionaryWrapper<byte, char>),
			typeof(FlexibleDictionaryWrapper<byte, double>),
			typeof(FlexibleDictionaryWrapper<byte, float>),

			typeof(FlexibleDictionaryWrapper<sbyte, object>),
			typeof(FlexibleDictionaryWrapper<sbyte, bool>),
			typeof(FlexibleDictionaryWrapper<sbyte, byte>),
			typeof(FlexibleDictionaryWrapper<sbyte, sbyte>),
			typeof(FlexibleDictionaryWrapper<sbyte, short>),
			typeof(FlexibleDictionaryWrapper<sbyte, ushort>),
			typeof(FlexibleDictionaryWrapper<sbyte, int>),
			typeof(FlexibleDictionaryWrapper<sbyte, uint>),
			typeof(FlexibleDictionaryWrapper<sbyte, long>),
			typeof(FlexibleDictionaryWrapper<sbyte, ulong>),
			typeof(FlexibleDictionaryWrapper<sbyte, char>),
			typeof(FlexibleDictionaryWrapper<sbyte, double>),
			typeof(FlexibleDictionaryWrapper<sbyte, float>),

			typeof(FlexibleDictionaryWrapper<short, object>),
			typeof(FlexibleDictionaryWrapper<short, bool>),
			typeof(FlexibleDictionaryWrapper<short, byte>),
			typeof(FlexibleDictionaryWrapper<short, sbyte>),
			typeof(FlexibleDictionaryWrapper<short, short>),
			typeof(FlexibleDictionaryWrapper<short, ushort>),
			typeof(FlexibleDictionaryWrapper<short, int>),
			typeof(FlexibleDictionaryWrapper<short, uint>),
			typeof(FlexibleDictionaryWrapper<short, long>),
			typeof(FlexibleDictionaryWrapper<short, ulong>),
			typeof(FlexibleDictionaryWrapper<short, char>),
			typeof(FlexibleDictionaryWrapper<short, double>),
			typeof(FlexibleDictionaryWrapper<short, float>),

			typeof(FlexibleDictionaryWrapper<ushort, object>),
			typeof(FlexibleDictionaryWrapper<ushort, bool>),
			typeof(FlexibleDictionaryWrapper<ushort, byte>),
			typeof(FlexibleDictionaryWrapper<ushort, sbyte>),
			typeof(FlexibleDictionaryWrapper<ushort, short>),
			typeof(FlexibleDictionaryWrapper<ushort, ushort>),
			typeof(FlexibleDictionaryWrapper<ushort, int>),
			typeof(FlexibleDictionaryWrapper<ushort, uint>),
			typeof(FlexibleDictionaryWrapper<ushort, long>),
			typeof(FlexibleDictionaryWrapper<ushort, ulong>),
			typeof(FlexibleDictionaryWrapper<ushort, char>),
			typeof(FlexibleDictionaryWrapper<ushort, double>),
			typeof(FlexibleDictionaryWrapper<ushort, float>),

			typeof(FlexibleDictionaryWrapper<int, object>),
			typeof(FlexibleDictionaryWrapper<int, bool>),
			typeof(FlexibleDictionaryWrapper<int, byte>),
			typeof(FlexibleDictionaryWrapper<int, sbyte>),
			typeof(FlexibleDictionaryWrapper<int, short>),
			typeof(FlexibleDictionaryWrapper<int, ushort>),
			typeof(FlexibleDictionaryWrapper<int, int>),
			typeof(FlexibleDictionaryWrapper<int, uint>),
			typeof(FlexibleDictionaryWrapper<int, long>),
			typeof(FlexibleDictionaryWrapper<int, ulong>),
			typeof(FlexibleDictionaryWrapper<int, char>),
			typeof(FlexibleDictionaryWrapper<int, double>),
			typeof(FlexibleDictionaryWrapper<int, float>),

			typeof(FlexibleDictionaryWrapper<uint, object>),
			typeof(FlexibleDictionaryWrapper<uint, bool>),
			typeof(FlexibleDictionaryWrapper<uint, byte>),
			typeof(FlexibleDictionaryWrapper<uint, sbyte>),
			typeof(FlexibleDictionaryWrapper<uint, short>),
			typeof(FlexibleDictionaryWrapper<uint, ushort>),
			typeof(FlexibleDictionaryWrapper<uint, int>),
			typeof(FlexibleDictionaryWrapper<uint, uint>),
			typeof(FlexibleDictionaryWrapper<uint, long>),
			typeof(FlexibleDictionaryWrapper<uint, ulong>),
			typeof(FlexibleDictionaryWrapper<uint, char>),
			typeof(FlexibleDictionaryWrapper<uint, double>),
			typeof(FlexibleDictionaryWrapper<uint, float>),

			typeof(FlexibleDictionaryWrapper<long, object>),
			typeof(FlexibleDictionaryWrapper<long, bool>),
			typeof(FlexibleDictionaryWrapper<long, byte>),
			typeof(FlexibleDictionaryWrapper<long, sbyte>),
			typeof(FlexibleDictionaryWrapper<long, short>),
			typeof(FlexibleDictionaryWrapper<long, ushort>),
			typeof(FlexibleDictionaryWrapper<long, int>),
			typeof(FlexibleDictionaryWrapper<long, uint>),
			typeof(FlexibleDictionaryWrapper<long, long>),
			typeof(FlexibleDictionaryWrapper<long, ulong>),
			typeof(FlexibleDictionaryWrapper<long, char>),
			typeof(FlexibleDictionaryWrapper<long, double>),
			typeof(FlexibleDictionaryWrapper<long, float>),

			typeof(FlexibleDictionaryWrapper<ulong, object>),
			typeof(FlexibleDictionaryWrapper<ulong, bool>),
			typeof(FlexibleDictionaryWrapper<ulong, byte>),
			typeof(FlexibleDictionaryWrapper<ulong, sbyte>),
			typeof(FlexibleDictionaryWrapper<ulong, short>),
			typeof(FlexibleDictionaryWrapper<ulong, ushort>),
			typeof(FlexibleDictionaryWrapper<ulong, int>),
			typeof(FlexibleDictionaryWrapper<ulong, uint>),
			typeof(FlexibleDictionaryWrapper<ulong, long>),
			typeof(FlexibleDictionaryWrapper<ulong, ulong>),
			typeof(FlexibleDictionaryWrapper<ulong, char>),
			typeof(FlexibleDictionaryWrapper<ulong, double>),
			typeof(FlexibleDictionaryWrapper<ulong, float>),

			typeof(FlexibleDictionaryWrapper<char, object>),
			typeof(FlexibleDictionaryWrapper<char, bool>),
			typeof(FlexibleDictionaryWrapper<char, byte>),
			typeof(FlexibleDictionaryWrapper<char, sbyte>),
			typeof(FlexibleDictionaryWrapper<char, short>),
			typeof(FlexibleDictionaryWrapper<char, ushort>),
			typeof(FlexibleDictionaryWrapper<char, int>),
			typeof(FlexibleDictionaryWrapper<char, uint>),
			typeof(FlexibleDictionaryWrapper<char, long>),
			typeof(FlexibleDictionaryWrapper<char, ulong>),
			typeof(FlexibleDictionaryWrapper<char, char>),
			typeof(FlexibleDictionaryWrapper<char, double>),
			typeof(FlexibleDictionaryWrapper<char, float>),

			typeof(FlexibleDictionaryWrapper<double, object>),
			typeof(FlexibleDictionaryWrapper<double, bool>),
			typeof(FlexibleDictionaryWrapper<double, byte>),
			typeof(FlexibleDictionaryWrapper<double, sbyte>),
			typeof(FlexibleDictionaryWrapper<double, short>),
			typeof(FlexibleDictionaryWrapper<double, ushort>),
			typeof(FlexibleDictionaryWrapper<double, int>),
			typeof(FlexibleDictionaryWrapper<double, uint>),
			typeof(FlexibleDictionaryWrapper<double, long>),
			typeof(FlexibleDictionaryWrapper<double, ulong>),
			typeof(FlexibleDictionaryWrapper<double, char>),
			typeof(FlexibleDictionaryWrapper<double, double>),
			typeof(FlexibleDictionaryWrapper<double, float>),

			typeof(FlexibleDictionaryWrapper<float, object>),
			typeof(FlexibleDictionaryWrapper<float, bool>),
			typeof(FlexibleDictionaryWrapper<float, byte>),
			typeof(FlexibleDictionaryWrapper<float, sbyte>),
			typeof(FlexibleDictionaryWrapper<float, short>),
			typeof(FlexibleDictionaryWrapper<float, ushort>),
			typeof(FlexibleDictionaryWrapper<float, int>),
			typeof(FlexibleDictionaryWrapper<float, uint>),
			typeof(FlexibleDictionaryWrapper<float, long>),
			typeof(FlexibleDictionaryWrapper<float, ulong>),
			typeof(FlexibleDictionaryWrapper<float, char>),
			typeof(FlexibleDictionaryWrapper<float, double>),
			typeof(FlexibleDictionaryWrapper<float, float>),

			typeof(FlexibleDictionaryWrapper<object, DateTime>),
			typeof(FlexibleDictionaryWrapper<DateTime, object>),

			(Action)(() => AVCloud.CallFunctionAsync<object>(null, null, null,CancellationToken.None)),
            (Action)(() => AVCloud.CallFunctionAsync<bool>(null, null,null, CancellationToken.None)),
            (Action)(() => AVCloud.CallFunctionAsync<byte>(null, null,null, CancellationToken.None)),
            (Action)(() => AVCloud.CallFunctionAsync<sbyte>(null, null,null ,CancellationToken.None)),
            (Action)(() => AVCloud.CallFunctionAsync<short>(null, null,null, CancellationToken.None)),
            (Action)(() => AVCloud.CallFunctionAsync<ushort>(null, null,null, CancellationToken.None)),
            (Action)(() => AVCloud.CallFunctionAsync<int>(null, null,null, CancellationToken.None)),
            (Action)(() => AVCloud.CallFunctionAsync<uint>(null, null,null, CancellationToken.None)),
            (Action)(() => AVCloud.CallFunctionAsync<long>(null, null, null,CancellationToken.None)),
            (Action)(() => AVCloud.CallFunctionAsync<ulong>(null, null,null ,CancellationToken.None)),
            (Action)(() => AVCloud.CallFunctionAsync<char>(null, null,null, CancellationToken.None)),
            (Action)(() => AVCloud.CallFunctionAsync<double>(null, null,null, CancellationToken.None)),
            (Action)(() => AVCloud.CallFunctionAsync<float>(null, null,null, CancellationToken.None)),
            (Action)(() => AVCloud.CallFunctionAsync<IDictionary<string, object>>(null, null,null, CancellationToken.None)),
            (Action)(() => AVCloud.CallFunctionAsync<IList<object>>(null, null,null, CancellationToken.None)),

            typeof(FlexibleListWrapper<object, AVGeoPoint>),
            typeof(FlexibleListWrapper<AVGeoPoint, object>),
            typeof(FlexibleDictionaryWrapper<object, AVGeoPoint>),
            typeof(FlexibleDictionaryWrapper<AVGeoPoint, object>),
		};
	}
  }
}
