//-----------------------------------------------------------------------
// 
//     Copyright (c) Microsoft Corporation.
// 
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop
{
    using System;
    using System.Globalization;
    using System.IO;
    using Microsoft.Isam.Esent.Interop.Server2003;
    using Microsoft.Isam.Esent.Interop.Vista;
    using Microsoft.Isam.Esent.Interop.Windows7;
    /// 
    /// This class provides properties to set and get system parameters
    /// on an ESENT instance.
    /// 
    public partial class InstanceParameters
    {
        /// 
        /// The instance to set parameters on.
        /// 
        private readonly JET_INSTANCE instance;
        /// 
        /// The session to set parameters with.
        /// 
        private readonly JET_SESID sesid;
        /// 
        /// Initializes a new instance of the InstanceParameters class.
        /// 
        /// 
        /// The instance to set parameters on. If this is JET_INSTANCE.Nil,
        /// then the settings affect the default settings of future instances.
        /// 
        public InstanceParameters(JET_INSTANCE instance)
        {
            this.instance = instance;
            this.sesid = JET_SESID.Nil;
        }
        /// 
        /// Gets or sets the relative or absolute file system path of the
        /// folder that will contain the checkpoint file for the instance.
        /// 
        public string SystemDirectory
        {
            get
            {
                return Util.AddTrailingDirectorySeparator(this.GetStringParameter(JET_param.SystemPath));
            }
            set
            {
                this.SetStringParameter(JET_param.SystemPath, Util.AddTrailingDirectorySeparator(value));
            }
        }
        /// 
        /// Gets or sets the relative or absolute file system path of
        /// the folder that will contain the temporary database for the instance.
        /// 
        public string TempDirectory
        {
            get
            {
                // Older versions of Esent (e.g. Windows XP) will return the
                // full path of the temporary database. Extract the directory name.
                string path = this.GetStringParameter(JET_param.TempPath);
                string dir = Path.GetDirectoryName(path);
                return Util.AddTrailingDirectorySeparator(dir);
            }
            set
            {
                this.SetStringParameter(JET_param.TempPath, Util.AddTrailingDirectorySeparator(value));
            }
        }
        /// 
        /// Gets or sets the relative or absolute file system path of the
        /// folder that will contain the transaction logs for the instance.
        /// 
        public string LogFileDirectory
        {
            get
            {
                return Util.AddTrailingDirectorySeparator(this.GetStringParameter(JET_param.LogFilePath));
            }
            set
            {
                this.SetStringParameter(JET_param.LogFilePath, Util.AddTrailingDirectorySeparator(value));
            }
        }
        /// 
        /// Gets or sets the relative or absolute file system path of the
        /// a folder where crash recovery or a restore operation can find
        /// the databases referenced in the transaction log in the
        /// specified folder.
        /// 
        /// 
        /// This parameter is ignored on Windows XP.
        /// 
        public string AlternateDatabaseRecoveryDirectory
        {
            get
            {
                if (EsentVersion.SupportsServer2003Features)
                {
                    return
                        Util.AddTrailingDirectorySeparator(
                            this.GetStringParameter(Server2003Param.AlternateDatabaseRecoveryPath));
                }
                return null;
            }
            set
            {
                if (EsentVersion.SupportsServer2003Features)
                {
                    this.SetStringParameter(
                        Server2003Param.AlternateDatabaseRecoveryPath, Util.AddTrailingDirectorySeparator(value));
                }
            }
        }
        /// 
        /// Gets or sets the three letter prefix used for many of the files used by
        /// the database engine. For example, the checkpoint file is called EDB.CHK by
        /// default because EDB is the default base name.
        /// 
        public string BaseName
        {
            get
            {
                return this.GetStringParameter(JET_param.BaseName);
            }
            set
            {
                this.SetStringParameter(JET_param.BaseName, value);
            }
        }
        /// 
        /// Gets or sets an application specific string that will be added to
        /// any event log messages that are emitted by the database engine. This allows
        /// easy correlation of event log messages with the source application. By default
        /// the host application executable name will be used.
        /// 
        public string EventSource
        {
            get
            {
                return this.GetStringParameter(JET_param.EventSource);
            }
            set
            {
                this.SetStringParameter(JET_param.EventSource, value);
            }
        }
        /// 
        /// Gets or sets the number of sessions resources reserved for this instance.
        /// A session resource directly corresponds to a JET_SESID.
        /// 
        public int MaxSessions
        {
            get
            {
                return this.GetIntegerParameter(JET_param.MaxSessions);
            }
            set
            {
                this.SetIntegerParameter(JET_param.MaxSessions, value);
            }
        }
        /// 
        /// Gets or sets the number of B+ Tree resources reserved for this instance.
        /// 
        public int MaxOpenTables
        {
            get
            {
                return this.GetIntegerParameter(JET_param.MaxOpenTables);
            }
            set
            {
                this.SetIntegerParameter(JET_param.MaxOpenTables, value);
            }
        }
        /// 
        /// Gets or sets the number of cursor resources reserved for this instance.
        /// A cursor resource directly corresponds to a JET_TABLEID.
        /// 
        public int MaxCursors
        {
            get
            {
                return this.GetIntegerParameter(JET_param.MaxCursors);
            }
            set
            {
                this.SetIntegerParameter(JET_param.MaxCursors, value);
            }
        }
        /// 
        /// Gets or sets the maximum number of version store pages reserved
        /// for this instance.
        /// 
        public int MaxVerPages
        {
            get
            {
                return this.GetIntegerParameter(JET_param.MaxVerPages);
            }
            set
            {
                this.SetIntegerParameter(JET_param.MaxVerPages, value);
            }
        }
        /// 
        /// Gets or sets the preferred number of version store pages reserved
        /// for this instance. If the size of the version store exceeds this
        /// threshold then any information that is only used for optional
        /// background tasks, such as reclaiming deleted space in the database,
        /// is instead sacrificed to preserve room for transactional information.
        /// 
        public int PreferredVerPages
        {
            get
            {
                return this.GetIntegerParameter(JET_param.PreferredVerPages);
            }
            set
            {
                this.SetIntegerParameter(JET_param.PreferredVerPages, value);
            }
        }
        /// 
        /// Gets or sets the the number of background cleanup work items that
        /// can be queued to the database engine thread pool at any one time.
        /// 
        public int VersionStoreTaskQueueMax
        {
            get
            {
                return this.GetIntegerParameter(JET_param.VersionStoreTaskQueueMax);
            }
            set
            {
                this.SetIntegerParameter(JET_param.VersionStoreTaskQueueMax, value);
            }
        }
        /// 
        /// Gets or sets the number of temporary table resources for use
        /// by an instance. This setting will affect how many temporary tables can be used at
        /// the same time. If this system parameter is set to zero then no temporary database
        /// will be created and any activity that requires use of the temporary database will
        /// fail. This setting can be useful to avoid the I/O required to create the temporary
        /// database if it is known that it will not be used.
        /// 
        /// 
        /// The use of a temporary table also requires a cursor resource.
        /// 
        public int MaxTemporaryTables
        {
            get
            {
                return this.GetIntegerParameter(JET_param.MaxTemporaryTables);
            }
            set
            {
                this.SetIntegerParameter(JET_param.MaxTemporaryTables, value);
            }
        }
        /// 
        /// Gets or sets the size of the transaction log files. This parameter
        /// should be set in units of 1024 bytes (e.g. a setting of 2048 will
        /// give 2MB logfiles).
        /// 
        public int LogFileSize
        {
            get
            {
                return this.GetIntegerParameter(JET_param.LogFileSize);
            }
            set
            {
                this.SetIntegerParameter(JET_param.LogFileSize, value);
            }
        }
        /// 
        /// Gets or sets the amount of memory used to cache log records
        /// before they are written to the transaction log file. The unit for this
        /// parameter is the sector size of the volume that holds the transaction log files.
        /// The sector size is almost always 512 bytes, so it is safe to assume that size
        /// for the unit. This parameter has an impact on performance. When the database
        /// engine is under heavy update load, this buffer can become full very rapidly.
        /// A larger cache size for the transaction log file is critical for good update
        /// performance under such a high load condition. The default is known to be too small
        /// for this case.
        /// Do not set this parameter to a number of buffers that is larger (in bytes) than
        /// half the size of a transaction log file.
        /// 
        public int LogBuffers
        {
            get
            {
                return this.GetIntegerParameter(JET_param.LogBuffers);
            }
            set
            {
                this.SetIntegerParameter(JET_param.LogBuffers, value);
            }
        }
        /// 
        /// Gets or sets a value indicating whether circular logging is on.
        /// When circular logging is off, all transaction log files that are generated
        /// are retained on disk until they are no longer needed because a full backup of the
        /// database has been performed. When circular logging is on, only transaction log files
        /// that are younger than the current checkpoint are retained on disk. The benefit of
        /// this mode is that backups are not required to retire old transaction log files. 
        /// 
        public bool CircularLog
        {
            get
            {
                return this.GetBoolParameter(JET_param.CircularLog);
            }
            set
            {
                this.SetBoolParameter(JET_param.CircularLog, value);
            }
        }
        /// 
        /// Gets or sets a value indicating whether JetInit fails when the database
        /// engine is configured to start using transaction log files on disk
        /// that are of a different size than what is configured. Normally,
        ///  will successfully recover the databases
        /// but will fail with 
        /// to indicate that the log file size is misconfigured. However, when
        /// this parameter is set to true then the database engine will silently
        /// delete all the old log files, start a new set of transaction log files
        /// using the configured log file size. This parameter is useful when the
        /// application wishes to transparently change its transaction log file
        /// size yet still work transparently in upgrade and restore scenarios.
        /// 
        public bool CleanupMismatchedLogFiles
        {
            get
            {
                return this.GetBoolParameter(JET_param.CleanupMismatchedLogFiles);
            }
            set
            {
                this.SetBoolParameter(JET_param.CleanupMismatchedLogFiles, value);
            }
        }
        /// 
        /// Gets or sets the initial size of the temporary database. The size is in
        /// database pages. A size of zero indicates that the default size of an ordinary
        /// database should be used. It is often desirable for small applications to configure
        /// the temporary database to be as small as possible. Setting this parameter to
        ///  will achieve the smallest
        /// temporary database possible.
        /// 
        public int PageTempDBMin
        {
            get
            {
                return this.GetIntegerParameter(JET_param.PageTempDBMin);
            }
            set
            {
                this.SetIntegerParameter(JET_param.PageTempDBMin, value);
            }
        }
        /// 
        /// Gets or sets the threshold in bytes for about how many transaction log
        /// files will need to be replayed after a crash. If circular logging is enabled using
        /// CircularLog then this parameter will also control the approximate amount
        /// of transaction log files that will be retained on disk.
        /// 
        public int CheckpointDepthMax
        {
            get
            {
                return this.GetIntegerParameter(JET_param.CheckpointDepthMax);
            }
            set
            {
                this.SetIntegerParameter(JET_param.CheckpointDepthMax, value);
            }
        }
        /// 
        /// Gets or sets the number of pages that are added to a database file each
        /// time it needs to grow to accommodate more data.
        /// 
        public int DbExtensionSize
        {
            get
            {
                return this.GetIntegerParameter(JET_param.DbExtensionSize);
            }
            set
            {
                this.SetIntegerParameter(JET_param.DbExtensionSize, value);
            }
        }
        /// 
        /// Gets or sets a value indicating whether crash recovery is on.
        /// 
        public bool Recovery
        {
            get
            {
                return 0 == string.Compare(this.GetStringParameter(JET_param.Recovery), "on", StringComparison.OrdinalIgnoreCase);
            }
            set
            {
                if (value)
                {
                    this.SetStringParameter(JET_param.Recovery, "on");
                }
                else
                {
                    this.SetStringParameter(JET_param.Recovery, "off");
                }
            }
        }
        /// 
        /// Gets or sets a value indicating whether online defragmentation is enabled.
        /// 
        public bool EnableOnlineDefrag
        {
            get
            {
                return this.GetBoolParameter(JET_param.EnableOnlineDefrag);
            }
            set
            {
                this.SetBoolParameter(JET_param.EnableOnlineDefrag, value);
            }
        }
        /// 
        /// Gets or sets a value indicating whether  will check for
        /// indexes that were build using an older version of the NLS library in the
        /// operating system.
        /// 
        public bool EnableIndexChecking
        {
            get
            {
                return this.GetBoolParameter(JET_param.EnableIndexChecking);
            }
            set
            {
                this.SetBoolParameter(JET_param.EnableIndexChecking, value);
            }
        }
        /// 
        /// Gets or sets the name of the event log the database engine uses for its event log
        /// messages. By default, all event log messages will go to the Application event log. If the registry
        /// key name for another event log is configured then the event log messages will go there instead.
        ///   
        public string EventSourceKey
        {
            get
            {
                return this.GetStringParameter(JET_param.EventSourceKey);  
            }
            set
            {
                this.SetStringParameter(JET_param.EventSourceKey, value);
            }
        }
        /// 
        /// Gets or sets a value indicating whether informational event 
        /// log messages that would ordinarily be generated by the
        /// database engine will be suppressed.
        /// 
        public bool NoInformationEvent
        {
            get
            {
                return this.GetBoolParameter(JET_param.NoInformationEvent);
            }
            set
            {
                this.SetBoolParameter(JET_param.NoInformationEvent, value);
            }
        }
        /// 
        /// Gets or sets the detail level of eventlog messages that are emitted
        /// to the eventlog by the database engine. Higher numbers will result
        /// in more detailed eventlog messages.
        /// 
        public EventLoggingLevels EventLoggingLevel
        {
            get
            {
                return (EventLoggingLevels)this.GetIntegerParameter(JET_param.EventLoggingLevel);
            }
            set
            {
                this.SetIntegerParameter(JET_param.EventLoggingLevel, (int)value);
            }
        }
        /// 
        /// Gets or sets a value indicating whether only one database is allowed to
        /// be opened using JetOpenDatabase by a given session at one time.
        /// The temporary database is excluded from this restriction. 
        /// 
        public bool OneDatabasePerSession
        {
            get
            {
                return this.GetBoolParameter(JET_param.OneDatabasePerSession);
            }
            set
            {
                this.SetBoolParameter(JET_param.OneDatabasePerSession, value);
            }
        }
        /// 
        /// Gets or sets a value indicating whether ESENT will silently create folders
        /// that are missing in its filesystem paths.
        /// 
        public bool CreatePathIfNotExist
        {
            get
            {
                return this.GetBoolParameter(JET_param.CreatePathIfNotExist);
            }
            set
            {
                this.SetBoolParameter(JET_param.CreatePathIfNotExist, value);
            }
        }
        /// 
        /// Gets or sets a value giving the number of B+ Tree resources cached by
        /// the instance after the tables they represent have been closed by
        /// the application. Large values for this parameter will cause the
        /// database engine to use more memory but will increase the speed
        /// with which a large number of tables can be opened randomly by
        /// the application. This is useful for applications that have a
        /// schema with a very large number of tables.
        /// 
        /// Supported on Windows Vista and up. Ignored on Windows XP and
        /// Windows Server 2003.
        /// 
        /// 
        public int CachedClosedTables
        {
            get
            {
                if (EsentVersion.SupportsVistaFeatures)
                {
                    return this.GetIntegerParameter(VistaParam.CachedClosedTables);
                }
                return 0;
            }
            set
            {
                if (EsentVersion.SupportsVistaFeatures)
                {
                    this.SetIntegerParameter(VistaParam.CachedClosedTables, value);
                }
            }
        }
        /// 
        /// Gets or sets a the number of logs that esent will defer database
        /// flushes for. This can be used to increase database recoverability if
        /// failures cause logfiles to be lost.
        /// 
        /// Supported on Windows 7 and up. Ignored on Windows XP,
        /// Windows Server 2003, Windows Vista and Windows Server 2008.
        /// 
        /// 
        public int WaypointLatency
        {
            get
            {
                if (EsentVersion.SupportsWindows7Features)
                {
                    return this.GetIntegerParameter(Windows7Param.WaypointLatency);
                }
                // older versions have no waypoint
                return 0;
            }
            set
            {
                if (EsentVersion.SupportsWindows7Features)
                {
                    this.SetIntegerParameter(Windows7Param.WaypointLatency, value);
                }
            }
        }
        /// 
        /// Gets or sets a value indicating whether  will
        /// delete indexes that were build using an older version of the NLS library in the
        /// operating system.
        /// 
        public bool EnableIndexCleanup
        {
            get
            {
                return this.GetBoolParameter(JET_param.EnableIndexCleanup);
            }
        
            set
            {
                this.SetBoolParameter(JET_param.EnableIndexCleanup, value);
            }
        }
        /// 
        /// Returns a  that represents the current .
        /// 
        /// 
        /// A  that represents the current .
        /// 
        public override string ToString()
        {
            return string.Format(CultureInfo.InvariantCulture, "InstanceParameters (0x{0:x})", this.instance.Value);
        }
        /// 
        /// Set a system parameter which is a string.
        /// 
        /// The parameter to set.
        /// The value to set.
        private void SetStringParameter(JET_param param, string value)
        {
            Api.JetSetSystemParameter(this.instance, this.sesid, param, 0, value);
        }
        /// 
        /// Get a system parameter which is a string.
        /// 
        /// The parameter to get.
        /// The value of the parameter.
        private string GetStringParameter(JET_param param)
        {
            int ignored = 0;
            string value;
            Api.JetGetSystemParameter(this.instance, this.sesid, param, ref ignored, out value, 1024);
            return value;
        }
        /// 
        /// Set a system parameter which is an integer.
        /// 
        /// The parameter to set.
        /// The value to set.
        private void SetIntegerParameter(JET_param param, int value)
        {
            Api.JetSetSystemParameter(this.instance, this.sesid, param, value, null);
        }
        /// 
        /// Get a system parameter which is an integer.
        /// 
        /// The parameter to get.
        /// The value of the parameter.
        private int GetIntegerParameter(JET_param param)
        {
            int value = 0;
            string ignored;
            Api.JetGetSystemParameter(this.instance, this.sesid, param, ref value, out ignored, 0);
            return value;
        }
        /// 
        /// Set a system parameter which is a boolean.
        /// 
        /// The parameter to set.
        /// The value to set.
        private void SetBoolParameter(JET_param param, bool value)
        {
            if (value)
            {
                Api.JetSetSystemParameter(this.instance, this.sesid, param, 1, null);
            }
            else
            {
                Api.JetSetSystemParameter(this.instance, this.sesid, param, 0, null);
            }
        }
        /// 
        /// Get a system parameter which is a boolean.
        /// 
        /// The parameter to get.
        /// The value of the parameter.
        private bool GetBoolParameter(JET_param param)
        {
            int value = 0;
            string ignored;
            Api.JetGetSystemParameter(this.instance, this.sesid, param, ref value, out ignored, 0);
            return value != 0;
        }
    }
}