
using System;
using System.ComponentModel;
using System.Windows.Forms;
using System.Net;
using System.IO;
using System.Threading;
using System.Diagnostics;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Globalization;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using ScoutBase;
using ScoutBase.Core;
using System.Data.SQLite;
using System.Text;

namespace AirScout.AircraftPositions
{

    #region AircraftPositionDatabaseMaintainer


    public class AircraftPositionDatabaseMaintainerStartOptions
    {
        public string Name;
        public double Database_MaxSize;
        public long Database_MaxCount;
        public int Database_MaxDaysLifetime;
    }


    // Background worker for aircraft position database maintainance
    [DefaultPropertyAttribute("Name")]
    public class AircraftPositionDatabaseMaintainer : BackgroundWorker
    {

        AircraftPositionDatabaseMaintainerStartOptions StartOptions;
        double DBLastSize = 0;

        public AircraftPositionDatabaseMaintainer() : base()
        {
            this.WorkerReportsProgress = true;
            this.WorkerSupportsCancellation = true;
        }

        protected override void OnDoWork(DoWorkEventArgs e)
        {
            StartOptions = (AircraftPositionDatabaseMaintainerStartOptions)e.Argument;
            this.ReportProgress(0, StartOptions.Name + "started.");
            // name the thread for debugging
            if (String.IsNullOrEmpty(Thread.CurrentThread.Name))
                Thread.CurrentThread.Name = nameof(AircraftPositionDatabaseMaintainer);
            // get maintenance interval
            int interval = (int)Properties.Settings.Default.Database_BackgroundMaintenance_Period * 60;
            do
            {                        
                try
                {
                    this.ReportProgress(0, "Maintaining database...");
                    try
                    {
                        // check database entry count and remove oldest entries
                        long count = AircraftPositionData.Database.AircraftPositionCount();
                        if (this.CancellationPending)
                            break;
                        // check against limit
                        if (count > StartOptions.Database_MaxCount)
                        {
                            // remove oldest entries from database
                            this.ReportProgress(0, "Exceeding database entries count limit, removing entries...");
                            AircraftPositionData.Database.AircraftPositionBulkDeleteFirst(1000);
                        }
                    }
                    catch (Exception ex)
                    {
                        this.ReportProgress(-1, ex.ToString());
                    }
                    try
                    {
                        // check and reduce database size
                        // tricky, because deleting entries not necessarily reduces database size
                        // neeeds pragma auto_vacuum to be set to full
                        // delete an amount of entries from AircraftPositions table and let auto_vacuum do the rest
                        // keep last reported size in memory trigger deletion only if size is increasing again
                        double size = AircraftPositionData.Database.GetDBSize();
                        // check against last reported size
                        if (size > DBLastSize)
                        {
                            // keep last reported size
                            DBLastSize = size;
                            if (DBLastSize > StartOptions.Database_MaxSize)
                            {
                                // remove first 1000 entries from database
                                this.ReportProgress(0, "Exceeding database size limit, removing entries...");
                                AircraftPositionData.Database.AircraftPositionBulkDeleteFirst(1000);
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        this.ReportProgress(-1, ex.ToString());
                    }
                    try
                    {
                        // check and remove oldest entries
                        DateTime olderthan = DateTime.UtcNow - new TimeSpan(StartOptions.Database_MaxDaysLifetime, 0, 0, 0);
                        // remove oldest entries from database
                        this.ReportProgress(0, "Cleaning up aircraft positions...");
                        AircraftPositionData.Database.AircraftPositionBulkDeleteOlderThan(olderthan);
                    }
                    catch (Exception ex)
                    {
                        this.ReportProgress(-1, ex.ToString());
                    }
                    // sleep 
                    int i = 0;
                    while (!this.CancellationPending && (i < interval))
                    {
                        Thread.Sleep(1000);
                        i++;
                    }
                }
                catch (Exception ex)
                {
                    this.ReportProgress(-1, ex.ToString());
                }
            }
            while (!this.CancellationPending);
            if (this.CancellationPending)
                this.ReportProgress(0, "Cancelled.");
            else
                this.ReportProgress(0, "Finished.");
        }

        #endregion

    }
}
