using System; using System.Collections.Generic; using System.Linq; using System.IO; using System.Globalization; using System.Reflection; using System.Data; using System.Diagnostics; using ScoutBase.Core; using ScoutBase.Database; using System.Data.SQLite; using Newtonsoft.Json; using System.Windows.Forms; using System.ComponentModel; namespace AirScout.Signals { public class SignalData { static SignalDatabase signals = new SignalDatabase(); public static SignalDatabase Database { get { return signals; } } } /// /// Holds the signal information in a database structure. /// public class SignalDatabase : ScoutBaseDatabase { public SignalDatabase() { UserVersion = 1; Name = "Scoutbase Signal Database"; Description = "Holds recorded signal strength information"; db = OpenDatabase("signals.db3", DefaultDatabaseDirectory(), Properties.Settings.Default.Database_InMemory); // set auto vacuum mode to "Full" to allow database to reduce size on disk // requires a vacuum command to change database layout AUTOVACUUMMODE mode = db.GetAutoVacuum(); if (mode != AUTOVACUUMMODE.FULL) { if (MessageBox.Show("A major database layout change is necessary to run this version of AirScout. Older versions of AirScout are not compatible anymore and will cause errors. \n\nPress >OK< to start upgrade now (this will take some minutes). \nPress >Cancel< to leave.", "Database Upgrade of " + Path.GetFileName(db.DBLocation), MessageBoxButtons.OKCancel) == DialogResult.Cancel) Environment.Exit(-1); // exit immediately db.SetAutoVacuum(AUTOVACUUMMODE.FULL); } // create tables with schemas if not exist if (!SignalLevelTableExists()) SignalLevelCreateTable(); } ~SignalDatabase() { CloseDatabase(db); } public string DefaultDatabaseDirectory() { // create default database directory name string dir = Properties.Settings.Default.Database_Directory; if (!String.IsNullOrEmpty(dir)) { return dir; } // empty settings -_> create standard path // collect entry assembly info Assembly ass = Assembly.GetExecutingAssembly(); string company = ""; string product = ""; object[] attribs; attribs = ass.GetCustomAttributes(typeof(AssemblyCompanyAttribute), true); if (attribs.Length > 0) { company = ((AssemblyCompanyAttribute)attribs[0]).Company; } attribs = ass.GetCustomAttributes(typeof(AssemblyProductAttribute), true); if (attribs.Length > 0) { product = ((AssemblyProductAttribute)attribs[0]).Product; } // create database path dir = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); if (!String.IsNullOrEmpty(company)) dir = Path.Combine(dir, company); if (!String.IsNullOrEmpty(product)) dir = Path.Combine(dir, product); return Path.Combine(dir, "AircraftData"); } #region SignalLevel public bool SignalLevelTableExists(string tablename = "") { // check for table name is null or empty --> use default tablename from type instead string tn = tablename; if (String.IsNullOrEmpty(tn)) tn = SignalLevelDesignator.TableName; return db.TableExists(tn); } public void SignalLevelCreateTable(string tablename = "") { lock (db.DBCommand) { // check for table name is null or empty --> use default tablename from type instead string tn = tablename; if (String.IsNullOrEmpty(tn)) tn = SignalLevelDesignator.TableName; db.DBCommand.CommandText = "CREATE TABLE `" + tn + "`(Level DOUBLE, LastUpdated INT32, PRIMARY KEY (LastUpdated))"; db.DBCommand.Parameters.Clear(); db.Execute(db.DBCommand); } } public long SignalLevelCount() { object count = db.ExecuteScalar("SELECT COUNT(*) FROM " + SignalLevelDesignator.TableName); if (IsValid(count)) return (long)count; return 0; } public bool SignalLevelExists(DateTime lastupdated) { SignalLevelDesignator sd = new SignalLevelDesignator(lastupdated); return SignalLevelExists(sd); } public bool SignalLevelExists(SignalLevelDesignator sd) { lock (db.DBCommand) { db.DBCommand.CommandText = "SELECT EXISTS (SELECT LastUpdated FROM " + SignalLevelDesignator.TableName + " WHERE LastUpdated = @LastUpdated"; db.DBCommand.Parameters.Clear(); db.DBCommand.Parameters.Add(sd.AsUNIXTime("LastUpdated")); object result = db.DBCommand.ExecuteScalar(); if (IsValid(result) && ((long)result > 0)) return true; } return false; } public SignalLevelDesignator SignalLevelFind(DateTime lastupdated) { SignalLevelDesignator sd = new SignalLevelDesignator(lastupdated); return SignalLevelFind(sd); } public SignalLevelDesignator SignalLevelFind(SignalLevelDesignator sd) { lock (db.DBCommand) { db.DBCommand.CommandText = "SELECT * FROM " + SignalLevelDesignator.TableName + " WHERE LastUpdated = @LastUpdated"; db.DBCommand.Parameters.Clear(); db.DBCommand.Parameters.Add(sd.AsUNIXTime("LastUpdated")); try { DataTable Result = db.Select(db.DBCommand); if ((Result != null) && (Result.Rows.Count > 0)) { return new SignalLevelDesignator(Result.Rows[0]); } } catch (Exception ex) { Log.WriteMessage(ex.ToString(), LogLevel.Error); } } return null; } public SignalLevelDesignator SignalLevelFindAt(long index) { lock (db.DBCommand) { db.DBCommand.CommandText = "SELECT * FROM " + SignalLevelDesignator.TableName + " LIMIT 1 OFFSET " + index.ToString(); db.DBCommand.Parameters.Clear(); try { DataTable Result = db.Select(db.DBCommand); if ((Result != null) && (Result.Rows.Count > 0)) { return new SignalLevelDesignator(Result.Rows[0]); } } catch (Exception ex) { Log.WriteMessage(ex.ToString(), LogLevel.Error); } } return null; } public DateTime SignalLevelFindlastUpdated(DateTime lastupdated) { SignalLevelDesignator sd = new SignalLevelDesignator(lastupdated); return SignalLevelFindLastUpdated(sd); } public DateTime SignalLevelFindLastUpdated(SignalLevelDesignator sd) { lock (db.DBCommand) { db.DBCommand.CommandText = "SELECT LastUpdated FROM " + SignalLevelDesignator.TableName + " WHERE LastUpdated = @LastUpdated"; db.DBCommand.Parameters.Clear(); db.DBCommand.Parameters.Add(sd.AsUNIXTime("LastUpdated")); object result = db.ExecuteScalar(db.DBCommand); if (IsValid(result)) return (SQLiteEntry.UNIXTimeToDateTime((int)result)); } return DateTime.MinValue; } public int SignalLevelInsert(SignalLevelDesignator sd) { lock (db.DBCommand) { db.DBCommand.CommandText = "INSERT INTO " + SignalLevelDesignator.TableName + " (Level, LastUpdated) VALUES (@Level, @LastUpdated)"; db.DBCommand.Parameters.Clear(); db.DBCommand.Parameters.Add(sd.AsDouble("Level")); db.DBCommand.Parameters.Add(sd.AsUNIXTime("LastUpdated")); return db.ExecuteNonQuery(db.DBCommand); } } public int SignalLevelDelete(DateTime lastupdated) { SignalLevelDesignator sd = new SignalLevelDesignator(lastupdated); return SignalLevelDelete(sd); } public int SignalLevelDelete(SignalLevelDesignator sd) { lock (db.DBCommand) { db.DBCommand.CommandText = "DELETE FROM " + SignalLevelDesignator.TableName + " WHERE LastUpdated = @LastUpdated"; db.DBCommand.Parameters.Clear(); db.DBCommand.Parameters.Add(sd.AsUNIXTime("LastUpdated")); return db.ExecuteNonQuery(db.DBCommand); } } public int SignalLevelDeleteAll() { lock (db.DBCommand) { db.DBCommand.CommandText = "DELETE FROM " + SignalLevelDesignator.TableName; db.DBCommand.Parameters.Clear(); return db.ExecuteNonQuery(db.DBCommand); } } public int SignalLevelUpdate(SignalLevelDesignator sd) { lock (db.DBCommand) { db.DBCommand.CommandText = "UPDATE " + SignalLevelDesignator.TableName + " SET Level = @Level, LastUpdated = @LastUpdated WHERE LastUpdated = @LastUpdated"; db.DBCommand.Parameters.Clear(); db.DBCommand.Parameters.Add(sd.AsDouble("Level")); db.DBCommand.Parameters.Add(sd.AsUNIXTime("LastUpdated")); return db.ExecuteNonQuery(db.DBCommand); } } public int SignalLevelBulkInsert(List sds) { int errors = 0; try { lock (db) { db.BeginTransaction(); foreach (SignalLevelDesignator sd in sds) { try { SignalLevelInsert(sd); } catch (Exception ex) { Log.WriteMessage("Error inserting SignalLevel at [" + sd.LastUpdated.ToString("yyyy-MM-dd HH:mm:ss") + "]: " + ex.ToString(), LogLevel.Error); errors++; } } db.Commit(); } } catch (Exception ex) { Log.WriteMessage(ex.ToString(), LogLevel.Error); } return -errors; } public int SignalLevelBulkDelete(List sds) { int errors = 0; try { lock (db) { db.BeginTransaction(); foreach (SignalLevelDesignator sd in sds) { try { SignalLevelDelete(sd); } catch (Exception ex) { Log.WriteMessage("Error deleting SignalLevel at [" + sd.LastUpdated.ToString("yyyy-MM-dd HH:mm:ss") + "]: " + ex.ToString(), LogLevel.Error); errors++; } } db.Commit(); } } catch (Exception ex) { Log.WriteMessage(ex.ToString(), LogLevel.Error); } return -errors; } public int SignalLevelBulkInsertOrUpdateIfNewer(List sds) { if (sds == null) return 0; int i = 0; lock (db) { db.BeginTransaction(); foreach (SignalLevelDesignator sd in sds) { SignalLevelInsertOrUpdateIfNewer(sd); i++; } db.Commit(); } return i; } public int SignalLevelInsertOrUpdateIfNewer(SignalLevelDesignator sd) { DateTime dt = SignalLevelFindLastUpdated(sd); if (dt == DateTime.MinValue) return SignalLevelInsert(sd); if (dt < sd.LastUpdated) return SignalLevelUpdate(sd); return 0; } public List SignalLevelGetAll() { List l = new List(); DataTable Result = db.Select("SELECT * FROM " + SignalLevelDesignator.TableName); if (!IsValid(Result) || (Result.Rows.Count == 0)) return l; foreach (DataRow row in Result.Rows) l.Add(new SignalLevelDesignator(row)); return l; } public List SignalLevelFromJSON(string json) { if (String.IsNullOrEmpty(json)) return null; JsonSerializerSettings settings = new JsonSerializerSettings(); settings.DateTimeZoneHandling = DateTimeZoneHandling.Utc; settings.FloatFormatHandling = FloatFormatHandling.String; settings.Formatting = Newtonsoft.Json.Formatting.Indented; return JsonConvert.DeserializeObject>(json, settings); } public string SignalLevelToJSON() { List l = SignalLevelGetAll(); JsonSerializerSettings settings = new JsonSerializerSettings(); settings.DateTimeZoneHandling = DateTimeZoneHandling.Utc; settings.FloatFormatHandling = FloatFormatHandling.String; settings.Formatting = Newtonsoft.Json.Formatting.Indented; string json = JsonConvert.SerializeObject(l, settings); return json; } public DataTableSignalLevels SignalLevelToDataTable() { List sds = SignalLevelGetAll(); DataTableSignalLevels dtl = new DataTableSignalLevels(sds); return dtl; } #endregion } }