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 ScoutBase.Propagation; using System.Data.SQLite; using Newtonsoft.Json; using System.Windows.Forms; using System.ComponentModel; using AirScout.Core; namespace AirScout.Aircrafts { public class AircraftData { static AircraftDatabase aircrafts = new AircraftDatabase(); public static AircraftDatabase Database { get { return aircrafts; } } } /// /// Holds the Aircraft information in a database structure. /// public class AircraftDatabase : ScoutBaseDatabase { public long AircraftRegistrationMinLength { get; private set; } public long AircraftRegistrationMaxLength { get; private set; } public long AircraftTypeIATAMinLength { get; private set; } public long AircraftTypeIATAMaxLength { get; private set; } public long AircraftTypeICAOMinLength { get; private set; } public long AircraftTypeICAOMaxLength { get; private set; } public AircraftDatabase() { UserVersion = 1; Name = "AirScout Aircraft Database"; Description = "Holds all aircraft, airline and airport information.\n" + "The information is updated periodically from a global web resource.\n" + "The user cannot change any item."; UserVersion = 1; Name = "ScoutBase Elevation Database"; // add table description manually TableDescriptions.Add(AircraftRegistrationDesignator.TableName, "Holds aircraft registration information."); TableDescriptions.Add(AircraftTypeDesignator.TableName, "Holds aircraft type information."); TableDescriptions.Add(AircraftDesignator.TableName, "Holds basic aircraft information."); TableDescriptions.Add(AirlineDesignator.TableName, "Holds airline information."); TableDescriptions.Add(AirportDesignator.TableName, "Holds airport information."); db = OpenDatabase("aircrafts.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 (!AircraftTableExists()) AircraftCreateTable(); if (!AircraftTypeTableExists()) AircraftTypeCreateTable(); if (!AirlineTableExists()) AirlineCreateTable(); if (!AirportTableExists()) AirportCreateTable(); if (!AircraftRegistrationTableExists()) AircraftRegistrationCreateTable(); // create views PlaneInfoCreateView(); // get max/min lengths for AircraftRegistrations // due to performance reasons the maintenance is only performed at startup and during insertion (without database query) AircraftRegistrationMaxLength = AircraftRegistrationGetMaxLength(); AircraftRegistrationMinLength = AircraftRegistrationGetMinLength(); AircraftTypeIATAMaxLength = AircraftTypeIATAGetMaxLength(); AircraftTypeIATAMinLength = AircraftTypeIATAGetMinLength(); AircraftTypeICAOMaxLength = AircraftTypeICAOGetMaxLength(); AircraftTypeICAOMinLength = AircraftTypeICAOGetMinLength(); } ~AircraftDatabase() { 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 Aircrafts public bool AircraftTableExists(string tablename = "") { // check for table name is null or empty --> use default tablename from type instead string tn = tablename; if (String.IsNullOrEmpty(tn)) tn = AircraftDesignator.TableName; return db.TableExists(tn); } public void AircraftCreateTable(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 = AircraftDesignator.TableName; db.DBCommand.CommandText = "CREATE TABLE `" + tn + "`(Hex TEXT UNIQUE NOT NULL DEFAULT '', Call TEXT NOT NULL DEFAULT '', Reg TEXT NOT NULL DEFAULT '', TypeCode TEXT, LastUpdated INT32, PRIMARY KEY (Hex))"; db.DBCommand.Parameters.Clear(); db.Execute(db.DBCommand); // create table indices db.DBCommand.CommandText = "CREATE INDEX idx_" + tn + "_Reg ON `" + tn + "` (Reg)"; db.DBCommand.Parameters.Clear(); db.Execute(db.DBCommand); // create table indices db.DBCommand.CommandText = "CREATE INDEX idx_" + tn + "_Call ON `" + tn + "` (Call)"; db.DBCommand.Parameters.Clear(); db.Execute(db.DBCommand); } } public long AircraftCount() { lock (db) { object count = db.ExecuteScalar("SELECT COUNT(*) FROM " + AircraftDesignator.TableName); if (IsValid(count)) return (long)count; } return 0; } public long AircraftCountUnknownCall() { lock (db) { object count = db.ExecuteScalar("SELECT COUNT(*) FROM " + AircraftDesignator.TableName + " WHERE Call = '[unknown]'"); if (IsValid(count)) return (long)count; } return 0; } public long AircraftCountUnknownHex() { lock (db) { object count = db.ExecuteScalar("SELECT COUNT(*) FROM " + AircraftDesignator.TableName + " WHERE Hex = '[unknown]'"); if (IsValid(count)) return (long)count; } return 0; } public long AircraftCountUnknownType() { lock (db) { object count = db.ExecuteScalar("SELECT COUNT(*) FROM " + AircraftDesignator.TableName + " WHERE TypeCode = '[unknown]'"); if (IsValid(count)) return (long)count; } return 0; } public bool AircraftExists(string hex) { AircraftDesignator ad = new AircraftDesignator(hex); return AircraftExists(ad); } public bool AircraftExists(AircraftDesignator ad) { lock (db.DBCommand) { db.DBCommand.CommandText = "SELECT EXISTS (SELECT LastUpdated FROM " + AircraftDesignator.TableName + " WHERE Hex = @Hex"; db.DBCommand.Parameters.Clear(); db.DBCommand.Parameters.Add(ad.AsString("Hex")); object result = db.DBCommand.ExecuteScalar(); if (IsValid(result) && ((long)result > 0)) return true; } return false; } public AircraftDesignator AircraftFindByHex(string hex) { AircraftDesignator ad = new AircraftDesignator(hex); return AircraftFind(ad); } public AircraftDesignator AircraftFindByReg(string reg) { // returs entry by search string, latest entry if more than one entry found lock (db.DBCommand) { db.DBCommand.CommandText = "SELECT * FROM " + AircraftDesignator.TableName + " WHERE Reg = '" + reg + "' ORDER BY Lastupdated DESC LIMIT 1"; db.DBCommand.Parameters.Clear(); try { DataTable Result = db.Select(db.DBCommand); if ((Result != null) && (Result.Rows.Count > 0)) { return new AircraftDesignator(Result.Rows[0]); } } catch (Exception ex) { Log.WriteMessage(ex.ToString(), LogLevel.Error); } } return null; } public AircraftDesignator AircraftFindByCall(string call) { // returs entry by search string, latest entry if more than one entry found lock (db.DBCommand) { db.DBCommand.CommandText = "SELECT * FROM " + AircraftDesignator.TableName + " WHERE Call = '" + call + "' ORDER BY Lastupdated DESC LIMIT 1"; db.DBCommand.Parameters.Clear(); try { DataTable Result = db.Select(db.DBCommand); if ((Result != null) && (Result.Rows.Count > 0)) { return new AircraftDesignator(Result.Rows[0]); } } catch (Exception ex) { Log.WriteMessage(ex.ToString(), LogLevel.Error); } } return null; } public AircraftDesignator AircraftFind(AircraftDesignator ad) { lock (db.DBCommand) { db.DBCommand.CommandText = "SELECT * FROM " + AircraftDesignator.TableName + " WHERE Hex = @Hex"; db.DBCommand.Parameters.Clear(); db.DBCommand.Parameters.Add(ad.AsString("Hex")); try { DataTable Result = db.Select(db.DBCommand); if ((Result != null) && (Result.Rows.Count > 0)) { return new AircraftDesignator(Result.Rows[0]); } } catch (Exception ex) { Log.WriteMessage(ex.ToString(), LogLevel.Error); } } return null; } public AircraftDesignator AircraftFindAt(long index) { lock (db.DBCommand) { db.DBCommand.CommandText = "SELECT * FROM " + AircraftDesignator.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 AircraftDesignator(Result.Rows[0]); } } catch (Exception ex) { Log.WriteMessage(ex.ToString(), LogLevel.Error); } } return null; } public DateTime AircraftFindlastUpdated(string hex) { AircraftDesignator ad = new AircraftDesignator(hex); return AircraftFindLastUpdated(ad); } public DateTime AircraftFindLastUpdated(AircraftDesignator ad) { lock (db.DBCommand) { db.DBCommand.CommandText = "SELECT LastUpdated FROM " + AircraftDesignator.TableName + " WHERE Hex = @Hex"; db.DBCommand.Parameters.Clear(); db.DBCommand.Parameters.Add(ad.AsString("Hex")); object result = db.ExecuteScalar(db.DBCommand); if (IsValid(result)) return (SQLiteEntry.UNIXTimeToDateTime((int)result)); } return DateTime.MinValue; } public int AircraftInsert(AircraftDesignator ad) { lock (db.DBCommand) { db.DBCommand.CommandText = "INSERT INTO " + AircraftDesignator.TableName + " (Hex, Call, Reg, TypeCode, LastUpdated) VALUES (@Hex, @Call, @Reg, @TypeCode, @LastUpdated)"; db.DBCommand.Parameters.Clear(); db.DBCommand.Parameters.Add(ad.AsString("Hex")); db.DBCommand.Parameters.Add(ad.AsString("Call")); db.DBCommand.Parameters.Add(ad.AsString("Reg")); db.DBCommand.Parameters.Add(ad.AsString("TypeCode")); db.DBCommand.Parameters.Add(ad.AsUNIXTime("LastUpdated")); return db.ExecuteNonQuery(db.DBCommand); } } public int AircraftDelete(string hex) { AircraftDesignator ad = new AircraftDesignator(hex); return AircraftDelete(ad); } public int AircraftDelete(AircraftDesignator ad) { lock (db.DBCommand) { db.DBCommand.CommandText = "DELETE FROM " + AircraftDesignator.TableName + " WHERE Hex = @Hex"; db.DBCommand.Parameters.Clear(); db.DBCommand.Parameters.Add(ad.AsString("Hex")); return db.ExecuteNonQuery(db.DBCommand); } } public int AircraftDeleteAll() { lock (db.DBCommand) { db.DBCommand.CommandText = "DELETE FROM " + AircraftDesignator.TableName; db.DBCommand.Parameters.Clear(); return db.ExecuteNonQuery(db.DBCommand); } } public int AircraftUpdate(AircraftDesignator ad) { lock (db.DBCommand) { db.DBCommand.CommandText = "UPDATE " + AircraftDesignator.TableName + " SET Hex = @Hex, Call = @Call, Reg = @Reg, TypeCode = @TypeCode, LastUpdated = @LastUpdated WHERE Hex = @Hex"; db.DBCommand.Parameters.Clear(); db.DBCommand.Parameters.Add(ad.AsString("Hex")); db.DBCommand.Parameters.Add(ad.AsString("Call")); db.DBCommand.Parameters.Add(ad.AsString("Reg")); db.DBCommand.Parameters.Add(ad.AsString("TypeCode")); db.DBCommand.Parameters.Add(ad.AsUNIXTime("LastUpdated")); return db.ExecuteNonQuery(db.DBCommand); } } public int AircraftBulkInsert(List ads) { int errors = 0; try { lock (db) { db.BeginTransaction(); foreach (AircraftDesignator ad in ads) { try { AircraftInsert(ad); } catch (Exception ex) { Log.WriteMessage("Error inserting aircraft [" + ad.Hex + "]: " + ex.ToString(), LogLevel.Error); errors++; } } db.Commit(); } } catch (Exception ex) { Log.WriteMessage(ex.ToString(), LogLevel.Error); } return -errors; } public int AircraftBulkDelete(List ads) { int errors = 0; try { lock (db) { db.BeginTransaction(); foreach (AircraftDesignator ad in ads) { try { AircraftDelete(ad); } catch (Exception ex) { Log.WriteMessage("Error deleting aircraft [" + ad.Hex + "]: " + ex.ToString(), LogLevel.Error); errors++; } } db.Commit(); } } catch (Exception ex) { Log.WriteMessage(ex.ToString(), LogLevel.Error); } return -errors; } public int AircraftBulkInsertOrUpdateIfNewer(List ads) { if (ads == null) return 0; int i = 0; try { lock (db) { db.BeginTransaction(); foreach (AircraftDesignator ad in ads) { try { AircraftInsertOrUpdateIfNewer(ad); i++; } catch (Exception ex) { } } db.Commit(); } } catch(Exception ex) { Log.WriteMessage(ex.ToString(), LogLevel.Error); } return i; } public int AircraftInsertOrUpdateIfNewer(AircraftDesignator ad) { DateTime dt = AircraftFindLastUpdated(ad); if (dt == DateTime.MinValue) return AircraftInsert(ad); if (dt < ad.LastUpdated) return AircraftUpdate(ad); return 0; } public List AircraftGetAll() { List l = new List(); DataTable Result = db.Select("SELECT * FROM " + AircraftDesignator.TableName); if (!IsValid(Result) || (Result.Rows.Count == 0)) return l; foreach (DataRow row in Result.Rows) l.Add(new AircraftDesignator(row)); return l; } public List AircraftGetAll(BackgroundWorker caller) { // gets all aircrafts from database // supports abort calculation if called from background worker and cancellation requested List l = new List(); int i = 0; SQLiteCommand cmd = new SQLiteCommand(db.DBConnection); cmd.CommandText = "SELECT * FROM " + AircraftDesignator.TableName; SQLiteDataReader reader = cmd.ExecuteReader(); while (reader.Read()) { AircraftDesignator ap = new AircraftDesignator((IDataRecord)reader); l.Add(ap); i++; // abort calculation if called from background worker and cancellation pending if (caller != null) { if (caller.WorkerSupportsCancellation && caller.CancellationPending) return new List(); if (caller.WorkerReportsProgress && (i % 1000 == 0)) caller.ReportProgress(0, "Getting aircraft " + i.ToString() + " of"); } } reader.Close(); return l; } public List AircraftFromJSON(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 AircraftToJSON() { List l = AircraftGetAll(); 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 DataTableAircrafts AircraftToDataTable() { List ads = AircraftGetAll(); DataTableAircrafts dtl = new DataTableAircrafts(ads); return dtl; } #endregion #region AircraftTypes public bool AircraftTypeTableExists(string tablename = "") { // check for table name is null or empty --> use default tablename from type instead string tn = tablename; if (String.IsNullOrEmpty(tn)) tn = AircraftTypeDesignator.TableName; return db.TableExists(tn); } public void AircraftTypeCreateTable(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 = AircraftTypeDesignator.TableName; db.DBCommand.CommandText = "CREATE TABLE `" + tn + "`(ICAO TEXT NOT NULL DEFAULT '', IATA TEXT NOT NULL DEFAULT '', Manufacturer TEXT, Model TEXT, Category INT32, LastUpdated INT32, PRIMARY KEY (ICAO, IATA))"; db.DBCommand.Parameters.Clear(); db.Execute(db.DBCommand); // create table indices db.DBCommand.CommandText = "CREATE INDEX idx_" + tn + "_ICAO ON `" + tn + "` (ICAO)"; db.DBCommand.Parameters.Clear(); db.Execute(db.DBCommand); db.DBCommand.CommandText = "CREATE INDEX idx_" + tn + "_IATA ON `" + tn + "` (IATA)"; db.DBCommand.Parameters.Clear(); db.Execute(db.DBCommand); } } public long AircraftTypeCount() { object count = db.ExecuteScalar("SELECT COUNT(*) FROM " + AircraftTypeDesignator.TableName); if (IsValid(count)) return (long)count; return 0; } public bool AircraftTypeExists(string icao, string iata) { AircraftTypeDesignator td = new AircraftTypeDesignator(icao, iata); return AircraftTypeExists(td); } public bool AircraftTypeExists(AircraftTypeDesignator td) { lock (db.DBCommand) { db.DBCommand.CommandText = "SELECT EXISTS (SELECT LastUpdated FROM " + AircraftTypeDesignator.TableName + " WHERE ICAO = @ICAO AND IATA = @IATA"; db.DBCommand.Parameters.Clear(); db.DBCommand.Parameters.Add(td.AsString("ICAO")); db.DBCommand.Parameters.Add(td.AsString("IATA")); object result = db.DBCommand.ExecuteScalar(); if (IsValid(result) && ((long)result > 0)) return true; } return false; } private long AircraftTypeIATAGetMaxLength() { lock (db.DBCommand) { db.DBCommand.CommandText = "SELECT max(length(IATA)) FROM " + AircraftTypeDesignator.TableName; db.DBCommand.Parameters.Clear(); object result = db.DBCommand.ExecuteScalar(); if (IsValid(result)) return (long)result; } return 0; } private long AircraftTypeIATAGetMinLength() { lock (db.DBCommand) { db.DBCommand.CommandText = "SELECT min(length(IATA)) FROM " + AircraftTypeDesignator.TableName; db.DBCommand.Parameters.Clear(); object result = db.DBCommand.ExecuteScalar(); if (IsValid(result)) return (long)result; } return 0; } private long AircraftTypeICAOGetMaxLength() { lock (db.DBCommand) { db.DBCommand.CommandText = "SELECT max(length(ICAO)) FROM " + AircraftTypeDesignator.TableName; db.DBCommand.Parameters.Clear(); object result = db.DBCommand.ExecuteScalar(); if (IsValid(result)) return (long)result; } return 0; } private long AircraftTypeICAOGetMinLength() { lock (db.DBCommand) { db.DBCommand.CommandText = "SELECT min(length(ICAO)) FROM " + AircraftTypeDesignator.TableName; db.DBCommand.Parameters.Clear(); object result = db.DBCommand.ExecuteScalar(); if (IsValid(result)) return (long)result; } return 0; } public AircraftTypeDesignator AircraftTypeFindByIATA(string iata) { // returs entry by search string, latest entry if more than one entry found if (String.IsNullOrEmpty(iata)) return null; lock (db.DBCommand) { db.DBCommand.CommandText = "SELECT * FROM " + AircraftTypeDesignator.TableName + " WHERE IATA = '" + iata + "' ORDER BY Lastupdated DESC LIMIT 1"; db.DBCommand.Parameters.Clear(); try { DataTable Result = db.Select(db.DBCommand); if ((Result != null) && (Result.Rows.Count > 0)) { return new AircraftTypeDesignator(Result.Rows[0]); } } catch (Exception ex) { Log.WriteMessage(ex.ToString(), LogLevel.Error); } } return null; } public AircraftTypeDesignator AircraftTypeFindByICAO(string icao) { // returs entry by search string, latest entry if more than one entry found if (String.IsNullOrEmpty(icao)) return null; lock (db.DBCommand) { db.DBCommand.CommandText = "SELECT * FROM " + AircraftTypeDesignator.TableName + " WHERE ICAO = '" + icao + "' ORDER BY Lastupdated DESC LIMIT 1"; db.DBCommand.Parameters.Clear(); try { DataTable Result = db.Select(db.DBCommand); if ((Result != null) && (Result.Rows.Count > 0)) { return new AircraftTypeDesignator(Result.Rows[0]); } } catch (Exception ex) { Log.WriteMessage(ex.ToString(), LogLevel.Error); } } return null; } public AircraftTypeDesignator AircraftTypeFind(string icao, string iata) { AircraftTypeDesignator td = new AircraftTypeDesignator(icao, iata); return AircraftTypeFind(td); } public AircraftTypeDesignator AircraftTypeFind(AircraftTypeDesignator td) { lock (db.DBCommand) { db.DBCommand.CommandText = "SELECT * FROM " + AircraftTypeDesignator.TableName + " WHERE ICAO = @ICAO AND IATA = @IATA"; db.DBCommand.Parameters.Clear(); db.DBCommand.Parameters.Add(td.AsString("ICAO")); db.DBCommand.Parameters.Add(td.AsString("IATA")); try { DataTable Result = db.Select(db.DBCommand); if ((Result != null) && (Result.Rows.Count > 0)) { return new AircraftTypeDesignator(Result.Rows[0]); } } catch (Exception ex) { Log.WriteMessage(ex.ToString(), LogLevel.Error); } } return null; } public AircraftTypeDesignator AircraftTypeFindAt(long index) { lock (db.DBCommand) { db.DBCommand.CommandText = "SELECT * FROM " + AircraftTypeDesignator.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 AircraftTypeDesignator(Result.Rows[0]); } } catch (Exception ex) { Log.WriteMessage(ex.ToString(), LogLevel.Error); } } return null; } public DateTime AircraftTypeFindlastUpdated(string icao, string iata) { AircraftTypeDesignator td = new AircraftTypeDesignator(icao, iata); return AircraftTypeFindLastUpdated(td); } public DateTime AircraftTypeFindLastUpdated(AircraftTypeDesignator td) { lock (db.DBCommand) { db.DBCommand.CommandText = "SELECT LastUpdated FROM " + AircraftTypeDesignator.TableName + " WHERE ICAO = @ICAO AND IATA = @IATA"; db.DBCommand.Parameters.Clear(); db.DBCommand.Parameters.Add(td.AsString("ICAO")); db.DBCommand.Parameters.Add(td.AsString("IATA")); object result = db.ExecuteScalar(db.DBCommand); if (IsValid(result)) return (SQLiteEntry.UNIXTimeToDateTime((int)result)); } return DateTime.MinValue; } public int AircraftTypeInsert(AircraftTypeDesignator td) { // maintain min/max values if (td.IATA.Length < AircraftTypeIATAMinLength) AircraftTypeIATAMinLength = td.IATA.Length; if (td.IATA.Length > AircraftTypeIATAMaxLength) AircraftTypeIATAMaxLength = td.IATA.Length; if (td.ICAO.Length < AircraftTypeICAOMinLength) AircraftTypeICAOMinLength = td.ICAO.Length; if (td.ICAO.Length > AircraftTypeICAOMaxLength) AircraftTypeICAOMaxLength = td.ICAO.Length; lock (db.DBCommand) { db.DBCommand.CommandText = "INSERT INTO " + AircraftTypeDesignator.TableName + " (ICAO, IATA, Manufacturer, Model, Category, LastUpdated) VALUES (@ICAO, @IATA, @Manufacturer, @Model, @Category, @LastUpdated)"; db.DBCommand.Parameters.Clear(); db.DBCommand.Parameters.Add(td.AsString("ICAO")); db.DBCommand.Parameters.Add(td.AsString("IATA")); db.DBCommand.Parameters.Add(td.AsString("Manufacturer")); db.DBCommand.Parameters.Add(td.AsString("Model")); db.DBCommand.Parameters.Add(td.AsInt32("Category")); db.DBCommand.Parameters.Add(td.AsUNIXTime("LastUpdated")); return db.ExecuteNonQuery(db.DBCommand); } } public int AircraftTypeDelete(string icao, string iata) { AircraftTypeDesignator td = new AircraftTypeDesignator(iata, icao); return AircraftTypeDelete(td); } public int AircraftTypeDelete(AircraftTypeDesignator td) { lock (db.DBCommand) { db.DBCommand.CommandText = "DELETE FROM " + AircraftTypeDesignator.TableName + " WHERE ICAO = @ICAO AND IATA = @IATA"; db.DBCommand.Parameters.Clear(); db.DBCommand.Parameters.Add(td.AsString("ICAO")); db.DBCommand.Parameters.Add(td.AsString("IATA")); return db.ExecuteNonQuery(db.DBCommand); } } public int AircraftTypeDeleteAll() { lock (db.DBCommand) { db.DBCommand.CommandText = "DELETE FROM " + AircraftTypeDesignator.TableName; db.DBCommand.Parameters.Clear(); return db.ExecuteNonQuery(db.DBCommand); } } public int AircraftTypeUpdate(AircraftTypeDesignator ad) { lock (db.DBCommand) { db.DBCommand.CommandText = "UPDATE " + AircraftTypeDesignator.TableName + " SET ICAO = @ICAO, IATA = @IATA, Manufacturer = @Manufacturer, Model = @Model, Category = @Category, LastUpdated = @LastUpdated WHERE ICAO = @ICAO AND IATA = @IATA"; db.DBCommand.Parameters.Clear(); db.DBCommand.Parameters.Add(ad.AsString("ICAO")); db.DBCommand.Parameters.Add(ad.AsString("IATA")); db.DBCommand.Parameters.Add(ad.AsString("Manufacturer")); db.DBCommand.Parameters.Add(ad.AsString("Model")); db.DBCommand.Parameters.Add(ad.AsInt32("Category")); db.DBCommand.Parameters.Add(ad.AsUNIXTime("LastUpdated")); return db.ExecuteNonQuery(db.DBCommand); } } public int AircraftTypeBulkInsert(List tds) { int errors = 0; try { lock (db) { db.BeginTransaction(); foreach (AircraftTypeDesignator td in tds) { try { AircraftTypeInsert(td); } catch (Exception ex) { Log.WriteMessage("Error inserting AircraftType [" + td.ICAO + ", " + td.IATA + "]: " + ex.ToString(), LogLevel.Error); errors++; } } db.Commit(); } } catch (Exception ex) { Log.WriteMessage(ex.ToString(), LogLevel.Error); } return -errors; } public int AircraftTypeBulkDelete(List ads) { int errors = 0; try { lock (db) { db.BeginTransaction(); foreach (AircraftTypeDesignator td in ads) { try { AircraftTypeDelete(td); } catch (Exception ex) { Log.WriteMessage("Error inserting AircraftType [" + td.ICAO + ", " + td.IATA + "]: " + ex.ToString()); errors++; } } db.Commit(); } } catch (Exception ex) { Log.WriteMessage(ex.ToString(), LogLevel.Error); } return -errors; } public int AircraftTypeBulkInsertOrUpdateIfNewer(List ads) { if (ads == null) return 0; int i = 0; lock (db) { db.BeginTransaction(); foreach (AircraftTypeDesignator ad in ads) { AircraftTypeInsertOrUpdateIfNewer(ad); i++; } db.Commit(); } return i; } public int AircraftTypeInsertOrUpdateIfNewer(AircraftTypeDesignator ad) { DateTime dt = AircraftTypeFindLastUpdated(ad); if (dt == DateTime.MinValue) return AircraftTypeInsert(ad); if (dt < ad.LastUpdated) return AircraftTypeUpdate(ad); return 0; } public List AircraftTypeGetAll() { List l = new List(); DataTable Result = db.Select("SELECT * FROM " + AircraftTypeDesignator.TableName); if (!IsValid(Result) || (Result.Rows.Count == 0)) return l; foreach (DataRow row in Result.Rows) l.Add(new AircraftTypeDesignator(row)); return l; } public List AircraftTypeGetAll(BackgroundWorker caller) { // gets all Aircraft types from database // supports abort calculation if called from background worker and cancellation requested List l = new List(); int i = 0; SQLiteCommand cmd = new SQLiteCommand(db.DBConnection); cmd.CommandText = "SELECT * FROM " + AircraftTypeDesignator.TableName; SQLiteDataReader reader = cmd.ExecuteReader(); while (reader.Read()) { AircraftTypeDesignator ap = new AircraftTypeDesignator((IDataRecord)reader); l.Add(ap); i++; // abort calculation if called from background worker and cancellation pending if (caller != null) { if (caller.WorkerSupportsCancellation && caller.CancellationPending) return new List(); if (caller.WorkerReportsProgress && (i % 1000 == 0)) caller.ReportProgress(0, "Getting Aircraft type " + i.ToString() + " of"); } } reader.Close(); return l; } public List AircraftTypeFromJSON(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 AircraftTypeToJSON() { List l = AircraftTypeGetAll(); 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 DataTableAircraftTypes AircraftTypeToDataTable() { List ads = AircraftTypeGetAll(); DataTableAircraftTypes dtl = new DataTableAircraftTypes(ads); return dtl; } #endregion #region Airlines public bool AirlineTableExists(string tablename = "") { // check for table name is null or empty --> use default tablename from type instead string tn = tablename; if (String.IsNullOrEmpty(tn)) tn = AirlineDesignator.TableName; return db.TableExists(tn); } public void AirlineCreateTable(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 = AirlineDesignator.TableName; db.DBCommand.CommandText = "CREATE TABLE `" + tn + "`(ICAO TEXT NOT NULL DEFAULT '', IATA TEXT NOT NULL DEFAULT '', Airline TEXT, Country TEXT, LastUpdated INT32, PRIMARY KEY (ICAO, IATA))"; db.DBCommand.Parameters.Clear(); db.Execute(db.DBCommand); // create table indices db.DBCommand.CommandText = "CREATE INDEX idx_" + tn + "_ICAO ON `" + tn + "` (ICAO)"; db.DBCommand.Parameters.Clear(); db.Execute(db.DBCommand); db.DBCommand.CommandText = "CREATE INDEX idx_" + tn + "_IATA ON `" + tn + "` (IATA)"; db.DBCommand.Parameters.Clear(); db.Execute(db.DBCommand); } } public long AirlineCount() { object count = db.ExecuteScalar("SELECT COUNT(*) FROM " + AirlineDesignator.TableName); if (IsValid(count)) return (long)count; return 0; } public bool AirlineExists(string icao, string iata) { AirlineDesignator ld = new AirlineDesignator(icao, iata); return AirlineExists(ld); } public bool AirlineExists(AirlineDesignator ld) { lock (db.DBCommand) { db.DBCommand.CommandText = "SELECT EXISTS (SELECT LastUpdated FROM " + AirlineDesignator.TableName + " WHERE ICAO = @ICAO AND IATA = @IATA"; db.DBCommand.Parameters.Clear(); db.DBCommand.Parameters.Add(ld.AsString("ICAO")); db.DBCommand.Parameters.Add(ld.AsString("IATA")); object result = db.DBCommand.ExecuteScalar(); if (IsValid(result) && ((long)result > 0)) return true; } return false; } public AirlineDesignator AirlineFindByICAO(string icao) { // returs entry by search string, latest entry if more than one entry found if (String.IsNullOrEmpty(icao)) return null; lock (db.DBCommand) { db.DBCommand.CommandText = "SELECT * FROM " + AirlineDesignator.TableName + " WHERE ICAO = '" + icao + "' ORDER BY LastUpdated DESC LIMIT 1"; db.DBCommand.Parameters.Clear(); try { DataTable Result = db.Select(db.DBCommand); if ((Result != null) && (Result.Rows.Count > 0)) { return new AirlineDesignator(Result.Rows[0]); } } catch (Exception ex) { Log.WriteMessage(ex.ToString(), LogLevel.Error); } } return null; } public AirlineDesignator AirlineFindByIATA(string iata) { // returs entry by search string, latest entry if more than one entry found if (String.IsNullOrEmpty(iata)) return null; lock (db.DBCommand) { db.DBCommand.CommandText = "SELECT * FROM " + AirlineDesignator.TableName + " WHERE IATA = '" + iata + "' ORDER BY LastUpdated DESC LIMIT 1"; db.DBCommand.Parameters.Clear(); try { DataTable Result = db.Select(db.DBCommand); if ((Result != null) && (Result.Rows.Count > 0)) { return new AirlineDesignator(Result.Rows[0]); } } catch (Exception ex) { Log.WriteMessage(ex.ToString(), LogLevel.Error); } } return null; } public AirlineDesignator AirlineFind(string icao, string iata) { AirlineDesignator ld = new AirlineDesignator(icao, iata); return AirlineFind(ld); } public AirlineDesignator AirlineFind(AirlineDesignator ld) { lock (db.DBCommand) { db.DBCommand.CommandText = "SELECT * FROM " + AirlineDesignator.TableName + " WHERE ICAO = @ICAO AND IATA = @IATA"; db.DBCommand.Parameters.Clear(); db.DBCommand.Parameters.Add(ld.AsString("ICAO")); db.DBCommand.Parameters.Add(ld.AsString("IATA")); try { DataTable Result = db.Select(db.DBCommand); if ((Result != null) && (Result.Rows.Count > 0)) { return new AirlineDesignator(Result.Rows[0]); } } catch (Exception ex) { Log.WriteMessage(ex.ToString(), LogLevel.Error); } } return null; } public AirlineDesignator AirlineFindAt(long index) { lock (db.DBCommand) { db.DBCommand.CommandText = "SELECT * FROM " + AirlineDesignator.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 AirlineDesignator(Result.Rows[0]); } } catch (Exception ex) { Log.WriteMessage(ex.ToString(), LogLevel.Error); } } return null; } public DateTime AirlineFindlastUpdated(string icao, string iata) { AirlineDesignator ld = new AirlineDesignator(icao, iata); return AirlineFindLastUpdated(ld); } public DateTime AirlineFindLastUpdated(AirlineDesignator ld) { lock (db.DBCommand) { db.DBCommand.CommandText = "SELECT LastUpdated FROM " + AirlineDesignator.TableName + " WHERE ICAO = @ICAO AND IATA = @IATA"; db.DBCommand.Parameters.Clear(); db.DBCommand.Parameters.Add(ld.AsString("ICAO")); db.DBCommand.Parameters.Add(ld.AsString("IATA")); object result = db.ExecuteScalar(db.DBCommand); if (IsValid(result)) return (SQLiteEntry.UNIXTimeToDateTime((int)result)); } return DateTime.MinValue; } public int AirlineInsert(AirlineDesignator ld) { lock (db.DBCommand) { db.DBCommand.CommandText = "INSERT INTO " + AirlineDesignator.TableName + " (ICAO, IATA, Airline, Country, LastUpdated) VALUES (@ICAO, @IATA, @Airline, @Country, @LastUpdated)"; db.DBCommand.Parameters.Clear(); db.DBCommand.Parameters.Add(ld.AsString("ICAO")); db.DBCommand.Parameters.Add(ld.AsString("IATA")); db.DBCommand.Parameters.Add(ld.AsString("Airline")); db.DBCommand.Parameters.Add(ld.AsString("Country")); db.DBCommand.Parameters.Add(ld.AsUNIXTime("LastUpdated")); return db.ExecuteNonQuery(db.DBCommand); } } public int AirlineDelete(string icao, string iata) { AirlineDesignator ld = new AirlineDesignator(iata, icao); return AirlineDelete(ld); } public int AirlineDelete(AirlineDesignator ld) { lock (db.DBCommand) { db.DBCommand.CommandText = "DELETE FROM " + AirlineDesignator.TableName + " WHERE ICAO = @ICAO AND IATA = @IATA"; db.DBCommand.Parameters.Clear(); db.DBCommand.Parameters.Add(ld.AsString("ICAO")); db.DBCommand.Parameters.Add(ld.AsString("IATA")); return db.ExecuteNonQuery(db.DBCommand); } } public int AirlineDeleteAll() { lock (db.DBCommand) { db.DBCommand.CommandText = "DELETE FROM " + AirlineDesignator.TableName; db.DBCommand.Parameters.Clear(); return db.ExecuteNonQuery(db.DBCommand); } } public int AirlineUpdate(AirlineDesignator ld) { lock (db.DBCommand) { db.DBCommand.CommandText = "UPDATE " + AirlineDesignator.TableName + " SET ICAO = @ICAO, IATA = @IATA, Airline = @Airline, Country = @Country, LastUpdated = @LastUpdated WHERE ICAO = @ICAO AND IATA = @IATA"; db.DBCommand.Parameters.Clear(); db.DBCommand.Parameters.Add(ld.AsString("ICAO")); db.DBCommand.Parameters.Add(ld.AsString("IATA")); db.DBCommand.Parameters.Add(ld.AsString("Airline")); db.DBCommand.Parameters.Add(ld.AsString("Country")); db.DBCommand.Parameters.Add(ld.AsUNIXTime("LastUpdated")); return db.ExecuteNonQuery(db.DBCommand); } } public int AirlineBulkInsert(List lds) { int errors = 0; try { lock (db) { db.BeginTransaction(); foreach (AirlineDesignator ld in lds) { try { AirlineInsert(ld); } catch (Exception ex) { Log.WriteMessage("Error inserting Airline [" + ld.ICAO + ", " + ld.IATA + "]: " + ex.ToString(), LogLevel.Error); errors++; } } db.Commit(); } } catch (Exception ex) { Log.WriteMessage(ex.ToString(), LogLevel.Error); } return -errors; } public int AirlineBulkDelete(List lds) { int errors = 0; try { lock (db) { db.BeginTransaction(); foreach (AirlineDesignator ld in lds) { try { AirlineDelete(ld); } catch (Exception ex) { Log.WriteMessage("Error inserting Airline [" + ld.ICAO + ", " + ld.IATA + "]: " + ex.ToString(), LogLevel.Error); errors++; } } db.Commit(); } } catch (Exception ex) { Log.WriteMessage(ex.ToString(), LogLevel.Error); } return -errors; } public int AirlineBulkInsertOrUpdateIfNewer(List lds) { if (lds == null) return 0; int i = 0; lock (db) { db.BeginTransaction(); foreach (AirlineDesignator ld in lds) { AirlineInsertOrUpdateIfNewer(ld); i++; } db.Commit(); } return i; } public int AirlineInsertOrUpdateIfNewer(AirlineDesignator ld) { DateTime dt = AirlineFindLastUpdated(ld); if (dt == DateTime.MinValue) return AirlineInsert(ld); if (dt < ld.LastUpdated) return AirlineUpdate(ld); return 0; } public List AirlineGetAll() { List l = new List(); DataTable Result = db.Select("SELECT * FROM " + AirlineDesignator.TableName); if (!IsValid(Result) || (Result.Rows.Count == 0)) return l; foreach (DataRow row in Result.Rows) l.Add(new AirlineDesignator(row)); return l; } public List AirlineGetAll(BackgroundWorker caller) { // gets all Airlines from database // supports abort calculation if called from background worker and cancellation requested List l = new List(); int i = 0; SQLiteCommand cmd = new SQLiteCommand(db.DBConnection); cmd.CommandText = "SELECT * FROM " + AirlineDesignator.TableName; SQLiteDataReader reader = cmd.ExecuteReader(); while (reader.Read()) { AirlineDesignator ap = new AirlineDesignator((IDataRecord)reader); l.Add(ap); i++; // abort calculation if called from background worker and cancellation pending if (caller != null) { if (caller.WorkerSupportsCancellation && caller.CancellationPending) return new List(); if (caller.WorkerReportsProgress && (i % 1000 == 0)) caller.ReportProgress(0, "Getting Airline " + i.ToString() + " of"); } } reader.Close(); return l; } public List AirlineFromJSON(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 AirlineToJSON() { List l = AirlineGetAll(); 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 DataTableAirlines AirlineToDataTable() { List lds = AirlineGetAll(); DataTableAirlines dtl = new DataTableAirlines(lds); return dtl; } #endregion #region Airports public bool AirportTableExists(string tablename = "") { // check for table name is null or empty --> use default tablename from type instead string tn = tablename; if (String.IsNullOrEmpty(tn)) tn = AirportDesignator.TableName; return db.TableExists(tn); } public void AirportCreateTable(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 = AirportDesignator.TableName; db.DBCommand.CommandText = "CREATE TABLE `" + tn + "`(ICAO TEXT NOT NULL DEFAULT '', IATA TEXT NOT NULL DEFAULT '', Lat DOUBLE, Lon DOUBLE, Alt DOUBLE, Airport TEXT, Country TEXT, LastUpdated INT32, PRIMARY KEY (ICAO, IATA))"; db.DBCommand.Parameters.Clear(); db.Execute(db.DBCommand); // create table indices db.DBCommand.CommandText = "CREATE INDEX idx_" + tn + "_ICAO ON `" + tn + "` (ICAO)"; db.DBCommand.Parameters.Clear(); db.Execute(db.DBCommand); db.DBCommand.CommandText = "CREATE INDEX idx_" + tn + "_IATA ON `" + tn + "` (IATA)"; db.DBCommand.Parameters.Clear(); db.Execute(db.DBCommand); } } public long AirportCount() { object count = db.ExecuteScalar("SELECT COUNT(*) FROM " + AirportDesignator.TableName); if (IsValid(count)) return (long)count; return 0; } public bool AirportExists(string icao, string iata) { AirportDesignator pd = new AirportDesignator(icao, iata); return AirportExists(pd); } public bool AirportExists(AirportDesignator pd) { lock (db.DBCommand) { db.DBCommand.CommandText = "SELECT EXISTS (SELECT LastUpdated FROM " + AirportDesignator.TableName + " WHERE ICAO = @ICAO AND IATA = @IATA"; db.DBCommand.Parameters.Clear(); db.DBCommand.Parameters.Add(pd.AsString("ICAO")); db.DBCommand.Parameters.Add(pd.AsString("IATA")); object result = db.DBCommand.ExecuteScalar(); if (IsValid(result) && ((long)result > 0)) return true; } return false; } public AirportDesignator AirportFindByICAO(string icao) { // returs entry by search string, latest entry if more than one entry found if (String.IsNullOrEmpty(icao)) return null; lock (db.DBCommand) { db.DBCommand.CommandText = "SELECT * FROM " + AirportDesignator.TableName + " WHERE ICAO = '" + icao + "' ORDER BY LastUpdated DESC LIMIT 1"; db.DBCommand.Parameters.Clear(); try { DataTable Result = db.Select(db.DBCommand); if ((Result != null) && (Result.Rows.Count > 0)) { return new AirportDesignator(Result.Rows[0]); } } catch (Exception ex) { Log.WriteMessage(ex.ToString(), LogLevel.Error); } } return null; } public AirportDesignator AirportFindByIATA(string iata) { // returs entry by search string, latest entry if more than one entry found if (String.IsNullOrEmpty(iata)) return null; lock (db.DBCommand) { db.DBCommand.CommandText = "SELECT * FROM " + AirportDesignator.TableName + " WHERE IATA = '" + iata + "' ORDER BY LastUpdated DESC LIMIT 1"; db.DBCommand.Parameters.Clear(); try { DataTable Result = db.Select(db.DBCommand); if ((Result != null) && (Result.Rows.Count > 0)) { return new AirportDesignator(Result.Rows[0]); } } catch (Exception ex) { Log.WriteMessage(ex.ToString(), LogLevel.Error); } } return null; } public AirportDesignator AirportFind(string icao, string iata) { AirportDesignator pd = new AirportDesignator(icao, iata); return AirportFind(pd); } public AirportDesignator AirportFind(AirportDesignator pd) { lock (db.DBCommand) { db.DBCommand.CommandText = "SELECT * FROM " + AirportDesignator.TableName + " WHERE ICAO = @ICAO AND IATA = @IATA"; db.DBCommand.Parameters.Clear(); db.DBCommand.Parameters.Add(pd.AsString("ICAO")); db.DBCommand.Parameters.Add(pd.AsString("IATA")); try { DataTable Result = db.Select(db.DBCommand); if ((Result != null) && (Result.Rows.Count > 0)) { return new AirportDesignator(Result.Rows[0]); } } catch (Exception ex) { Log.WriteMessage(ex.ToString(), LogLevel.Error); } } return null; } public AirportDesignator AirportFindAt(long index) { lock (db.DBCommand) { db.DBCommand.CommandText = "SELECT * FROM " + AirportDesignator.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 AirportDesignator(Result.Rows[0]); } } catch (Exception ex) { Log.WriteMessage(ex.ToString(), LogLevel.Error); } } return null; } public DateTime AirportFindlastUpdated(string icao, string iata) { AirportDesignator pd = new AirportDesignator(icao, iata); return AirportFindLastUpdated(pd); } public DateTime AirportFindLastUpdated(AirportDesignator pd) { lock (db.DBCommand) { db.DBCommand.CommandText = "SELECT LastUpdated FROM " + AirportDesignator.TableName + " WHERE ICAO = @ICAO AND IATA = @IATA"; db.DBCommand.Parameters.Clear(); db.DBCommand.Parameters.Add(pd.AsString("ICAO")); db.DBCommand.Parameters.Add(pd.AsString("IATA")); object result = db.ExecuteScalar(db.DBCommand); if (IsValid(result)) return (SQLiteEntry.UNIXTimeToDateTime((int)result)); } return DateTime.MinValue; } public int AirportInsert(AirportDesignator pd) { lock (db.DBCommand) { db.DBCommand.CommandText = "INSERT INTO " + AirportDesignator.TableName + " (ICAO, IATA, Lat, Lon, Alt, Airport, Country, LastUpdated) VALUES (@ICAO, @IATA, @Lat, @Lon, @Alt, @Airport, @Country, @LastUpdated)"; db.DBCommand.Parameters.Clear(); db.DBCommand.Parameters.Add(pd.AsString("ICAO")); db.DBCommand.Parameters.Add(pd.AsString("IATA")); db.DBCommand.Parameters.Add(pd.AsDouble("Lat")); db.DBCommand.Parameters.Add(pd.AsDouble("Lon")); db.DBCommand.Parameters.Add(pd.AsDouble("Alt")); db.DBCommand.Parameters.Add(pd.AsString("Airport")); db.DBCommand.Parameters.Add(pd.AsString("Country")); db.DBCommand.Parameters.Add(pd.AsUNIXTime("LastUpdated")); return db.ExecuteNonQuery(db.DBCommand); } } public int AirportDelete(string icao, string iata) { AirportDesignator pd = new AirportDesignator(iata, icao); return AirportDelete(pd); } public int AirportDelete(AirportDesignator pd) { lock (db.DBCommand) { db.DBCommand.CommandText = "DELETE FROM " + AirportDesignator.TableName + " WHERE ICAO = @ICAO AND IATA = @IATA"; db.DBCommand.Parameters.Clear(); db.DBCommand.Parameters.Add(pd.AsString("ICAO")); db.DBCommand.Parameters.Add(pd.AsString("IATA")); return db.ExecuteNonQuery(db.DBCommand); } } public int AirportDeleteAll() { lock (db.DBCommand) { db.DBCommand.CommandText = "DELETE FROM " + AirportDesignator.TableName; db.DBCommand.Parameters.Clear(); return db.ExecuteNonQuery(db.DBCommand); } } public int AirportUpdate(AirportDesignator pd) { lock (db.DBCommand) { db.DBCommand.CommandText = "UPDATE " + AirportDesignator.TableName + " SET ICAO = @ICAO, IATA = @IATA, Lat = @Lat, Lon = @Lon, Alt = @Alt, Airport = @Airport, Country = @Country, LastUpdated = @LastUpdated WHERE ICAO = @ICAO AND IATA = @IATA"; db.DBCommand.Parameters.Clear(); db.DBCommand.Parameters.Add(pd.AsString("ICAO")); db.DBCommand.Parameters.Add(pd.AsString("IATA")); db.DBCommand.Parameters.Add(pd.AsDouble("Lat")); db.DBCommand.Parameters.Add(pd.AsDouble("Lon")); db.DBCommand.Parameters.Add(pd.AsDouble("Alt")); db.DBCommand.Parameters.Add(pd.AsString("Airport")); db.DBCommand.Parameters.Add(pd.AsString("Country")); db.DBCommand.Parameters.Add(pd.AsUNIXTime("LastUpdated")); return db.ExecuteNonQuery(db.DBCommand); } } public int AirportBulkInsert(List pds) { int errors = 0; try { lock (db) { db.BeginTransaction(); foreach (AirportDesignator pd in pds) { try { AirportInsert(pd); } catch (Exception ex) { Log.WriteMessage("Error inserting Airport [" + pd.ICAO + ", " + pd.IATA + "]: " + ex.ToString(), LogLevel.Error); errors++; } } db.Commit(); } } catch (Exception ex) { Log.WriteMessage(ex.ToString(), LogLevel.Error); } return -errors; } public int AirportBulkDelete(List pds) { int errors = 0; try { lock (db) { db.BeginTransaction(); foreach (AirportDesignator pd in pds) { try { AirportDelete(pd); } catch (Exception ex) { Log.WriteMessage("Error inserting Airport [" + pd.ICAO + ", " + pd.IATA + "]: " + ex.ToString(), LogLevel.Error); errors++; } } db.Commit(); } } catch (Exception ex) { Log.WriteMessage(ex.ToString(), LogLevel.Error); } return -errors; } public int AirportBulkInsertOrUpdateIfNewer(List pds) { if (pds == null) return 0; int i = 0; lock (db) { db.BeginTransaction(); foreach (AirportDesignator pd in pds) { AirportInsertOrUpdateIfNewer(pd); i++; } db.Commit(); } return i; } public int AirportInsertOrUpdateIfNewer(AirportDesignator pd) { DateTime dt = AirportFindLastUpdated(pd); if (dt == DateTime.MinValue) return AirportInsert(pd); if (dt < pd.LastUpdated) return AirportUpdate(pd); return 0; } public List AirportGetAll() { List l = new List(); DataTable Result = db.Select("SELECT * FROM " + AirportDesignator.TableName); if (!IsValid(Result) || (Result.Rows.Count == 0)) return l; foreach (DataRow row in Result.Rows) l.Add(new AirportDesignator(row)); return l; } public List AirportGetAll(BackgroundWorker caller) { // gets all Airports from database // supports abort calculation if called from background worker and cancellation requested List l = new List(); int i = 0; SQLiteCommand cmd = new SQLiteCommand(db.DBConnection); cmd.CommandText = "SELECT * FROM " + AirportDesignator.TableName; SQLiteDataReader reader = cmd.ExecuteReader(); while (reader.Read()) { AirportDesignator ap = new AirportDesignator((IDataRecord)reader); l.Add(ap); i++; // abort calculation if called from background worker and cancellation pending if (caller != null) { if (caller.WorkerSupportsCancellation && caller.CancellationPending) return new List(); if (caller.WorkerSupportsCancellation && caller.WorkerReportsProgress && (i % 1000 == 0)) caller.ReportProgress(0, "Getting Airport " + i.ToString() + " of"); } } reader.Close(); return l; } public List AirportFromJSON(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 AirportToJSON() { List l = AirportGetAll(); 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 DataTableAirports AirportToDataTable() { List lds = AirportGetAll(); DataTableAirports dtl = new DataTableAirports(lds); return dtl; } #endregion #region AircraftRegistrations public bool AircraftRegistrationTableExists(string tablename = "") { // check for table name is null or empty --> use default tablename from type instead string tn = tablename; if (String.IsNullOrEmpty(tn)) tn = AircraftRegistrationDesignator.TableName; return db.TableExists(tn); } public void AircraftRegistrationCreateTable(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 = AircraftRegistrationDesignator.TableName; db.DBCommand.CommandText = "CREATE TABLE `" + tn + "`(Prefix TEXT NOT NULL DEFAULT '', Country TEXT, Remarks TEXT, LastUpdated INT32, PRIMARY KEY (Prefix))"; db.DBCommand.Parameters.Clear(); db.Execute(db.DBCommand); } } public long AircraftRegistrationCount() { object count = db.ExecuteScalar("SELECT COUNT(*) FROM " + AircraftRegistrationDesignator.TableName); if (IsValid(count)) return (long)count; return 0; } public bool AircraftRegistrationExists(string prefix) { AircraftRegistrationDesignator rd = new AircraftRegistrationDesignator(prefix); return AircraftRegistrationExists(rd); } public bool AircraftRegistrationExists(AircraftRegistrationDesignator rd) { lock (db.DBCommand) { db.DBCommand.CommandText = "SELECT EXISTS (SELECT LastUpdated FROM " + AircraftRegistrationDesignator.TableName + " WHERE Prefix = @Prefix"; db.DBCommand.Parameters.Clear(); db.DBCommand.Parameters.Add(rd.AsString("Prefix")); object result = db.DBCommand.ExecuteScalar(); if (IsValid(result) && ((long)result > 0)) return true; } return false; } private long AircraftRegistrationGetMaxLength() { lock (db.DBCommand) { db.DBCommand.CommandText = "SELECT max(length(Prefix)) FROM " + AircraftRegistrationDesignator.TableName; db.DBCommand.Parameters.Clear(); object result = db.DBCommand.ExecuteScalar(); if (IsValid(result)) return (long)result; } return 0; } private long AircraftRegistrationGetMinLength() { lock (db.DBCommand) { db.DBCommand.CommandText = "SELECT min(length(Prefix)) FROM " + AircraftRegistrationDesignator.TableName; db.DBCommand.Parameters.Clear(); object result = db.DBCommand.ExecuteScalar(); if (IsValid(result)) return (long)result; } return 0; } public AircraftRegistrationDesignator AircraftRegistrationFindByReg(string reg) { if (String.IsNullOrEmpty(reg)) return null; reg = reg.ToUpper().Trim(); // check for US registration --> insert '-' after first letter if (reg.StartsWith("N")) { if (Char.IsDigit(reg[1])) reg = reg[0] + "-" + reg.Substring(1); else return null; } // return null if not a registration if (reg.IndexOf("-") == 0) return null; // stop search at char before '-' should be clean prefix then int stop = reg.IndexOf("-") - 1; // start search two chars after '-' int i = stop + 2; while (i >= stop) { AircraftRegistrationDesignator rd = AircraftRegistrationFind(reg.Substring(0, i)); if (rd != null) return rd; i--; } return null; } public AircraftRegistrationDesignator AircraftRegistrationFind(string prefix) { AircraftRegistrationDesignator rd = new AircraftRegistrationDesignator(prefix); return AircraftRegistrationFind(rd); } public AircraftRegistrationDesignator AircraftRegistrationFind(AircraftRegistrationDesignator rd) { lock (db.DBCommand) { db.DBCommand.CommandText = "SELECT * FROM " + AircraftRegistrationDesignator.TableName + " WHERE Prefix = @Prefix"; db.DBCommand.Parameters.Clear(); db.DBCommand.Parameters.Add(rd.AsString("Prefix")); try { DataTable Result = db.Select(db.DBCommand); if ((Result != null) && (Result.Rows.Count > 0)) { return new AircraftRegistrationDesignator(Result.Rows[0]); } } catch (Exception ex) { Log.WriteMessage(ex.ToString(), LogLevel.Error); } } return null; } public AircraftRegistrationDesignator AircraftRegistrationFindAt(long index) { lock (db.DBCommand) { db.DBCommand.CommandText = "SELECT * FROM " + AircraftRegistrationDesignator.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 AircraftRegistrationDesignator(Result.Rows[0]); } } catch (Exception ex) { Log.WriteMessage(ex.ToString(), LogLevel.Error); } } return null; } public DateTime AircraftRegistrationFindlastUpdated(string prefix) { AircraftRegistrationDesignator rd = new AircraftRegistrationDesignator(prefix); return AircraftRegistrationFindLastUpdated(rd); } public DateTime AircraftRegistrationFindLastUpdated(AircraftRegistrationDesignator rd) { lock (db.DBCommand) { db.DBCommand.CommandText = "SELECT LastUpdated FROM " + AircraftRegistrationDesignator.TableName + " WHERE Prefix = @Prefix"; db.DBCommand.Parameters.Clear(); db.DBCommand.Parameters.Add(rd.AsString("Prefix")); object result = db.ExecuteScalar(db.DBCommand); if (IsValid(result)) return (SQLiteEntry.UNIXTimeToDateTime((int)result)); } return DateTime.MinValue; } public int AircraftRegistrationInsert(AircraftRegistrationDesignator rd) { // maintain max/min lengths if (rd.Prefix.Length < AircraftRegistrationMinLength) AircraftRegistrationMinLength = rd.Prefix.Length; if (rd.Prefix.Length > AircraftRegistrationMaxLength) AircraftRegistrationMaxLength = rd.Prefix.Length; lock (db.DBCommand) { db.DBCommand.CommandText = "INSERT INTO " + AircraftRegistrationDesignator.TableName + " (Prefix, Country, Remarks, LastUpdated) VALUES (@Prefix, @Country, @Remarks, @LastUpdated)"; db.DBCommand.Parameters.Clear(); db.DBCommand.Parameters.Add(rd.AsString("Prefix")); db.DBCommand.Parameters.Add(rd.AsString("Country")); db.DBCommand.Parameters.Add(rd.AsString("Remarks")); db.DBCommand.Parameters.Add(rd.AsUNIXTime("LastUpdated")); return db.ExecuteNonQuery(db.DBCommand); } } public int AircraftRegistrationDelete(string prefix) { AircraftRegistrationDesignator rd = new AircraftRegistrationDesignator(prefix); return AircraftRegistrationDelete(rd); } public int AircraftRegistrationDelete(AircraftRegistrationDesignator rd) { lock (db.DBCommand) { db.DBCommand.CommandText = "DELETE FROM " + AircraftRegistrationDesignator.TableName + " WHERE Prefix = @Prefix"; db.DBCommand.Parameters.Clear(); db.DBCommand.Parameters.Add(rd.AsString("Prefix")); return db.ExecuteNonQuery(db.DBCommand); } } public int AircraftRegistrationDeleteAll() { lock (db.DBCommand) { db.DBCommand.CommandText = "DELETE FROM " + AircraftRegistrationDesignator.TableName; db.DBCommand.Parameters.Clear(); return db.ExecuteNonQuery(db.DBCommand); } } public int AircraftRegistrationUpdate(AircraftRegistrationDesignator rd) { lock (db.DBCommand) { db.DBCommand.CommandText = "UPDATE " + AircraftRegistrationDesignator.TableName + " SET Prefix = @Prefix, Country = @Country, Remarks = @Remarks, LastUpdated = @LastUpdated WHERE Prefix = @Prefix"; db.DBCommand.Parameters.Clear(); db.DBCommand.Parameters.Add(rd.AsString("Prefix")); db.DBCommand.Parameters.Add(rd.AsString("Country")); db.DBCommand.Parameters.Add(rd.AsString("Remarks")); db.DBCommand.Parameters.Add(rd.AsUNIXTime("LastUpdated")); return db.ExecuteNonQuery(db.DBCommand); } } public int AircraftRegistrationBulkInsert(List rds) { int errors = 0; try { lock (db) { db.BeginTransaction(); foreach (AircraftRegistrationDesignator rd in rds) { try { AircraftRegistrationInsert(rd); } catch (Exception ex) { Log.WriteMessage("Error inserting AircraftRegistration [" + rd.Prefix + "]: " + ex.ToString(), LogLevel.Error); errors++; } } db.Commit(); } } catch (Exception ex) { Log.WriteMessage(ex.ToString(), LogLevel.Error); } return -errors; } public int AircraftRegistrationBulkDelete(List rds) { int errors = 0; try { lock (db) { db.BeginTransaction(); foreach (AircraftRegistrationDesignator rd in rds) { try { AircraftRegistrationDelete(rd); } catch (Exception ex) { Log.WriteMessage("Error deleting AircraftRegistration [" + rd.Prefix + "]: " + ex.ToString(), LogLevel.Error); errors++; } } db.Commit(); } } catch (Exception ex) { Log.WriteMessage(ex.ToString(), LogLevel.Error); } return -errors; } public int AircraftRegistrationBulkInsertOrUpdateIfNewer(List rds) { if (rds == null) return 0; int i = 0; lock (db) { db.BeginTransaction(); foreach (AircraftRegistrationDesignator rd in rds) { AircraftRegistrationInsertOrUpdateIfNewer(rd); i++; } db.Commit(); } return i; } public int AircraftRegistrationInsertOrUpdateIfNewer(AircraftRegistrationDesignator rd) { DateTime dt = AircraftRegistrationFindLastUpdated(rd); if (dt == DateTime.MinValue) return AircraftRegistrationInsert(rd); if (dt < rd.LastUpdated) return AircraftRegistrationUpdate(rd); return 0; } public List AircraftRegistrationGetAll() { List l = new List(); DataTable Result = db.Select("SELECT * FROM " + AircraftRegistrationDesignator.TableName); if (!IsValid(Result) || (Result.Rows.Count == 0)) return l; foreach (DataRow row in Result.Rows) l.Add(new AircraftRegistrationDesignator(row)); return l; } public List AircraftRegistrationGetAll(BackgroundWorker caller) { // gets all AircraftRegistrations from database // supports abort calculation if called from background worker and cancellation requested List l = new List(); int i = 0; SQLiteCommand cmd = new SQLiteCommand(db.DBConnection); cmd.CommandText = "SELECT * FROM " + AircraftRegistrationDesignator.TableName; SQLiteDataReader reader = cmd.ExecuteReader(); while (reader.Read()) { AircraftRegistrationDesignator ap = new AircraftRegistrationDesignator((IDataRecord)reader); l.Add(ap); i++; // abort calculation if called from background worker and cancellation pending if (caller != null) { if (caller.WorkerSupportsCancellation && caller.CancellationPending) return new List(); if (caller.WorkerReportsProgress && (i % 1000 == 0)) caller.ReportProgress(0, "Getting AircraftRegistration " + i.ToString() + " of"); } } reader.Close(); return l; } public List AircraftRegistrationFromJSON(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 AircraftRegistrationToJSON() { List l = AircraftRegistrationGetAll(); 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 DataTableAircraftRegistrations AircraftRegistrationToDataTable() { List rds = AircraftRegistrationGetAll(); DataTableAircraftRegistrations dtl = new DataTableAircraftRegistrations(rds); return dtl; } #endregion #region PlaneInfo public void PlaneInfoCreateView() { lock (db.DBCommand) { db.DBCommand.CommandText = "CREATE VIEW IF NOT EXISTS view_PlaneInfo AS SELECT AircraftPositions.LastUpdated, Call, Reg, AircraftPositions.Hex, Lat, Lon, Track, Alt, Speed, TypeCode, Manufacturer, Model, Category FROM AircraftPositions INNER JOIN Aircrafts ON AircraftPositions.Hex = Aircrafts.Hex INNER JOIN AircraftTypes ON AircraftTypes.ICAO = Aircrafts.TypeCode"; db.DBCommand.Parameters.Clear(); object result = db.DBCommand.ExecuteNonQuery(); } } public int PlaneInfoBulkInsertOrUpdateIfNewer(List planes) { if (planes == null) return 0; int i = 0; lock (db) { db.BeginTransaction(); foreach (PlaneInfo plane in planes) { try { // update aircraft information if (PlaneInfoChecker.Check_Hex(plane.Hex) && PlaneInfoChecker.Check_Call(plane.Call) && PlaneInfoChecker.Check_Reg(plane.Reg) && PlaneInfoChecker.Check_Type(plane.Type)) AircraftData.Database.AircraftInsertOrUpdateIfNewer(new AircraftDesignator(plane.Hex, plane.Call, plane.Reg, plane.Type, plane.Time)); // update aircraft type information if (!String.IsNullOrEmpty(plane.Type)) { AircraftTypeInsertOrUpdateIfNewer(new AircraftTypeDesignator("", plane.Type, plane.Manufacturer, plane.Model, plane.Category, DateTime.UtcNow)); } } catch (Exception ex) { Log.WriteMessage(ex.ToString(), LogLevel.Error); return -1; } } db.Commit(); } return i; } public int PlaneInfoBulkInsertOrUpdateIfNewer(BackgroundWorker caller, List planes) { if (planes == null) return 0; int i = 0; lock (db) { db.BeginTransaction(); foreach (PlaneInfo plane in planes) { try { // update aircraft information if (!String.IsNullOrEmpty(plane.Hex) && !String.IsNullOrEmpty(plane.Reg) && !String.IsNullOrEmpty(plane.Type)) AircraftData.Database.AircraftInsertOrUpdateIfNewer(new AircraftDesignator(plane.Hex, plane.Call, plane.Reg, plane.Type, plane.Time)); // update aircraft type information if (!String.IsNullOrEmpty(plane.Type)) { AircraftTypeInsertOrUpdateIfNewer(new AircraftTypeDesignator("", plane.Type, plane.Manufacturer, plane.Model, plane.Category, DateTime.UtcNow)); } } catch (Exception ex) { db.Rollback(); Log.WriteMessage(ex.ToString(), LogLevel.Error); return -1; } // abort if called from background worker and cancellation pending if (caller != null) { if (caller.WorkerSupportsCancellation && caller.CancellationPending) { db.Rollback(); return -1; } } } db.Commit(); } return i; } public List PlaneInfoGetAll(DateTime newerthan) { List l = new List(); int i = SupportFunctions.DateTimeToUNIXTime(newerthan); // SELECT max(AircraftPositions.Lastupdated) AS LastUpdated, Call, Reg, AircraftPositions.Hex, Lat, Lon, Track, Alt, Speed, TypeCode, Manufacturer, Model, Category FROM AircraftPositions INNER JOIN Aircrafts ON AircraftPositions.Hex = Aircrafts.Hex INNER JOIN AircraftTypes ON AircraftTypes.ICAO = Aircrafts.TypeCode WHERE AircraftPositions.LastUpdated > 1500000 GROUP BY AircraftPositions.Hex DataTable Result = db.Select("SELECT max(AircraftPositions.Lastupdated) AS LastUpdated, Call, Reg, AircraftPositions.Hex, Lat, Lon, Track, Alt, Speed, TypeCode, Manufacturer, Model, Category FROM AircraftPositions INNER JOIN Aircrafts ON AircraftPositions.Hex = Aircrafts.Hex INNER JOIN AircraftTypes ON AircraftTypes.ICAO = Aircrafts.TypeCode WHERE AircraftPositions.LastUpdated > " + i.ToString() + " GROUP BY AircraftPositions.Hex"); if (!IsValid(Result) || (Result.Rows.Count == 0)) return l; foreach (DataRow row in Result.Rows) { PlaneInfo info = new PlaneInfo(row); try { l.Add(info); } catch (Exception ex) { Log.WriteMessage("Error inserting PlaneInfo[" + info.ToString() + "]: " + ex.ToString(), LogLevel.Error); } } return l; } /// /// Gets a list of aircraft infos at a time. /// Querying the latest position entry per aircraft but not older than ttl back in history /// and estimating the position at given time /// The given time. /// "Time To Live": discard positions which are older than ttl [min]. /// /// public List PlaneInfoGetAll(DateTime at, int ttl) { List l = new List(); int to = SupportFunctions.DateTimeToUNIXTime(at); int from = to - ttl * 60; DataTable Result = db.Select("SELECT max(AircraftPositions.Lastupdated) AS LastUpdated, Call, Reg, AircraftPositions.Hex, Lat, Lon, Track, Alt, Speed, TypeCode, Manufacturer, Model, Category FROM AircraftPositions INNER JOIN Aircrafts ON AircraftPositions.Hex = Aircrafts.Hex INNER JOIN AircraftTypes ON AircraftTypes.ICAO = Aircrafts.TypeCode WHERE AircraftPositions.LastUpdated >= " + from.ToString() + " AND AircraftPositions.LastUpdated <= " + to.ToString() + " GROUP BY AircraftPositions.Hex"); // DataTable Result = db.Select("SELECT max(Lastupdated) AS LastUpdated, Call, Reg, Hex, Lat, Lon, Track, Alt, Speed, TypeCode, Manufacturer, Model, Category FROM view_PlaneInfo WHERE LastUpdated > " + from.ToString() + " AND LastUpdated <= " + to.ToString() + " GROUP BY Hex"); if (!IsValid(Result) || (Result.Rows.Count == 0)) return l; foreach (DataRow row in Result.Rows) { PlaneInfo info = new PlaneInfo(row); //estimate new position // change speed to km/h double speed = info.Speed_kmh; // calculate distance after timespan double dist = speed * (at - info.Time).TotalHours; // estimate new position LatLon.GPoint newpos = LatLon.DestinationPoint(info.Lat, info.Lon, info.Track, dist); info.Lat = newpos.Lat; info.Lon = newpos.Lon; info.Time = at; l.Add(info); } return l; } // selects all planes from a list which are in range of the midpoint of a given propagation path public List GetNearestPlanes(DateTime at, PropagationPathDesignator ppath, List planes, double maxradius, double maxdist, double maxalt) { List l = new List(); // return empty list on empty list or null if (planes == null) return l; if (planes.Count() == 0) return l; // adjust maxradius when automatic calculation is required if (maxradius < 0) maxradius = double.MaxValue; if (maxradius == 0) maxradius = ppath.Distance / 2; // get midpoint value double midlat = ppath.GetMidPoint().Lat; double midlon = ppath.GetMidPoint().Lon; try { // StreamWriter sw = new StreamWriter("GetNearestPlanes.csv"); // sw.WriteLine("utc;hex;call;lat;lon;alt;speed;track;maxdist"); // get intersection info for each plane in list foreach (PlaneInfo info in planes) { PlaneInfo plane; try { // skip if plane is out of range double dist = LatLon.Distance(midlat, midlon, info.Lat, info.Lon); /* sw.WriteLine(info.Time.ToString() + ";" + info.Hex + ";" + info.Call + ";" + info.Lat.ToString("") + ";" + info.Lon.ToString("") + ";" + info.Alt_m.ToString("") + ";" + info.Speed_kmh.ToString("") + ";" + info.Track.ToString("") + ";" + maxdist.ToString("")); */ if (dist > maxradius) continue; // clone object plane = new PlaneInfo(info.Time, info.Call, info.Reg, info.Hex, info.Lat, info.Lon, info.Track, info.Alt, info.Speed, info.Type, info.Manufacturer, info.Model, info.Category); //estimate new position // change speed to km/h double speed = info.Speed_kmh; // calculate distance after timespan double di = speed * (at - info.Time).TotalHours; // estimate new position LatLon.GPoint newpos = LatLon.DestinationPoint(info.Lat, info.Lon, info.Track, di); info.Lat = newpos.Lat; info.Lon = newpos.Lon; info.Time = at; // Test!!! if (info.Call.StartsWith("xxx")) { int k = 3; } // calculate four possible intersections // i1 --> plane heading // i2 --> plane heading +90° // i3 --> plane heading - 90° // i4 --> opposite plane heading // imin --> intpoint with shortest distance IntersectionPoint imin = null; IntersectionPoint i1 = null; IntersectionPoint i2 = null; IntersectionPoint i3 = null; IntersectionPoint i4 = null; Stopwatch st = new Stopwatch(); i1 = ppath.GetIntersectionPoint(plane.Lat, plane.Lon, plane.Track, 0); i2 = ppath.GetIntersectionPoint(plane.Lat, plane.Lon, ppath.Bearing12 - 90, 0); // calculate right opposite direction only if no left intersection was found if (i2 == null) i3 = ppath.GetIntersectionPoint(plane.Lat, plane.Lon, ppath.Bearing12 + 90, 0); // calcalute opposite direction only if no forward intersection was found if (i1 == null) i4 = ppath.GetIntersectionPoint(plane.Lat, plane.Lon, plane.Track - 180, 0); // find the minimum distance first if (i1 != null) imin = i1; if ((i2 != null) && ((imin == null) || (i2.QRB < imin.QRB))) imin = i2; if ((i3 != null) && ((imin == null) || (i3.QRB < imin.QRB))) imin = i3; if ((i4 != null) && ((imin == null) || (i4.QRB < imin.QRB))) imin = i4; // check hot planes which are very near the path first if ((imin != null) && (imin.QRB <= maxdist) && (imin.Dist1 <= ppath.Distance)) { // plane is near path // use the minimum qrb info plane.IntPoint = new LatLon.GPoint(imin.Lat, imin.Lon); plane.IntQRB = imin.QRB; plane.AltDiff = plane.Alt_m - imin.Min_H; double c1 = LatLon.Bearing(plane.IntPoint.Lat, plane.IntPoint.Lon, ppath.Lat2, ppath.Lon2); double c2 = plane.Track; double ca = c1 - c2; if (ca < 0) ca = ca + 360; if ((ca > 180) && (ca < 360)) ca = 360 - ca; // save in rad plane.Angle = ca / 180.0 * Math.PI; plane.Eps1 = Propagation.EpsilonFromHeights(ppath.h1, imin.Dist1, plane.Alt_m, ppath.Radius); plane.Eps2 = Propagation.EpsilonFromHeights(ppath.h2, imin.Dist2, plane.Alt_m, ppath.Radius); plane.Theta1 = Propagation.ThetaFromHeights(ppath.h1, imin.Dist1, plane.Alt_m, ppath.Radius); plane.Theta2 = Propagation.ThetaFromHeights(ppath.h2, imin.Dist2, plane.Alt_m, ppath.Radius); plane.Squint = Math.Abs(Propagation.ThetaFromHeights(ppath.h1, imin.Dist1, plane.Alt_m, ppath.Radius) - Propagation.ThetaFromHeights(ppath.h2, imin.Dist2, plane.Alt_m, ppath.Radius)); if (plane.AltDiff > 0) { // plane is high enough plane.Potential = 100; } else if (imin.Min_H <= maxalt) { // plane is not high enough yet but might be in the future plane.Potential = 50; } else { // minimal needed altitude is higher than Planes_MaxAlt --> no way to reach // plane is not interesting plane.Potential = 0; } } else { // plane is far from path --> check only intersection i1 = planes moves towards path if ((i1 != null) && (i1.Min_H <= maxalt) && (i1.Dist1 <= ppath.Distance)) { plane.IntPoint = new LatLon.GPoint(i1.Lat, i1.Lon); plane.IntQRB = i1.QRB; plane.AltDiff = plane.Alt_m - i1.Min_H; plane.Eps1 = Propagation.EpsilonFromHeights(ppath.h1, i1.Dist1, plane.Alt_m, ppath.Radius); plane.Eps2 = Propagation.EpsilonFromHeights(ppath.h2, i1.Dist2, plane.Alt_m, ppath.Radius); plane.Squint = Math.Abs(Propagation.ThetaFromHeights(ppath.h1, imin.Dist1, plane.Alt_m, ppath.Radius) - Propagation.ThetaFromHeights(ppath.h2, imin.Dist2, plane.Alt_m, ppath.Radius)); if (plane.AltDiff > 0) { // plane wil cross path in a suitable altitude plane.Potential = 75; } else { // plane wil cross path not in a suitable altitude plane.Potential = 50; } } else { // plane is not interesting plane.Potential = 0; } } // add plane to list l.Add(plane); } catch (Exception ex) { Log.WriteMessage(ex.ToString(), LogLevel.Error); } } } catch (Exception ex) { Log.WriteMessage(ex.ToString(), LogLevel.Error); } return l; } #endregion } }