//using LevelDB;
//using STS.General.Generators;
//using System;
//using DatabaseBenchmark.Core;
//using System.Collections.Generic;
//using System.ComponentModel;
//using System.Drawing;
//using System.IO;
//using System.Xml.Serialization;
//using DatabaseBenchmark.Core.Attributes;

//namespace DatabaseBenchmark.Databases
//{
//    public class LevelDBDatabase : Database
//    {
//        private DB database;
//        private Options options;

//        public override string IndexingTechnology
//        {
//            get { return "LSMTree"; }
//        }

//        // Any internal progress/error information generated by the db will
//        // be written to info_log if it is non-NULL, or to a file stored
//        // in the same directory as the DB contents if info_log is NULL.

//        /// <summary>
//        /// Amount of data to build up in memory (backed by an unsorted log
//        /// on disk) before converting to a sorted on-disk file.
//        ///
//        /// Larger values increase performance, especially during bulk loads.
//        /// Up to two write buffers may be held in memory at the same time,
//        /// so you may wish to adjust this parameter to control memory usage.
//        /// Also, a larger write buffer will result in a longer recovery time
//        /// the next time the database is opened.
//        ///
//        /// Default: 4MB
//        /// </summary>
//        [Category("Settings")]
//        [DbParameter]
//        public long WriteBufferSize { get; set; }

//        /// <summary>
//        /// Control over blocks (user data is stored in a set of blocks, and
//        /// a block is the unit of reading from disk).
//        ///
//        /// If not set, leveldb will automatically create and use an 8MB internal cache.
//        /// </summary>
//        [Category("Settings")]
//        [DbParameter]
//        public int Cache { get; set; }

//        /// <summary>
//        /// Approximate size of user data packed per block.  Note that the
//        /// block size specified here corresponds to uncompressed data.  The
//        /// actual size of the unit read from disk may be smaller if
//        /// compression is enabled.  This parameter can be changed dynamically.
//        ///
//        /// Default: 4K
//        /// </summary>
//        [Category("Settings")]
//        [DbParameter]
//        public long BlockSize { get; set; }

//        /// <summary>
//        /// Number of open files that can be used by the DB.  You may need to
//        /// increase this if your database has a large working set (budget
//        /// one open file per 2MB of working set).
//        ///
//        /// Default: 1000
//        /// </summary>
//        [Category("Settings")]
//        [DbParameter]
//        public int MaxOpenFiles { get; set; }

//        /// <summary>
//        /// Enables SnappyCompression.
//        /// </summary>
//        [Category("Settings")]
//        [DbParameter]
//        public CompressionLevel Compression { get; set; }

//        public LevelDBDatabase()
//        {
//            SyncRoot = new object();

//            Name = "LevelDB";
//            CollectionName = "table1";
//            Category = "NoSQL\\Key-Value Store";
//            Description = "LevelDB.NET.dll built from http://leveldb.angeloflogic.com/";
//            Website = "http://leveldb.org/";
//            Color = Color.LightGreen;

//            Requirements = new string[]
//            { 
//                "LevelDB.NET.dll" 
//            };

//            BlockSize = 4 * 1024;
//            Cache = 100 * 1024 * 1024;
//            WriteBufferSize = 4 * 1024 * 1024;
//            MaxOpenFiles = 1000;
//            Compression = CompressionLevel.NoCompression;
//        }

//        public override void Open(int flowCount, long flowRecordCount)
//        {
//            options = new Options()
//            {
//                CreateIfMissing = true,
//                BlockSize = BlockSize,
//                Cache = new Cache(Cache),
//                WriteBufferSize = WriteBufferSize,
//                MaxOpenFiles = MaxOpenFiles,
//                CompressionLevel = Compression
//            };

//            database = new DB(Path.Combine(DataDirectory, CollectionName), options);
//        }

//        public override void Write(int flowID, IEnumerable<KeyValuePair<long, Tick>> flow)
//        {
//            lock (SyncRoot)
//            {
//                foreach (var kv in flow)
//                {
//                    byte[] key = Direct(kv.Key);
//                    var rec = FromTick(kv.Value);

//                    database.Put(key, rec);
//                }
//            }
//        }

//        public override IEnumerable<KeyValuePair<long, Tick>> Read()
//        {
//            using (var iterator = database.CreateIterator())
//            {
//                for (iterator.SeekToFirst(); iterator.IsValid(); iterator.Next())
//                {
//                    byte[] key = iterator.GetKey();
//                    byte[] value = iterator.GetValue();

//                    var ID = Reverse(key);
//                    var rec = ToTick(value);

//                    yield return new KeyValuePair<long, Tick>(ID, rec);
//                }
//            }
//        }

//        public override void Close()
//        {
//            database.Dispose();
//        }

//        #region Helper Methods

//        private byte[] FromTick(Tick tick)
//        {
//            using (MemoryStream stream = new MemoryStream())
//            {
//                BinaryWriter writer = new BinaryWriter(stream);

//                writer.Write(tick.Symbol);
//                writer.Write(tick.Timestamp.Ticks);
//                writer.Write(tick.Bid);
//                writer.Write(tick.Ask);
//                writer.Write(tick.BidSize);
//                writer.Write(tick.AskSize);
//                writer.Write(tick.Provider);

//                return stream.ToArray();
//            }
//        }

//        private Tick ToTick(byte[] value)
//        {
//            Tick tick = new Tick();

//            using (MemoryStream stream = new MemoryStream(value))
//            {
//                BinaryReader reader = new BinaryReader(stream);

//                tick.Symbol = reader.ReadString();
//                tick.Timestamp = new DateTime(reader.ReadInt64());
//                tick.Bid = reader.ReadDouble();
//                tick.Ask = reader.ReadDouble();
//                tick.BidSize = reader.ReadInt32();
//                tick.AskSize = reader.ReadInt32();
//                tick.Provider = reader.ReadString();
//            }

//            return tick;
//        }

//        private byte[] Direct(Int64 key)
//        {
//            ulong val = (UInt64)(key + Int64.MaxValue + 1);
//            var index = BitConverter.GetBytes(val);

//            byte[] buf = new byte[8];
//            buf[0] = index[7];
//            buf[1] = index[6];
//            buf[2] = index[5];
//            buf[3] = index[4];
//            buf[4] = index[3];
//            buf[5] = index[2];
//            buf[6] = index[1];
//            buf[7] = index[0];

//            return buf;
//        }

//        private Int64 Reverse(byte[] index)
//        {
//            byte[] buf = new byte[8];
//            buf[0] = index[7];
//            buf[1] = index[6];
//            buf[2] = index[5];
//            buf[3] = index[4];
//            buf[4] = index[3];
//            buf[5] = index[2];
//            buf[6] = index[1];
//            buf[7] = index[0];

//            UInt64 val = BitConverter.ToUInt64(buf, 0);

//            return (Int64)(val - (UInt64)Int64.MaxValue - 1);
//        }

//        #endregion
//    }
//}
