// The provider manifest token helps to distinguish between store versions.
        // We have only one backend version.
        // However, use the connection passed in to determine whether
        // the provider is local provider or remote provider
        //
        /// <summary>
        /// Returns provider manifest token for a given connection.
        /// </summary>
        /// <param name="connection">Connection to find manifest token from.</param>
        /// <returns>The provider manifest token for the specified connection.</returns>
        protected override string GetDbProviderManifestToken(DbConnection connection)
        {
            Check.NotNull(connection, "connection");

            // vamshikb: Do we need to validate the connection and connection string
            // before returning the ProviderManifestToken????

            // Determine the type of DbConnection
            // This method should never be called at runtime, so the provider
            // must be remote provider.
            // Throw if it is none.
            //
            if (connection.GetType() == typeof(SqlCeConnection))
            {
                _isLocalProvider = true;
            }
            else if (RemoteProviderHelper.CompareObjectEqualsToType(connection, RemoteProvider.SqlCeConnection))
            {
                _isLocalProvider = false;
            }
            else
            {
                throw ADP1.Argument(EntityRes.GetString(EntityRes.Mapping_Provider_WrongConnectionType, "SqlCeConnection"));
            }

            return(SqlCeProviderManifest.Token40);
        }
        /// <summary>
        /// Returns the provider manifest by using the specified version information.
        /// </summary>
        /// <returns> The provider manifest by using the specified version information. </returns>
        /// <param name="versionHint"> The token information associated with the provider manifest. </param>
        protected override DbProviderManifest GetDbProviderManifest(string versionHint)
        {
            // This method can be called at runtime or design time.
            //

            if (string.IsNullOrEmpty(versionHint))
            {
                throw ADP1.Argument(EntityRes.GetString(EntityRes.UnableToDetermineStoreVersion));
            }

            return(_providerManifests.GetOrAdd(_isLocalProvider, l => new SqlCeProviderManifest(l)));
        }
        public override TypeUsage GetStoreType(TypeUsage edmType)
        {
            Check.NotNull(edmType, "edmType");

            Debug.Assert(edmType.EdmType.BuiltInTypeKind == BuiltInTypeKind.PrimitiveType);

            var primitiveType = edmType.EdmType as PrimitiveType;

            if (primitiveType == null)
            {
                throw ADP1.Argument(EntityRes.GetString(EntityRes.ProviderDoesNotSupportType, edmType.EdmType));
            }

            var facets = edmType.Facets;

            switch (primitiveType.PrimitiveTypeKind)
            {
            case PrimitiveTypeKind.Boolean:
                return(TypeUsage.CreateDefaultTypeUsage(StoreTypeNameToStorePrimitiveType["bit"]));

            case PrimitiveTypeKind.Byte:
                return(TypeUsage.CreateDefaultTypeUsage(StoreTypeNameToStorePrimitiveType["tinyint"]));

            case PrimitiveTypeKind.Int16:
                return(TypeUsage.CreateDefaultTypeUsage(StoreTypeNameToStorePrimitiveType["smallint"]));

            case PrimitiveTypeKind.Int32:
                return(TypeUsage.CreateDefaultTypeUsage(StoreTypeNameToStorePrimitiveType["int"]));

            case PrimitiveTypeKind.Int64:
                return(TypeUsage.CreateDefaultTypeUsage(StoreTypeNameToStorePrimitiveType["bigint"]));

            case PrimitiveTypeKind.Guid:
                return(TypeUsage.CreateDefaultTypeUsage(StoreTypeNameToStorePrimitiveType["uniqueidentifier"]));

            case PrimitiveTypeKind.Double:
                return(TypeUsage.CreateDefaultTypeUsage(StoreTypeNameToStorePrimitiveType["float"]));

            case PrimitiveTypeKind.Single:
                return(TypeUsage.CreateDefaultTypeUsage(StoreTypeNameToStorePrimitiveType["real"]));

            case PrimitiveTypeKind.Decimal:     // decimal, numeric, money
            {
                byte precision;
                if (!TypeHelpers.TryGetPrecision(edmType, out precision))
                {
                    precision = 18;
                }

                byte scale;
                if (!TypeHelpers.TryGetScale(edmType, out scale))
                {
                    scale = 0;
                }
                var tu = TypeUsage.CreateDecimalTypeUsage(StoreTypeNameToStorePrimitiveType["decimal"], precision, scale);
                return(tu);
            }

            case PrimitiveTypeKind.Binary:     // binary, varbinary, image, timestamp, rowversion
            {
                var isFixedLength = null != facets[ProviderManifest.FixedLengthFacetName].Value &&
                                    (bool)facets[ProviderManifest.FixedLengthFacetName].Value;
                var f           = facets[ProviderManifest.MaxLengthFacetName];
                var isMaxLength = Helper.IsUnboundedFacetValue(f) || null == f.Value || (int)f.Value > binaryMaxSize;
                var maxLength   = !isMaxLength ? (int)f.Value : Int32.MinValue;

                TypeUsage tu;
                if (isFixedLength)
                {
                    tu = TypeUsage.CreateBinaryTypeUsage(
                        StoreTypeNameToStorePrimitiveType["binary"], true, (isMaxLength ? binaryMaxSize : maxLength));
                }
                else
                {
                    if (null == f.Value)
                    {
                        tu = TypeUsage.CreateBinaryTypeUsage(StoreTypeNameToStorePrimitiveType["varbinary"], false, binaryMaxSize);
                    }
                    else if (Helper.IsUnboundedFacetValue(f) ||
                             edmType.EdmType.Name == "image")
                    {
                        tu = TypeUsage.CreateBinaryTypeUsage(StoreTypeNameToStorePrimitiveType["image"], false);
                    }
                    else if ((int)f.Value > binaryMaxSize)
                    {
                        throw ADP1.ColumnGreaterThanMaxLengthNotSupported(edmType.EdmType.Name, binaryMaxSize);
                    }
                    else
                    {
                        tu = TypeUsage.CreateBinaryTypeUsage(StoreTypeNameToStorePrimitiveType["varbinary"], false, maxLength);
                    }
                }
                return(tu);
            }

            case PrimitiveTypeKind.String:
                //char, nchar, varchar, nvarchar, ntext, text, xml
            {
                var isFixedLength = null != facets[ProviderManifest.FixedLengthFacetName].Value &&
                                    (bool)facets[ProviderManifest.FixedLengthFacetName].Value;
                var f = facets[ProviderManifest.MaxLengthFacetName];
                // maxlen is true if facet value is unbounded, the value is bigger than the limited string sizes *or* the facet
                // value is null. this is needed since functions still have maxlength facet value as null
                var isMaxLength = Helper.IsUnboundedFacetValue(f) || null == f.Value || (int)f.Value > (nvarcharMaxSize);
                var maxLength   = !isMaxLength ? (int)f.Value : Int32.MinValue;

                TypeUsage tu;

                if (isFixedLength)
                {
                    tu = TypeUsage.CreateStringTypeUsage(
                        StoreTypeNameToStorePrimitiveType["nchar"], true, true, (isMaxLength ? nvarcharMaxSize : maxLength));
                }
                else
                {
                    if (null == f.Value)
                    {
                        // if it is unknown, fallback to nvarchar[4000] instead of ntext since it has limited store semantics
                        tu = TypeUsage.CreateStringTypeUsage(
                            StoreTypeNameToStorePrimitiveType["nvarchar"], true, false, nvarcharMaxSize);
                    }
                    else if (Helper.IsUnboundedFacetValue(f) ||
                             edmType.EdmType.Name == "ntext")
                    {
                        tu = TypeUsage.CreateStringTypeUsage(StoreTypeNameToStorePrimitiveType["ntext"], true, false);
                    }
                    else if ((int)f.Value > nvarcharMaxSize)
                    {
                        throw ADP1.ColumnGreaterThanMaxLengthNotSupported(edmType.EdmType.Name, nvarcharMaxSize);
                    }
                    else
                    {
                        tu = TypeUsage.CreateStringTypeUsage(StoreTypeNameToStorePrimitiveType["nvarchar"], true, false, maxLength);
                    }
                }
                return(tu);
            }

            case PrimitiveTypeKind.DateTime:
                return(TypeUsage.CreateDefaultTypeUsage(StoreTypeNameToStorePrimitiveType["datetime"]));

            default:
                throw ADP1.NotSupported(
                          EntityRes.GetString(
                              EntityRes.NoStoreTypeForEdmType, TypeHelpers.GetIdentity(edmType), primitiveType.PrimitiveTypeKind));
            }
        }
        public override TypeUsage GetEdmType(TypeUsage storeType)
        {
            Check.NotNull(storeType, "storeType");

            var storeTypeName = storeType.EdmType.Name.ToLowerInvariant();

            if (!base.StoreTypeNameToEdmPrimitiveType.ContainsKey(storeTypeName))
            {
                throw ADP1.Argument(EntityRes.GetString(EntityRes.ProviderDoesNotSupportType, storeTypeName));
            }

            var edmPrimitiveType = base.StoreTypeNameToEdmPrimitiveType[storeTypeName];

            var maxLength   = 0;
            var isFixedLen  = false;
            var isUnbounded = true;

            PrimitiveTypeKind newPrimitiveTypeKind;

            switch (storeTypeName)
            {
            // for some types we just go with simple type usage with no facets
            case "tinyint":
            case "smallint":
            case "bigint":
            case "bit":
            case "uniqueidentifier":
            case "int":
                return(TypeUsage.CreateDefaultTypeUsage(edmPrimitiveType));

            case "nvarchar":
                newPrimitiveTypeKind = PrimitiveTypeKind.String;
                isUnbounded          = !TypeHelpers.TryGetMaxLength(storeType, out maxLength);
                isFixedLen           = false;
                break;

            case "nchar":
                newPrimitiveTypeKind = PrimitiveTypeKind.String;
                isUnbounded          = !TypeHelpers.TryGetMaxLength(storeType, out maxLength);
                isFixedLen           = true;
                break;

            case "ntext":
                newPrimitiveTypeKind = PrimitiveTypeKind.String;
                isUnbounded          = true;
                isFixedLen           = false;
                break;

            case "binary":
                newPrimitiveTypeKind = PrimitiveTypeKind.Binary;
                isUnbounded          = !TypeHelpers.TryGetMaxLength(storeType, out maxLength);
                isFixedLen           = true;
                break;

            case "varbinary":
                newPrimitiveTypeKind = PrimitiveTypeKind.Binary;
                isUnbounded          = !TypeHelpers.TryGetMaxLength(storeType, out maxLength);
                isFixedLen           = false;
                break;

            case "image":
                newPrimitiveTypeKind = PrimitiveTypeKind.Binary;
                isUnbounded          = true;
                isFixedLen           = false;
                break;

            case "timestamp":
            case "rowversion":
                return(TypeUsage.CreateBinaryTypeUsage(edmPrimitiveType, true, 8));

            case "float":
            case "real":
                return(TypeUsage.CreateDefaultTypeUsage(edmPrimitiveType));

            case "decimal":
            case "numeric":
            {
                byte precision;
                byte scale;
                if (TypeHelpers.TryGetPrecision(storeType, out precision) &&
                    TypeHelpers.TryGetScale(storeType, out scale))
                {
                    return(TypeUsage.CreateDecimalTypeUsage(edmPrimitiveType, precision, scale));
                }
                else
                {
                    return(TypeUsage.CreateDecimalTypeUsage(edmPrimitiveType));
                }
            }

            case "money":
                return(TypeUsage.CreateDecimalTypeUsage(edmPrimitiveType, 19, 4));

            case "datetime":
                return(TypeUsage.CreateDateTimeTypeUsage(edmPrimitiveType, null));

            default:
                throw ADP1.NotSupported(EntityRes.GetString(EntityRes.ProviderDoesNotSupportType, storeTypeName));
            }

            Debug.Assert(
                newPrimitiveTypeKind == PrimitiveTypeKind.String || newPrimitiveTypeKind == PrimitiveTypeKind.Binary,
                "at this point only string and binary types should be present");

            switch (newPrimitiveTypeKind)
            {
            case PrimitiveTypeKind.String:
                if (!isUnbounded)
                {
                    return(TypeUsage.CreateStringTypeUsage(edmPrimitiveType, /*isUnicode*/ true, isFixedLen, maxLength));
                }
                else
                {
                    return(TypeUsage.CreateStringTypeUsage(edmPrimitiveType, /*isUnicode*/ true, isFixedLen));
                }

            case PrimitiveTypeKind.Binary:
                if (!isUnbounded)
                {
                    return(TypeUsage.CreateBinaryTypeUsage(edmPrimitiveType, isFixedLen, maxLength));
                }
                else
                {
                    return(TypeUsage.CreateBinaryTypeUsage(edmPrimitiveType, isFixedLen));
                }

            default:
                throw ADP1.NotSupported(EntityRes.GetString(EntityRes.ProviderDoesNotSupportType, storeTypeName));
            }
        }