//
// IOStatsDatabaseMapper.cs
//
// Author:
//       Carsten Sonne Larsen <cs@innolan.dk>
//
// Copyright (c) 2013 Carsten Sonne Larsen
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
using System.Collections.Generic;
using MySql.Data.MySqlClient;
using Ntp.Analyzer.Log;
using Ntp.Analyzer.Objects;
using Ntp.Analyzer.Objects.Live;

namespace Ntp.Analyzer.Data.Static
{
    public sealed class HostIOReadingDatabaseMapper : FilteredMapper<HostIOReading>
    {
        internal HostIOReadingDatabaseMapper (HostDatabaseMapper hostMapper, LogBase log)
            : base(log)
        {
            this.hostMapper = hostMapper;
        }

        private readonly HostDatabaseMapper hostMapper;

        protected override bool UseCache {
            get { return false; }
        }

        protected override string TableName {
            get { return "hostIoReading"; }
        }

        protected override string CreateSql {
            get {
                return
                    "CREATE TABLE hostIoReading ( " +
                    "    id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, " +
                    "    time  TIMESTAMP NOT NULL, " +
                    "    hostId INT NOT NULL, " +
                    "    timeSinceReset INT NOT NULL, " +
                    "    receiveBuffers INT NOT NULL, " +
                    "    freeReceiveBuffers INT NOT NULL, " +
                    "    usedReceiveBuffers INT NOT NULL, " +
                    "    lowWaterRefills INT NOT NULL, " +
                    "    droppedPackets INT NOT NULL, " +
                    "    ignoredPackets INT NOT NULL, " +
                    "    receivedPackets INT NOT NULL, " +
                    "    packetsSent INT NOT NULL, " +
                    "    packetsNotSent INT NOT NULL, " +
                    "    interruptsHandled INT NOT NULL, " +
                    "    receivedByInt INT NOT NULL, " +
                    "    FOREIGN KEY (hostId) REFERENCES host(id) " +
                    ") ENGINE=INNODB;";
            }
        }

        private const string selectSql =
            "SELECT " +
            "id, time, hostId, timeSinceReset, " +
            "receiveBuffers, freeReceiveBuffers, usedReceiveBuffers, lowWaterRefills, " +
            "droppedPackets, ignoredPackets, receivedPackets, " +
            "packetsSent, packetsNotSent, interruptsHandled, receivedByInt " +
            "FROM hostIoReading ";
        private const string insertSql =
            "INSERT INTO hostIoReading ( " +
            "time, hostId, timeSinceReset, " +
            "receiveBuffers, freeReceiveBuffers, usedReceiveBuffers, lowWaterRefills, " +
            "droppedPackets, ignoredPackets, receivedPackets, " +
            "packetsSent, packetsNotSent, interruptsHandled, receivedByInt) " +
            "VALUES ( " +
            "?time, ?hostId, ?timeSinceReset, " +
            "?receiveBuffers, ?freeReceiveBuffers, ?usedReceiveBuffers, ?lowWaterRefills, " +
            "?droppedPackets, ?ignoredPackets, ?receivedPackets, " +
            "?packetsSent, ?packetsNotSent, ?interruptsHandled, ?receivedByInt); " +
            "SELECT LAST_INSERT_ID();";

        protected override void Insert (HostIOReading item)
        {
            lock (Locker) {
                try {
                    Open ();

                    Command.CommandText = insertSql;
                    Command.Prepare ();
                    Command.Parameters.AddWithValue ("?time", item.Time);
                    Command.Parameters.AddWithValue ("?hostId", item.Host.Id);
                    Command.Parameters.AddWithValue ("?timeSinceReset", item.TimeSinceReset);
                    Command.Parameters.AddWithValue ("?receiveBuffers", item.ReceiveBuffers);
                    Command.Parameters.AddWithValue ("?freeReceiveBuffers", item.FreeReceiveBuffers);
                    Command.Parameters.AddWithValue ("?usedReceiveBuffers", item.UsedReceiveBuffers);
                    Command.Parameters.AddWithValue ("?lowWaterRefills", item.LowWaterRefills);
                    Command.Parameters.AddWithValue ("?droppedPackets", item.DroppedPackets);
                    Command.Parameters.AddWithValue ("?ignoredPackets", item.IgnoredPackets);
                    Command.Parameters.AddWithValue ("?receivedPackets", item.ReceivedPackets);
                    Command.Parameters.AddWithValue ("?packetsSent", item.PacketsSent);
                    Command.Parameters.AddWithValue ("?packetsNotSent", item.PacketsNotSent);
                    Command.Parameters.AddWithValue ("?interruptsHandled", item.InterruptsHandled);
                    Command.Parameters.AddWithValue ("?receivedByInt", item.ReceivedByInt);

                    object idObject = Command.ExecuteScalar ();
                    item.SetId (Convert.ToInt32 (idObject));
                } finally {
                    Close ();
                }
            }
        }

        protected override void Update (HostIOReading item)
        {
            throw new NotSupportedException ("Updating rows in hostIoReading table is not supported.");
        }

        /// <summary>
        /// Read all data from table in a sequential manner.
        /// </summary>
        /// <returns>The enumerator.</returns>
        public override IEnumerator<HostIOReading> GetEnumerator ()
        {
            lock (Locker) {
                string sql = selectSql;

                if (FilterHost != null)
                    sql += " WHERE hostId = " + FilterHost.Id;

                if (FilterTime != null)
                    sql += " AND time > '" + FilterTime.Value.ToString ("yyyy-MM-dd HH:mm") + "'";

                try {
                    Open ();
                    Command.CommandText = sql;
                    Reader = Command.ExecuteReader ();

                    while (Reader.Read ()) {
                        int id = Convert.ToInt32 (Reader ["id"]);
                        DateTime time = Convert.ToDateTime (Reader ["time"]);
                        int hostId = Convert.ToInt32 (Reader ["hostId"]);
                        Host host = hostMapper [hostId];
                        int timeSinceReset = Convert.ToInt32 (Reader ["timeSinceReset"]);
                        int receiveBuffers = Convert.ToInt32 (Reader ["receiveBuffers"]);
                        int freeReceiveBuffers = Convert.ToInt32 (Reader ["freeReceiveBuffers"]);
                        int usedReceiveBuffers = Convert.ToInt32 (Reader ["usedReceiveBuffers"]);
                        int lowWaterRefills = Convert.ToInt32 (Reader ["lowWaterRefills"]);
                        int droppedPackets = Convert.ToInt32 (Reader ["droppedPackets"]);
                        int ignoredPackets = Convert.ToInt32 (Reader ["ignoredPackets"]);
                        int receivedPackets = Convert.ToInt32 (Reader ["receivedPackets"]);
                        int packetsSent = Convert.ToInt32 (Reader ["packetsSent"]);
                        int packetsNotSent = Convert.ToInt32 (Reader ["packetsNotSent"]);
                        int interruptsHandled = Convert.ToInt32 (Reader ["interruptsHandled"]);
                        int receivedByInt = Convert.ToInt32 (Reader ["receivedByInt"]);

                        HostIOReading reading = 
                        new HostIOReading (
                            id, time, host, timeSinceReset,
                            receiveBuffers, freeReceiveBuffers, usedReceiveBuffers, lowWaterRefills,
                            droppedPackets, ignoredPackets, receivedPackets,
                            packetsSent, packetsNotSent,
                            interruptsHandled, receivedByInt);

                        yield return reading;
                    }
                } finally {
                    Close ();
                }
            }
        }
    }
}
