/*-
 * See the file LICENSE for redistribution information.
 *
 * Copyright (c) 2009 Oracle.  All rights reserved.
 *
 */
using System;
using System.Collections.Generic;
using System.Text;

using BerkeleyDB.Internal;

namespace BerkeleyDB {
    /// <summary>
    /// A class representing configuration parameters for
    /// <see cref="BTreeDatabase"/>
    /// </summary>
    public class BTreeDatabaseConfig : DatabaseConfig {
        /* Fields for DB->set_flags() */
        /// <summary>
        /// Policy for duplicate data items in the database; that is, insertion
        /// when the key of the key/data pair being inserted already exists in
        /// the database will be successful.
        /// </summary>
        /// <remarks>
        /// <para>The ordering of duplicates in the database for
        /// <see cref="DuplicatesPolicy.UNSORTED"/> is determined by the order
        /// of insertion, unless the ordering is otherwise specified by use of a
        /// cursor operation or a duplicate sort function. The ordering of
        /// duplicates in the database for
        /// <see cref="DuplicatesPolicy.SORTED"/> is determined by the
        /// duplicate comparison function. If the application does not specify a
        /// comparison function using 
        /// <see cref="DuplicateCompare"/>, a default lexical
        /// comparison will be used.
        /// </para>
        /// <para>
        /// <see cref="DuplicatesPolicy.SORTED"/> is preferred to 
        /// <see cref="DuplicatesPolicy.UNSORTED"/> for performance reasons.
        /// <see cref="DuplicatesPolicy.UNSORTED"/> should only be used by
        /// applications wanting to order duplicate data items manually.
        /// </para>
        /// <para>
        /// If the database already exists, the value of Duplicates must be the
        /// same as the existing database or an error will be returned.
        /// </para>
        /// <para>
        /// It is an error to specify <see cref="UseRecordNumbers"/> and
        /// anything other than <see cref="DuplicatesPolicy.NONE"/>.
        /// </para>
        /// </remarks>
        public DuplicatesPolicy Duplicates;
        /// <summary>
        /// Turn reverse splitting in the Btree on or off.
        /// </summary>
        /// <remarks>
        /// As pages are emptied in a database, the Berkeley DB Btree
        /// implementation attempts to coalesce empty pages into higher-level
        /// pages in order to keep the database as small as possible and
        /// minimize search time. This can hurt performance in applications with
        /// cyclical data demands; that is, applications where the database
        /// grows and shrinks repeatedly. For example, because Berkeley DB does
        /// page-level locking, the maximum level of concurrency in a database
        /// of two pages is far smaller than that in a database of 100 pages, so
        /// a database that has shrunk to a minimal size can cause severe
        /// deadlocking when a new cycle of data insertion begins. 
        /// </remarks>
        public bool NoReverseSplitting;
        /// <summary>
        /// If true, support retrieval from the Btree using record numbers.
        /// </summary>
        /// <remarks>
        /// <para>
        /// Logical record numbers in Btree databases are mutable in the face of
        /// record insertion or deletion. See
        /// <see cref="RecnoDatabaseConfig.Renumber"/> for further discussion.
        /// </para>
		/// <para>
        /// Maintaining record counts within a Btree introduces a serious point
        /// of contention, namely the page locations where the record counts are
        /// stored. In addition, the entire database must be locked during both
        /// insertions and deletions, effectively single-threading the database
        /// for those operations. Specifying UseRecordNumbers can result in
        /// serious performance degradation for some applications and data sets.
        /// </para>
		/// <para>
        /// It is an error to specify <see cref="UseRecordNumbers"/> and
        /// anything other than <see cref="DuplicatesPolicy.NONE"/>.
        /// </para>
		/// <para>
        /// If the database already exists, the value of UseRecordNumbers must
        /// be the same as the existing database or an error will be returned. 
        /// </para>
        /// </remarks>
        public bool UseRecordNumbers;
        internal new uint flags {
            get {
                uint ret = base.flags;
                ret |= (uint)Duplicates;
                ret |= NoReverseSplitting ?
                    Internal.DbConstants.DB_REVSPLITOFF : 0;
                ret |= UseRecordNumbers ? Internal.DbConstants.DB_RECNUM : 0;
                return ret;
            }
        }

        /// <summary>
        /// The policy for how to handle database creation.
        /// </summary>
        /// <remarks>
        /// If the database does not already exist and
        /// <see cref="CreatePolicy.NEVER"/> is set,
        /// <see cref="BTreeDatabase.Open"/> will fail.
        /// </remarks>
        public CreatePolicy Creation;
        internal new uint openFlags {
            get {
                uint flags = base.openFlags;
                flags |= (uint)Creation;
                return flags;
            }
        }

        /// <summary>
        /// The Btree key comparison function.
        /// </summary>
        /// <remarks>
        /// <para>
        /// The comparison function is called whenever it is necessary to
        /// compare a key specified by the application with a key currently
        /// stored in the tree.
        /// </para>
		/// <para>
        /// If no comparison function is specified, the keys are compared
        /// lexically, with shorter keys collating before longer keys.
        /// </para>
		/// <para>
        /// If the database already exists, the comparison function must be the
        /// same as that historically used to create the database or corruption
        /// can occur. 
        /// </para>
        /// </remarks>
        public EntryComparisonDelegate BTreeCompare;
        /// <summary>
        /// The Btree prefix function.
        /// </summary>
        /// <remarks>
        /// <para>
        /// The prefix function is used to determine the amount by which keys
        /// stored on the Btree internal pages can be safely truncated without
        /// losing their uniqueness. See the Btree prefix comparison section of
        /// the Berkeley DB Reference Guide for more details about how this
        /// works. The usefulness of this is data-dependent, but can produce
        /// significantly reduced tree sizes and search times in some data sets.
        /// </para>
		/// <para>
        /// If no prefix function or key comparison function is specified by the
        /// application, a default lexical comparison function is used as the
        /// prefix function. If no prefix function is specified and
        /// <see cref="BTreeCompare"/> is specified, no prefix function is
        /// used. It is an error to specify a prefix function without also
        /// specifying <see cref="BTreeCompare"/>. 
        /// </para>
		/// <para>
        /// If the database already exists, the prefix function must be the
        /// same as that historically used to create the database or corruption
        /// can occur. 
        /// </para>
        /// </remarks>
        public EntryComparisonDelegate BTreePrefixCompare;
        /// <summary>
        /// The duplicate data item comparison function.
        /// </summary>
        /// <remarks>
        /// <para>
        /// The comparison function is called whenever it is necessary to
        /// compare a data item specified by the application with a data item
        /// currently stored in the database. Setting DuplicateCompare implies 
        /// setting <see cref="Duplicates"/> to
        /// <see cref="DuplicatesPolicy.SORTED"/>.
        /// </para>
		/// <para>
        /// If no comparison function is specified, the data items are compared
        /// lexically, with shorter data items collating before longer data
        /// items.
        /// </para>
		/// <para>
        /// If the database already exists when
        /// <see cref="BTreeDatabase.Open"/> is called, the
        /// delegate must be the same as that historically used to create the
        /// database or corruption can occur.
        /// </para>
        /// </remarks>
        public EntryComparisonDelegate DuplicateCompare;

	internal bool compressionIsSet;
        private BTreeCompressDelegate compressFunc;
        /// <summary>
        /// The compression function used to store key/data pairs in the
        /// database.
        /// </summary>
        public BTreeCompressDelegate Compress { get { return compressFunc; } }
        private BTreeDecompressDelegate decompressFunc;
        /// <summary>
        /// The decompression function used to retrieve key/data pairs from the
        /// database.
        /// </summary>
        public BTreeDecompressDelegate Decompress {
            get { return decompressFunc; }
        }
        /// <summary>
        /// Enable compression of the key/data pairs stored in the database,
        /// using the default compression and decompression functions.
        /// </summary>
        /// <remarks>
        /// The default functions perform prefix compression on keys, and prefix
        /// compression on data items for duplicate keys.
        /// </remarks>
        public void SetCompression() {
            compressionIsSet = true;
            compressFunc = null;
            decompressFunc = null;
        }
        /// <summary>
        /// Enable compression of the key/data pairs stored in the database,
        /// using the specified compression and decompression functions.
        /// </summary>
        /// <param name="compression">The compression function</param>
        /// <param name="decompression">The decompression function</param>
        public void SetCompression(BTreeCompressDelegate compression,
            BTreeDecompressDelegate decompression) {
            compressionIsSet = true;
            compressFunc = compression;
            decompressFunc = decompression;
        }

        internal bool minkeysIsSet;
        private uint minKeys;
        /// <summary>
        /// The minimum number of key/data pairs intended to be stored on any
        /// single Btree leaf page.
        /// </summary>
        /// <remarks>
        /// <para>
        /// This value is used to determine if key or data items will be stored
        /// on overflow pages instead of Btree leaf pages. For more information
        /// on the specific algorithm used, see the Berkeley DB Reference Guide.
        /// The value specified must be at least 2; if not explicitly set, a
        /// value of 2 is used. 
        /// </para>
		/// <para>
        /// If the database already exists, MinKeysPerPage will be ignored. 
        /// </para>
        /// </remarks>
        public uint MinKeysPerPage {
            get { return minKeys; }
            set {
                minkeysIsSet = true;
                minKeys = value;
            }
        }

        /// <summary>
        /// Create a new BTreeDatabaseConfig object
        /// </summary>
        public BTreeDatabaseConfig() {
            Duplicates = DuplicatesPolicy.NONE;
            NoReverseSplitting = false;
            UseRecordNumbers = false;

            BTreeCompare = null;
            BTreePrefixCompare = null;

            minkeysIsSet = false;

            Creation = CreatePolicy.NEVER;
        }
    }
}