2020-02-12 10:45:19 +00:00
using System ;
using System.Collections.Generic ;
using System.Linq ;
using System.Text ;
using System.Reflection ;
using System.ComponentModel.Composition ;
using System.ComponentModel ;
using System.Globalization ;
using AirScout.PlaneFeeds.Plugin.MEFContract ;
using System.Diagnostics ;
using System.Net ;
using System.IO ;
using System.Web.Script.Serialization ;
using System.Xml.Serialization ;
using System.Windows.Forms ;
using AirScout.PlaneFeeds.Plugin ;
using System.Xml ;
using System.Xml.Linq ;
namespace AirScout.PlaneFeeds.Plugin.FlexJSON
{
[Serializable]
public class FlexJSONSettings
{
[CategoryAttribute("Data Field Properties")]
[DescriptionAttribute("Index for UTC [OPTIONAL] . Use - 1 for detect , 255 for not used . ")]
[DefaultValue(-1)]
public int Index_UTC { get ; set ; }
[CategoryAttribute("Data Field Properties")]
[DescriptionAttribute("Index for Hex [OPTIONAL] . Use - 1 for detect , 255 for not used . ")]
[DefaultValue(-1)]
public int Index_Hex { get ; set ; }
[CategoryAttribute("Data Field Properties")]
[DescriptionAttribute("Index for Call [OPTIONAL] . Use - 1 for detect , 255 for not used . ")]
[DefaultValue(-1)]
public int Index_Call { get ; set ; }
[CategoryAttribute("Data Field Properties")]
[DescriptionAttribute("Index for Latitude [deg] [ MANDATORY ] . Use - 1 for detect , 255 for not used . ")]
[DefaultValue(-1)]
public int Index_Lat { get ; set ; }
[CategoryAttribute("Data Field Properties")]
[DescriptionAttribute("Index for Longitde [deg] [ MANDATORY ] . Use - 1 for detect , 255 for not used . ")]
[DefaultValue(-1)]
public int Index_Lon { get ; set ; }
[CategoryAttribute("Data Field Properties")]
[DescriptionAttribute("Index for Altitude [ft, m] [ MANDATORY ] . Use - 1 for detect , 255 for not used . ")]
[DefaultValue(-1)]
public int Index_Alt { get ; set ; }
[CategoryAttribute("Data Field Properties")]
[DescriptionAttribute("Units for Altitude [ft, m] ")]
[DefaultValue("ft")]
public string Units_Alt { get ; set ; }
[CategoryAttribute("Data Field Properties")]
[DescriptionAttribute("Index for Speed [kts, km/h] [ MANDATORY ] . Use - 1 for detect , 255 for not used . ")]
[DefaultValue(-1)]
public int Index_Speed { get ; set ; }
[CategoryAttribute("Data Field Properties")]
[DescriptionAttribute("Units for Speed [kts, km/h] ")]
[DefaultValue("kts")]
public string Units_Speed { get ; set ; }
[CategoryAttribute("Data Field Properties")]
[DescriptionAttribute("Index for Track in [deg] [ MANDATORY ] . Use - 1 for detect , 255 for not used . ")]
[DefaultValue(-1)]
public int Index_Track { get ; set ; }
[CategoryAttribute("Data Field Properties")]
[DescriptionAttribute("Index for Type [OPTIONAL] . Use - 1 for detect , 255 for not used . ")]
[DefaultValue(-1)]
public int Index_Type { get ; set ; }
[CategoryAttribute("Data Field Properties")]
[DescriptionAttribute("Index for Registration [OPTIONAL] . Use - 1 for detect , 255 for not used . ")]
[DefaultValue(-1)]
public int Index_Reg { get ; set ; }
[CategoryAttribute("Data Field Properties")]
[DescriptionAttribute("Minimum Count of Elements per Plane Position Data Set")]
[DefaultValue(10)]
public int Min_Elements { get ; set ; }
[CategoryAttribute("Data Field Properties")]
[DescriptionAttribute("Minium Count of Plane Position Data Sets")]
[DefaultValue(50)]
public int Min_Planes { get ; set ; }
[Browsable(false)]
[DefaultValue("")]
[XmlIgnore]
public string DisclaimerAccepted { get ; set ; }
[CategoryAttribute("Web Feed")]
[DescriptionAttribute("Save downloaded JSON to file")]
[DefaultValue(false)]
[XmlIgnore]
public bool SaveToFile { get ; set ; }
[CategoryAttribute("Web Feed")]
[DescriptionAttribute("Base URL for website.")]
[DefaultValue("")]
public string URL { get ; set ; }
[CategoryAttribute("Web Feed")]
[DescriptionAttribute("Timeout for loading the site.")]
[DefaultValue(30)]
[XmlIgnore]
public int Timeout { get ; set ; }
public FlexJSONSettings ( )
{
Default ( ) ;
Load ( true ) ;
}
/// <summary>
/// Sets all properties to their default value according to the [DefaultValue=] attribute
/// </summary>
public void Default ( )
{
// set all properties to their default values according to definition in [DeafultValue=]
foreach ( var p in this . GetType ( ) . GetProperties ( ) )
{
try
{
// initialize all properties with default value if set
if ( Attribute . IsDefined ( p , typeof ( DefaultValueAttribute ) ) )
{
p . SetValue ( this , ( ( DefaultValueAttribute ) Attribute . GetCustomAttribute (
p , typeof ( DefaultValueAttribute ) ) ) ? . Value , null ) ;
}
}
catch ( Exception ex )
{
Console . WriteLine ( "[" + this . GetType ( ) . Name + "]: Cannot set default value of: " + p . Name + ", " + ex . Message ) ;
}
}
}
/// <summary>
/// Loads settings from a XML-formatted configuration file into settings.
/// </summary>
/// <param name="loadall">If true, ignore the [XmlIgnore] attribute, e.g. load all settings available in the file.<br>If false, load only settings without [XmlIgore] attrbute.</br></param>
/// <param name="filename">The filename of the settings file.</param>
public void Load ( bool loadall , string filename = "" )
{
// use standard filename if empty
// be careful because Linux file system is case sensitive
if ( String . IsNullOrEmpty ( filename ) )
filename = new Uri ( Assembly . GetExecutingAssembly ( ) . GetName ( ) . CodeBase . Replace ( ".dll" , ".cfg" ) . Replace ( ".DLL" , ".CFG" ) ) . LocalPath ;
// do nothing if file not exists
if ( ! File . Exists ( filename ) )
return ;
try
{
string xml = "" ;
using ( StreamReader sr = new StreamReader ( File . OpenRead ( filename ) ) )
{
xml = sr . ReadToEnd ( ) ;
}
XDocument xdoc = XDocument . Parse ( xml ) ;
PropertyInfo [ ] properties = this . GetType ( ) . GetProperties ( ) ;
foreach ( PropertyInfo p in properties )
{
if ( ! loadall )
{
// check on XmlIgnore attribute, skip if set
object [ ] attr = p . GetCustomAttributes ( typeof ( XmlIgnoreAttribute ) , false ) ;
if ( attr . Length > 0 )
continue ;
}
try
{
// get matching element
XElement typenode = xdoc . Element ( this . GetType ( ) . Name ) ;
if ( typenode ! = null )
{
XElement element = typenode . Element ( p . Name ) ;
if ( element ! = null )
p . SetValue ( this , Convert . ChangeType ( element . Value , p . PropertyType ) , null ) ;
}
}
catch ( Exception ex )
{
Console . WriteLine ( "[" + this . GetType ( ) . Name + "]: Error while loading property[" + p . Name + " from " + filename + ", " + ex . Message ) ;
}
}
}
catch ( Exception ex )
{
Console . WriteLine ( "[" + this . GetType ( ) . Name + "]: Cannot load settings from " + filename + ", " + ex . Message ) ;
}
}
/// <summary>
/// Saves settings from settings into a XML-formatted configuration file
/// </summary>
/// <param name="saveall">If true, ignore the [XmlIgnore] attribute, e.g. save all settings.<br>If false, save only settings without [XmlIgore] attrbute.</param>
/// <param name="filename">The filename of the settings file.</param>
public void Save ( bool saveall , string filename = "" )
{
// use standard filename if empty
// be careful because Linux file system is case sensitive
if ( String . IsNullOrEmpty ( filename ) )
filename = new Uri ( Assembly . GetExecutingAssembly ( ) . GetName ( ) . CodeBase . Replace ( ".dll" , ".cfg" ) . Replace ( ".DLL" , ".CFG" ) ) . LocalPath ;
XmlAttributeOverrides overrides = new XmlAttributeOverrides ( ) ;
if ( saveall )
{
// ovverride the XmlIgnore attributes to get all serialized
PropertyInfo [ ] properties = this . GetType ( ) . GetProperties ( ) ;
foreach ( PropertyInfo p in properties )
{
XmlAttributes attribs = new XmlAttributes { XmlIgnore = false } ;
overrides . Add ( this . GetType ( ) , p . Name , attribs ) ;
}
}
try
{
using ( StreamWriter sw = new StreamWriter ( File . Create ( filename ) ) )
{
XmlSerializer s = new XmlSerializer ( this . GetType ( ) , overrides ) ;
s . Serialize ( sw , this ) ;
}
}
catch ( Exception ex )
{
throw new InvalidOperationException ( "[" + this . GetType ( ) . Name + "]: Cannot save settings to " + filename + ", " + ex . Message ) ;
}
}
}
[Export(typeof(IPlaneFeedPlugin))]
[ExportMetadata("Name", "PlaneFeedPlugin")]
public class FlexJSONPlugin : IPlaneFeedPlugin
{
//********************************** START OF INTERFACE ******************************************
public string Name
{
get
{
return "[WebFeed] Flexible JSON" ;
}
}
public string Info
{
get
{
return "Web feed with flexible JSON column assignment. Use it for webfeed with unknown content.\n" +
"(c) AirScout(www.airscout.eu)\n" +
"This feed tries to read unknown JSON data into an array of plane information.\n" +
"If this is successful, a \"forensic\" algorithm tries to find out which information is on which index.\n" +
"You can manually enter indices as well.See documentation for further details." ;
}
}
public string Version
{
get
{
return Assembly . GetExecutingAssembly ( ) . GetName ( ) . Version . ToString ( ) ;
}
}
public bool HasSettings
{
get
{
return true ;
}
}
public bool CanImport
{
get
{
return true ;
}
}
public bool CanExport
{
get
{
return true ;
}
}
public string Disclaimer
{
get
{
return "This plane feed might fetch data from an Internet server via Deep Link\n" +
"technology(see http://en.wikipedia.org/wiki/Deep_link)\n." +
"The use is probably not intended by the website owners and could be changed in URL and data format frequently and without further notice.\n" +
"Furthermore, it might cause legal issues in some countries.\n" +
"By clicking on \"Accept\" you understand that you are\n\n" +
"DOING THAT ON YOUR OWN RISK\n\n" +
"The auhor of this software will not be responsible in any case." ;
}
}
public string DisclaimerAccepted
{
get
{
return Settings . DisclaimerAccepted ;
}
set
{
Settings . DisclaimerAccepted = value ;
}
}
public void ResetSettings ( )
{
Settings . Default ( ) ;
}
public void LoadSettings ( )
{
Settings . Load ( true ) ;
}
public void SaveSettings ( )
{
Settings . Save ( true ) ;
}
public object GetSettings ( )
{
return this . Settings ;
}
public void ImportSettings ( )
{
OpenFileDialog Dlg = new OpenFileDialog ( ) ;
Dlg . FileName = "*.feed" ;
Dlg . DefaultExt = "feed" ;
Dlg . Filter = "Plane Feeds | .feed" ;
Dlg . CheckFileExists = true ;
if ( Dlg . ShowDialog ( ) = = DialogResult . OK )
{
try
{
Settings . Load ( false , Dlg . FileName ) ;
}
catch ( Exception ex )
{
throw new InvalidOperationException ( "[" + this . GetType ( ) . Name + "]: Cannot import from " + Dlg . FileName + ", " + ex . Message ) ;
}
}
}
public void ExportSettings ( )
{
SaveFileDialog Dlg = new SaveFileDialog ( ) ;
Dlg . DefaultExt = "feed" ;
Dlg . Filter = "Plane Feeds | .feed" ;
Dlg . OverwritePrompt = true ;
if ( Dlg . ShowDialog ( ) = = DialogResult . OK )
{
try
{
Settings . Save ( false , Dlg . FileName ) ;
}
catch ( Exception ex )
{
throw new InvalidOperationException ( "[" + this . GetType ( ) . Name + "]: Cannot export to " + Dlg . FileName + ", " + ex . Message ) ;
}
}
}
public void Start ( PlaneFeedPluginArgs args )
{
// keep the TmpDirectory
TmpDirectory = args . TmpDirectory ;
}
public PlaneFeedPluginPlaneInfoList GetPlanes ( PlaneFeedPluginArgs args )
{
// intialize variables
VarConverter VC = new VarConverter ( ) ;
VC . AddVar ( "APPDIR" , args . AppDirectory ) ;
VC . AddVar ( "DATADIR" , args . AppDataDirectory ) ;
VC . AddVar ( "LOGDIR" , args . LogDirectory ) ;
VC . AddVar ( "DATABASEDIR" , args . DatabaseDirectory ) ;
VC . AddVar ( "MINLAT" , args . MinLat ) ;
VC . AddVar ( "MAXLAT" , args . MaxLat ) ;
VC . AddVar ( "MINLON" , args . MinLon ) ;
VC . AddVar ( "MAXLON" , args . MaxLon ) ;
VC . AddVar ( "MINALTM" , args . MinAlt ) ;
VC . AddVar ( "MAXALTM" , args . MaxAlt ) ;
VC . AddVar ( "MINALTFT" , ( int ) UnitConverter . m_ft ( ( double ) args . MinAlt ) ) ;
VC . AddVar ( "MAXALTFT" , ( int ) UnitConverter . m_ft ( ( double ) args . MaxAlt ) ) ;
// initialize plane info list
PlaneFeedPluginPlaneInfoList planes = new PlaneFeedPluginPlaneInfoList ( ) ;
string json = "" ;
// calculate url and get json
String url = VC . ReplaceAllVars ( Settings . URL ) ;
// check parameters
if ( String . IsNullOrEmpty ( url ) )
throw new ArgumentException ( "The URL is empty." ) ;
if ( Settings . Timeout < = 0 )
throw new ArgumentException ( "The value for Timout is invalid: " + Settings . Timeout . ToString ( ) ) ;
Console . WriteLine ( "[" + this . GetType ( ) . Name + "]: Creating web request: " + url ) ;
2022-08-27 12:13:47 +00:00
// check url and choose the according download mode
if ( ! url . ToLowerInvariant ( ) . StartsWith ( "https://" ) )
2020-02-12 10:45:19 +00:00
{
2022-08-27 12:13:47 +00:00
HttpWebRequest webrequest = ( HttpWebRequest ) HttpWebRequest . Create ( url ) ;
webrequest . Referer = "" ;
webrequest . Timeout = ( int ) Settings . Timeout * 1000 ;
webrequest . UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:72.0) Gecko/20100101 Firefox/72.0" ;
webrequest . Accept = "application/json, text/javascript, */*;q=0.01" ;
webrequest . AutomaticDecompression = System . Net . DecompressionMethods . Deflate | System . Net . DecompressionMethods . GZip ;
Console . WriteLine ( "[" + this . GetType ( ) . Name + "]: Getting web response" ) ;
HttpWebResponse webresponse = ( HttpWebResponse ) webrequest . GetResponse ( ) ;
Console . WriteLine ( "[" + this . GetType ( ) . Name + "]: Reading stream" ) ;
using ( StreamReader sr = new StreamReader ( webresponse . GetResponseStream ( ) ) )
{
json = sr . ReadToEnd ( ) ;
}
}
else
{
json = TlsClient . DownloadFile ( url , Settings . Timeout * 1000 ) ;
2020-02-12 10:45:19 +00:00
}
// save raw data to file if enabled
if ( Settings . SaveToFile )
{
using ( StreamWriter sw = new StreamWriter ( args . TmpDirectory + Path . DirectorySeparatorChar + this . GetType ( ) . Name + "_" + DateTime . UtcNow . ToString ( "yyyy-MM-dd HH_mm_ss" ) + ".json" ) )
{
sw . WriteLine ( json ) ;
}
}
Console . WriteLine ( "[" + this . GetType ( ) . Name + "]: Analyzing data" ) ;
JavaScriptSerializer js = new JavaScriptSerializer ( ) ;
dynamic root = js . Deserialize < dynamic > ( json ) ;
// get all planeinfos in an array
GetAllPlaneInfos ( root ) ;
// try to find all indices automatically if not set
// mind the search order!
if ( Settings . Index_Hex < 0 )
{
FindHexIndex ( ) ;
Settings . Save ( true ) ;
}
if ( Settings . Index_UTC < 0 )
{
FindUTCIndex ( ) ;
Settings . Save ( true ) ;
}
if ( Settings . Index_Type < 0 )
{
FindTypeIndex ( ) ;
Settings . Save ( true ) ;
}
if ( Settings . Index_Lat < 0 )
{
FindLatIndex ( ) ;
Settings . Save ( true ) ;
}
if ( Settings . Index_Lon < 0 )
{
FindLonIndex ( ) ;
Settings . Save ( true ) ;
}
if ( Settings . Index_Alt < 0 )
{
FindAltIndex ( ) ;
Settings . Save ( true ) ;
}
if ( Settings . Index_Track < 0 )
{
FindTrackIndex ( ) ;
Settings . Save ( true ) ;
}
if ( Settings . Index_Speed < 0 )
{
FindSpeedIndex ( ) ;
Settings . Save ( true ) ;
}
if ( Settings . Index_Reg < 0 )
{
FindRegIndex ( ) ;
Settings . Save ( true ) ;
}
// all must produce/have some mandatory data
if ( Settings . Index_Lat < 0 )
throw new InvalidOperationException ( "[" + this . GetType ( ) . Name + "]: Cannot get planes, Lat index not found/not set!" ) ;
if ( Settings . Index_Lon < 0 )
throw new InvalidOperationException ( "[" + this . GetType ( ) . Name + "]: Cannot get planes, Lon index not found/not set!" ) ;
if ( Settings . Index_Alt < 0 )
throw new InvalidOperationException ( "[" + this . GetType ( ) . Name + "]: Cannot get planes, Alt index not found/not set!" ) ;
if ( Settings . Index_Track < 0 )
throw new InvalidOperationException ( "[" + this . GetType ( ) . Name + "]: Cannot get planes, Track index not found/not set!" ) ;
if ( Settings . Index_Speed < 0 )
throw new InvalidOperationException ( "[" + this . GetType ( ) . Name + "]: Cannot get planes, Speed index not found/not set!" ) ;
// fill plane info
foreach ( string [ ] info in PlaneList )
{
PlaneFeedPluginPlaneInfo plane = new PlaneFeedPluginPlaneInfo ( ) ;
if ( ( Settings . Index_Hex > 0 ) & & ( Settings . Index_Hex < info . Length ) )
plane . Hex = To_Hex ( info [ Settings . Index_Hex ] ) ;
else
plane . Hex = "" ;
if ( ( Settings . Index_UTC > 0 ) & & ( Settings . Index_UTC < info . Length ) )
plane . Time = To_UTC ( info [ Settings . Index_UTC ] ) ;
else
plane . Time = DateTime . UtcNow ;
if ( ( Settings . Index_Lat > 0 ) & & ( Settings . Index_Lat < info . Length ) )
plane . Lat = To_Lat ( info [ Settings . Index_Lat ] ) ;
else
plane . Lat = double . MinValue ;
if ( ( Settings . Index_Lon > 0 ) & & ( Settings . Index_Lon < info . Length ) )
plane . Lon = To_Lon ( info [ Settings . Index_Lon ] ) ;
else
plane . Lon = double . MinValue ;
if ( ( Settings . Index_Alt > 0 ) & & ( Settings . Index_Alt < info . Length ) )
plane . Alt = To_Alt ( info [ Settings . Index_Alt ] ) ;
else
plane . Alt = double . MinValue ;
if ( ( Settings . Index_Speed > 0 ) & & ( Settings . Index_Speed < info . Length ) )
plane . Speed = To_Speed ( info [ Settings . Index_Speed ] ) ;
else
plane . Speed = int . MinValue ;
if ( ( Settings . Index_Track > 0 ) & & ( Settings . Index_Track < info . Length ) )
plane . Track = To_Track ( info [ Settings . Index_Track ] ) ;
else
plane . Track = int . MinValue ;
if ( ( Settings . Index_Call > 0 ) & & ( Settings . Index_Call < info . Length ) )
plane . Call = To_Call ( info [ Settings . Index_Call ] ) ;
else
plane . Call = "" ;
if ( ( Settings . Index_Type > 0 ) & & ( Settings . Index_Type < info . Length ) )
plane . Type = To_Type ( info [ Settings . Index_Type ] ) ;
else
plane . Type = "" ;
if ( ( Settings . Index_Reg > 0 ) & & ( Settings . Index_Reg < info . Length ) )
plane . Reg = To_Reg ( info [ Settings . Index_Reg ] ) ;
else
plane . Reg = "" ;
planes . Add ( plane ) ;
}
Console . WriteLine ( "[" + this . GetType ( ) . Name + "]: Returning planes" ) ;
return planes ;
}
public void Stop ( PlaneFeedPluginArgs args )
{
// save settings
Settings . Save ( true ) ;
}
// **************************** END OF INTERFACE *********************************
private string TmpDirectory ;
private FlexJSONSettings Settings = new FlexJSONSettings ( ) ;
public FlexJSONPlugin ( )
{
}
// *********************** Plane info converters **********************************
#region PlaneInfoCheckers
// checks for int and long values
private bool IsInt ( string s )
{
s = s . Trim ( ) ;
// int should contain only these chars
string allowed = "-01234567890" ;
int i ;
for ( i = 0 ; i < s . Length ; i + + )
{
if ( ! allowed . Contains ( s [ i ] ) )
return false ;
}
long l ;
// try to convert to int
if ( ! long . TryParse ( s , out l ) )
return false ;
// all checks paased
return true ;
}
private bool IsDouble ( string s )
{
s = s . Trim ( ) ;
// double must contain at least a decimal separator
if ( ! s . Contains ( "." ) & & ! s . Contains ( "," ) )
return false ;
// try to convert to double
double d ;
// try to convert with regional settings
if ( ! double . TryParse ( s , out d ) )
{
// try invariant
if ( ! double . TryParse ( s , NumberStyles . Any , CultureInfo . InvariantCulture , out d ) )
return false ;
}
// all checks passed
return true ;
}
private bool IsHex ( string s )
{
bool b ;
s = s . Trim ( ) ;
if ( s . Length ! = 6 )
return false ;
long l ;
if ( ! long . TryParse ( s , System . Globalization . NumberStyles . HexNumber , null , out l ) )
return false ;
// all checks passed
return true ;
}
private bool IsUTC ( string s )
{
// get current time in all three formats
DateTime now = DateTime . UtcNow ;
int now_int = ( Int32 ) ( now . Subtract ( new DateTime ( 1970 , 1 , 1 ) ) ) . TotalSeconds ;
long now_long = ( long ) now_int * 1000 ;
s = s . Trim ( ) ;
// to short for a UTC value
if ( s . Length < 10 )
return false ;
if ( ! IsInt ( s ) )
{
// maybe DateTime formatted
if ( ! s . ToCharArray ( ) . Any ( c = > "-_:" . Contains ( c ) ) )
return false ;
}
// assuming int
long l = 0 ;
// assuming integer values
if ( s . Length < 13 )
{
// assuming UNIX time in sec
if ( ! long . TryParse ( s , out l ) )
return false ;
if ( Math . Abs ( now_int - l ) > 1000 )
return false ;
}
// assuming UNIX time in msec
if ( ! long . TryParse ( s , out l ) )
return false ;
if ( Math . Abs ( now_long - l ) > 1000000 )
return false ;
// all checks passed
return true ;
}
private bool IsLat ( string s )
{
bool b ;
s = s . Trim ( ) ;
if ( ! IsDouble ( s ) )
return false ;
double d = To_Double ( s ) ;
if ( d < - 90 )
return false ;
if ( d > 90 )
return false ;
// all checks passed
return true ;
}
private bool IsLon ( string s )
{
bool b ;
s = s . Trim ( ) ;
if ( ! IsDouble ( s ) )
return false ;
double d = To_Double ( s ) ;
if ( d < - 180 )
return false ;
if ( d > 180 )
return false ;
// all checks passed
return true ;
}
private bool IsAlt ( string s )
{
bool b ;
s = s . Trim ( ) ;
if ( ! IsInt ( s ) & & ! IsDouble ( s ) )
return false ;
double d = To_Double ( s ) ;
// don't accept negative values though they might occur
if ( d < 0 )
return false ;
if ( ( Settings . Units_Alt . ToLower ( ) = = "m " ) & & ( d > 30000 ) )
return false ;
// assuming altitude in feet
if ( d > 100000 )
return false ;
// all checks passed
return true ;
}
private bool IsTrack ( string s )
{
bool b ;
s = s . Trim ( ) ;
if ( ! IsInt ( s ) & & ! IsDouble ( s ) )
return false ;
double d = To_Double ( s ) ;
if ( d < 0 )
return false ;
if ( d > 360 )
return false ;
// all checks passed
return true ;
}
private bool IsSpeed ( string s )
{
bool b ;
s = s . Trim ( ) ;
if ( ! IsInt ( s ) & & ! IsDouble ( s ) )
return false ;
double d = To_Double ( s ) ;
if ( d < 0 )
return false ;
// don't accept higher values though they might occur
if ( ( Settings . Units_Speed . ToLower ( ) = = "km/h " ) & & ( d > 1000 ) )
return false ;
// assuming speed in kts
if ( d > 550 )
return false ;
// all checks passed
return true ;
}
private bool IsReg ( string s )
{
bool b ;
s = s . Trim ( ) ;
// Registration should contain a "-" or start with "N"
if ( ! s . Contains ( "-" ) )
{
if ( ! s . StartsWith ( "N" ) )
return false ;
}
return true ;
}
private bool IsType ( string s )
{
bool b ;
s = s . Trim ( ) ;
if ( s . Length ! = 4 )
return false ;
// type should contain at least on number
for ( int i = 0 ; i < s . Length ; i + + )
{
if ( char . IsNumber ( s [ i ] ) )
return true ;
}
return false ; ;
}
# endregion
#region PlaneInfoConverters
public int To_Int ( string s )
{
int i ;
if ( int . TryParse ( s , out i ) )
return i ;
return int . MinValue ;
}
public long To_Long ( string s )
{
long l ;
if ( long . TryParse ( s , out l ) )
return l ;
return long . MinValue ;
}
public double To_Double ( string s )
{
double d ;
if ( double . TryParse ( s , out d ) )
return d ;
if ( double . TryParse ( s , NumberStyles . Any , CultureInfo . InvariantCulture , out d ) )
return d ;
return double . MinValue ;
}
public DateTime To_UTC ( string s )
{
if ( String . IsNullOrEmpty ( s ) )
return DateTime . MinValue ;
// remove qoutes and spaces, if any
s = s . Replace ( "\"" , String . Empty ) . Trim ( ) ;
// UTC could be either:
// a 32bit integer containing seconds since 1970-01-01
// a 64bit ticks containing ticks[ms] since 1970-01-01
// a valid DateTime string, like "yyyy-MM-dd HH:mm:ss"
// try to convert UNIX times first
if ( ( s . Length > = 10 ) & & IsInt ( s ) )
{
try
{
if ( s . Length > 10 )
{
// try to convert to milliseconds
// try to convert to seconds
long l = System . Convert . ToInt64 ( s ) ;
DateTime timestamp = new System . DateTime ( 1970 , 1 , 1 , 0 , 0 , 0 , 0 , DateTimeKind . Utc ) ;
timestamp = timestamp . AddMilliseconds ( l ) ;
return timestamp ;
}
else
{
// try to convert to seconds
long l = System . Convert . ToInt64 ( s ) ;
DateTime timestamp = new System . DateTime ( 1970 , 1 , 1 , 0 , 0 , 0 , 0 , DateTimeKind . Utc ) ;
timestamp = timestamp . AddSeconds ( l ) ;
return timestamp ;
}
}
catch ( Exception ex )
{
// Console.WriteLine("[" + System.Reflection.MethodBase.GetCurrentMethod().Name + "]" + ex.Message + ": " + s);
}
}
// check for Standard DateTime notation
try
{
// try to convert to UTC timestamp
DateTime timestamp ;
if ( DateTime . TryParse ( s , out timestamp ) )
return timestamp ;
}
catch ( Exception ex )
{
// Console.WriteLine("[" + System.Reflection.MethodBase.GetCurrentMethod().Name + "]" + ex.Message + ": " + s);
}
return DateTime . MinValue ;
}
public string To_Hex ( string s )
{
if ( String . IsNullOrEmpty ( s ) )
return null ;
// remove qoutes and spaces, if any
s = s . Replace ( "\"" , String . Empty ) . ToUpper ( ) . Trim ( ) ;
// check if Hex
if ( ! IsHex ( s ) )
return null ;
try
{
// try to convert to Hex value
long hex = System . Convert . ToInt64 ( s , 16 ) ;
// check boundaries
if ( ( hex < 0 ) | | ( hex > 16777215 ) )
return null ;
return s ;
}
catch ( Exception ex )
{
// Console.WriteLine("[" + System.Reflection.MethodBase.GetCurrentMethod().Name + "]" + ex.Message + ": " + s);
}
return null ;
}
public double To_Lat ( string s )
{
s = s . Replace ( "\"" , String . Empty ) . Trim ( ) ;
if ( s . Length < 3 )
return double . MinValue ;
// double Lon must contain a decimal separator
if ( s . IndexOf ( CultureInfo . CurrentCulture . NumberFormat . NumberDecimalSeparator ) < 0 )
return double . MinValue ;
try
{
// try to convert to double
double d = System . Convert . ToDouble ( s ) ;
// check bounds
if ( ( d > = - 90.0 ) & & ( d < = 90.0 ) )
return d ;
}
catch ( Exception ex )
{
// Console.WriteLine("[" + System.Reflection.MethodBase.GetCurrentMethod().Name + "]" + ex.Message + ": " + s);
}
return double . MinValue ;
}
public double To_Lon ( string s )
{
s = s . Replace ( "\"" , String . Empty ) . Trim ( ) ;
if ( s . Length < 3 )
return double . MinValue ;
// double Lon must contain a decimal separator
if ( s . IndexOf ( CultureInfo . CurrentCulture . NumberFormat . NumberDecimalSeparator ) < 0 )
return double . MinValue ;
try
{
// try to convert to double
double d = System . Convert . ToDouble ( s ) ;
// check bounds
if ( ( d > = - 180.0 ) & & ( d < = 180.0 ) )
return d ;
}
catch ( Exception ex )
{
// Console.WriteLine("[" + System.Reflection.MethodBase.GetCurrentMethod().Name + "]" + ex.Message + ": " + s);
}
return double . MinValue ;
}
public int To_Alt ( string s )
{
s = s . Replace ( "\"" , String . Empty ) . Trim ( ) ;
try
{
// try to convert to integer
long alt = System . Convert . ToInt64 ( s ) ;
// convert m to ft
if ( Settings . Units_Alt . ToLower ( ) = = "m" )
alt = ( int ) ( ( double ) alt * 3.28084 ) ;
// check bounds
if ( ( alt < 0 ) | | ( alt > 100000 ) )
return int . MinValue ;
return ( int ) alt ;
}
catch ( Exception ex )
{
// Console.WriteLine("[" + System.Reflection.MethodBase.GetCurrentMethod().Name + "]" + ex.Message + ": " + s);
}
return int . MinValue ;
}
public int To_Track ( string s )
{
s = s . Replace ( "\"" , String . Empty ) . Trim ( ) ;
try
{
// try to convert to integer
long track = System . Convert . ToInt64 ( s ) ;
// check bounds
if ( ( track < 0 ) | | ( track > 360 ) )
return int . MinValue ;
return ( int ) track ;
}
catch ( Exception ex )
{
// Console.WriteLine("[" + System.Reflection.MethodBase.GetCurrentMethod().Name + "]" + ex.Message + ": " + s);
}
return int . MinValue ;
}
public int To_Speed ( string s )
{
s = s . Replace ( "\"" , String . Empty ) . Trim ( ) ;
try
{
// try to convert to integer
long speed = System . Convert . ToInt64 ( s ) ;
// convert km/h to kts
if ( Settings . Units_Speed . ToLower ( ) = = "km/h" )
return ( int ) ( ( double ) speed / 1.852 ) ;
if ( ( speed < 0 ) | | ( speed > 550 ) )
return int . MinValue ;
return ( int ) speed ;
}
catch ( Exception ex )
{
// Console.WriteLine("[" + System.Reflection.MethodBase.GetCurrentMethod().Name + "]" + ex.Message + ": " + s);
}
return int . MinValue ;
}
public string To_Call ( string s )
{
if ( String . IsNullOrEmpty ( s ) )
return null ;
// remove qoutes and spaces, if any
s = s . Replace ( "\"" , String . Empty ) . ToUpper ( ) . Trim ( ) ;
return s ;
}
public string To_Type ( string s )
{
if ( String . IsNullOrEmpty ( s ) )
return null ;
// remove qoutes and spaces, if any
s = s . Replace ( "\"" , String . Empty ) . ToUpper ( ) . Trim ( ) ;
return s ;
}
public string To_Reg ( string s )
{
if ( String . IsNullOrEmpty ( s ) )
return null ;
// remove qoutes and spaces, if any
s = s . Replace ( "\"" , String . Empty ) . ToUpper ( ) . Trim ( ) ;
return s ;
}
# endregion
#region IndexFinders
private void FindHexIndex ( )
{
if ( PlaneList . Count < = 0 )
return ;
int maxindex = - 1 ;
int maxcount = 0 ;
for ( int i = 0 ; i < IsHexColumns . Length ; i + + )
{
if ( ! DetectedColumns [ i ] )
{
if ( IsHexColumns [ i ] > maxcount )
{
maxcount = IsHexColumns [ i ] ;
maxindex = i ;
}
}
}
if ( maxcount > ( int ) ( 0.9 * ( double ) PlaneList . Count ) )
{
Settings . Index_Hex = maxindex ;
DetectedColumns [ maxindex ] = true ;
}
}
private void FindUTCIndex ( )
{
if ( PlaneList . Count < = 0 )
return ;
int maxindex = - 1 ;
int maxcount = 0 ;
for ( int i = 0 ; i < IsUTCColumns . Length ; i + + )
{
if ( ! DetectedColumns [ i ] )
{
if ( IsUTCColumns [ i ] > maxcount )
{
maxcount = IsUTCColumns [ i ] ;
maxindex = i ;
}
}
}
if ( maxcount > ( int ) ( 0.9 * ( double ) PlaneList . Count ) )
{
Settings . Index_UTC = maxindex ;
DetectedColumns [ maxindex ] = true ;
}
}
private void FindLatIndex ( )
{
int maxindex = - 1 ;
int maxcount = 0 ;
for ( int i = 0 ; i < IsLatColumns . Length ; i + + )
{
if ( ! DetectedColumns [ i ] )
{
if ( IsLatColumns [ i ] > maxcount )
{
maxcount = IsLatColumns [ i ] ;
maxindex = i ;
}
}
}
if ( maxcount > ( int ) ( 0.9 * ( double ) PlaneList . Count ) )
{
Settings . Index_Lat = maxindex ;
DetectedColumns [ maxindex ] = true ;
}
}
private void FindLonIndex ( )
{
int maxindex = - 1 ;
int maxcount = 0 ;
for ( int i = 0 ; i < IsLonColumns . Length ; i + + )
{
if ( ! DetectedColumns [ i ] )
{
if ( IsLonColumns [ i ] > maxcount )
{
maxcount = IsLonColumns [ i ] ;
maxindex = i ;
}
}
}
if ( maxcount > ( int ) ( 0.9 * ( double ) PlaneList . Count ) )
{
Settings . Index_Lon = maxindex ;
DetectedColumns [ maxindex ] = true ;
}
}
private void FindTrackIndex ( )
{
int maxindex = - 1 ;
int maxcount = 0 ;
for ( int i = 0 ; i < IsTrackColumns . Length ; i + + )
{
if ( ! DetectedColumns [ i ] & & ( MaxColumns [ i ] < = 360 ) )
{
if ( IsTrackColumns [ i ] > maxcount )
{
maxcount = IsTrackColumns [ i ] ;
maxindex = i ;
}
}
}
if ( maxcount > ( int ) ( 0.9 * ( double ) PlaneList . Count ) )
{
Settings . Index_Track = maxindex ;
DetectedColumns [ maxindex ] = true ;
}
}
private void FindSpeedIndex ( )
{
int maxindex = - 1 ;
int maxcount = 0 ;
for ( int i = 0 ; i < IsSpeedColumns . Length ; i + + )
{
if ( ! DetectedColumns [ i ] & & ( MaxColumns [ i ] > 360 ) )
{
if ( IsSpeedColumns [ i ] > maxcount )
{
maxcount = IsSpeedColumns [ i ] ;
maxindex = i ;
}
}
}
if ( maxcount > ( int ) ( 0.9 * ( double ) PlaneList . Count ) )
{
Settings . Index_Speed = maxindex ;
DetectedColumns [ maxindex ] = true ;
}
}
private void FindAltIndex ( )
{
int maxindex = - 1 ;
int maxcount = 0 ;
for ( int i = 0 ; i < IsAltColumns . Length ; i + + )
{
if ( ! DetectedColumns [ i ] & & ( MeanColumns [ i ] > 5000 ) )
{
if ( IsAltColumns [ i ] > maxcount )
{
maxcount = IsAltColumns [ i ] ;
maxindex = i ;
}
}
}
if ( maxcount > ( int ) ( 0.9 * ( double ) PlaneList . Count ) )
{
Settings . Index_Alt = maxindex ;
DetectedColumns [ maxindex ] = true ;
}
}
private void FindTypeIndex ( )
{
int maxindex = - 1 ;
int maxcount = 0 ;
for ( int i = 0 ; i < IsTypeColumns . Length ; i + + )
{
if ( ! DetectedColumns [ i ] )
{
if ( IsTypeColumns [ i ] > maxcount )
{
maxcount = IsTypeColumns [ i ] ;
maxindex = i ;
}
}
}
if ( maxcount > ( int ) ( 0.9 * ( double ) PlaneList . Count ) )
{
Settings . Index_Type = maxindex ;
DetectedColumns [ maxindex ] = true ;
}
}
private void FindRegIndex ( )
{
int maxindex = - 1 ;
int maxcount = 0 ;
for ( int i = 0 ; i < IsRegColumns . Length ; i + + )
{
if ( ! DetectedColumns [ i ] )
{
if ( IsRegColumns [ i ] > maxcount )
{
maxcount = IsRegColumns [ i ] ;
maxindex = i ;
}
}
}
if ( maxcount > ( int ) ( 0.9 * ( double ) PlaneList . Count ) )
{
Settings . Index_Reg = maxindex ;
DetectedColumns [ maxindex ] = true ;
}
}
# endregion
// *********************** Parsing elements ************************************
private class ElementInfo
{
public string Key ;
public string TypeName ;
public int Length ;
public dynamic Element ;
public ElementInfo ( string key , string typename , int length , dynamic element )
{
Key = key ;
TypeName = typename ;
Length = length ;
Element = element ;
}
}
private List < ElementInfo > Elements = new List < ElementInfo > ( ) ;
private Dictionary < int , int > ElementLengths = new Dictionary < int , int > ( ) ;
private List < string [ ] > PlaneList = new List < string [ ] > ( ) ;
private double [ ] MaxColumns ;
private double [ ] MinColumns ;
private double [ ] MeanColumns ;
private int [ ] IsDoubleColumns ;
private int [ ] IsIntColumns ;
private int [ ] IsHexColumns ;
private int [ ] IsUTCColumns ;
private int [ ] IsLatColumns ;
private int [ ] IsLonColumns ;
private int [ ] IsAltColumns ;
private int [ ] IsTrackColumns ;
private int [ ] IsSpeedColumns ;
private int [ ] IsTypeColumns ;
private int [ ] IsRegColumns ;
private bool [ ] DetectedColumns ;
private void AddElement ( string key , dynamic el )
{
string typename = el . GetType ( ) . Name ;
if ( typename . ToLower ( ) . Contains ( "dictionary" ) )
{
// dictionary found
// count the length and maintain element lengths
int i = 0 ;
int c = el . Values . Count ;
if ( ElementLengths . TryGetValue ( c , out i ) )
{
ElementLengths [ c ] + + ;
}
else
{
ElementLengths . Add ( c , 1 ) ;
}
// add element to elements list
ElementInfo info = new ElementInfo ( key , typename , c , el ) ;
Elements . Add ( info ) ;
// recurse element, key ist dictionary key
foreach ( dynamic e in el . Keys )
{
AddElement ( e , el [ e ] ) ;
}
}
else if ( typename . ToLower ( ) . Contains ( "[]" ) )
{
// array found
// add element to elements list
// count the length and maintain element lengths
int i = 0 ;
int c = el . Length ;
if ( ElementLengths . TryGetValue ( c , out i ) )
{
ElementLengths [ c ] + + ;
}
else
{
ElementLengths . Add ( c , 1 ) ;
}
ElementInfo info = new ElementInfo ( key , typename , c , el ) ;
Elements . Add ( info ) ;
// recurse elements, key is a unique ID
foreach ( dynamic e in el )
{
AddElement ( Guid . NewGuid ( ) . ToString ( ) , e ) ;
}
}
else if ( typename . ToLower ( ) . Contains ( "arraylist" ) )
{
// ArrayList found
// add element to elements list
// count the length and maintain element lengths
int i = 0 ;
int c = el . Count ;
if ( ElementLengths . TryGetValue ( c , out i ) )
{
ElementLengths [ c ] + + ;
}
else
{
ElementLengths . Add ( c , 1 ) ;
}
ElementInfo info = new ElementInfo ( key , typename , c , el ) ;
Elements . Add ( info ) ;
Console . WriteLine ( "Element found: " + info . Key + "; " + info . TypeName + "; " + c . ToString ( ) + "; " , el . ToString ( ) ) ;
// recurse elements, key is a unique ID
foreach ( dynamic e in el )
{
AddElement ( Guid . NewGuid ( ) . ToString ( ) , e ) ;
}
}
}
private string [ ] GetPlaneInfo ( ElementInfo el )
{
string [ ] info = new string [ el . Length + 1 ] ;
// set key
info [ 0 ] = el . Key ;
// grab info
if ( el . TypeName . ToLower ( ) . Contains ( "dictionary" ) )
{
// dictionary found
int count = 1 ;
foreach ( dynamic e in el . Element . Values )
{
if ( e . GetType ( ) . IsPrimitive | | ( e . GetType ( ) . Name . ToLower ( ) = = "string" ) )
{
info [ count ] = e . ToString ( ) ;
}
else
{
info [ count ] = "" ;
}
count + + ;
}
}
else if ( el . TypeName . ToLower ( ) . Contains ( "[]" ) )
{
// array found
int count = 1 ;
foreach ( dynamic e in el . Element )
{
string typename = e . GetType ( ) . Name ;
if ( e . GetType ( ) . IsPrimitive | | ( typename . ToLower ( ) = = "string" ) | | ( typename . ToLower ( ) = = "decimal" ) )
{
info [ count ] = e . ToString ( ) ;
}
else
{
info [ count ] = "" ;
}
count + + ;
}
}
else if ( el . TypeName . ToLower ( ) . Contains ( "arraylist" ) )
{
// ArrayList found
int count = 1 ;
foreach ( dynamic e in el . Element )
{
string typename = e . GetType ( ) . Name ;
if ( e . GetType ( ) . IsPrimitive | | ( typename . ToLower ( ) = = "string" ) | | ( typename . ToLower ( ) = = "decimal" ) )
{
info [ count ] = e . ToString ( ) ;
}
else
{
info [ count ] = "" ;
}
count + + ;
}
}
return info ;
}
private void GetColumnInfo ( )
{
double [ ] sum = new double [ MinColumns . Length ] ;
for ( int i = 0 ; i < sum . Length ; i + + )
sum [ i ] = 0 ;
foreach ( string [ ] info in PlaneList )
{
if ( info = = null )
continue ;
for ( int i = 0 ; i < info . Length ; i + + )
{
if ( IsDouble ( info [ i ] ) )
{
IsDoubleColumns [ i ] + + ;
double d = To_Double ( info [ i ] ) ;
if ( d ! = double . MinValue )
{
if ( d < MinColumns [ i ] )
MinColumns [ i ] = d ;
else if ( d > MaxColumns [ i ] )
MaxColumns [ i ] = d ;
}
sum [ i ] = sum [ i ] + d ;
}
if ( IsInt ( info [ i ] ) )
{
IsIntColumns [ i ] + + ;
long l = To_Long ( info [ i ] ) ;
if ( l ! = long . MinValue )
{
if ( l < MinColumns [ i ] )
MinColumns [ i ] = l ;
else if ( l > MaxColumns [ i ] )
MaxColumns [ i ] = l ;
}
sum [ i ] = sum [ i ] + l ;
}
if ( IsHex ( info [ i ] ) )
IsHexColumns [ i ] + + ;
if ( IsUTC ( info [ i ] ) )
IsUTCColumns [ i ] + + ;
if ( IsLat ( info [ i ] ) )
IsLatColumns [ i ] + + ;
if ( IsLon ( info [ i ] ) )
IsLonColumns [ i ] + + ;
if ( IsAlt ( info [ i ] ) )
IsAltColumns [ i ] + + ;
if ( IsTrack ( info [ i ] ) )
IsTrackColumns [ i ] + + ;
if ( IsSpeed ( info [ i ] ) )
IsSpeedColumns [ i ] + + ;
if ( IsType ( info [ i ] ) )
IsTypeColumns [ i ] + + ;
if ( IsReg ( info [ i ] ) )
IsRegColumns [ i ] + + ;
}
}
for ( int i = 0 ; i < sum . Length ; i + + )
MeanColumns [ i ] = sum [ i ] / PlaneList . Count ( ) ;
}
private void GetAllPlaneInfos ( dynamic obj )
{
// get all elements in a linear list and count the lengths
Elements . Clear ( ) ;
ElementLengths . Clear ( ) ;
// start at the root element
AddElement ( "" , obj ) ;
// find the majority of element lengths --> assuming that these are the plane elements
int maxcount = 0 ;
int maxkey = 0 ;
foreach ( int key in ElementLengths . Keys )
{
if ( ElementLengths [ key ] > maxcount )
{
maxcount = ElementLengths [ key ] ;
maxkey = key ;
}
}
// get all plane infos in a clean list
PlaneList . Clear ( ) ;
foreach ( ElementInfo el in Elements )
{
// add matching elements to planes list
if ( el . Length = = maxkey )
{
string [ ] info = GetPlaneInfo ( el ) ;
PlaneList . Add ( info ) ;
}
}
// store the plane i nfo table as CSV, so that a user can determine which columns at which indices are needed
// catch the exception here to continue grabbing planes if user left thge file open :-)
string csvfilename = Path . Combine ( TmpDirectory , "FlexJSON.csv" ) ;
try
{
using ( StreamWriter sw = new StreamWriter ( csvfilename ) )
{
foreach ( string [ ] infos in PlaneList )
{
foreach ( string info in infos )
sw . Write ( "\"" + info + "\"" + ";" ) ;
sw . WriteLine ( ) ;
}
}
}
catch ( Exception ex )
{
// do nothing
Console . WriteLine ( "[" + this . GetType ( ) . Name + "]: Cannot write CSV-table " + csvfilename + ", " + ex . ToString ( ) ) ;
}
// clear all info arrays
MaxColumns = new double [ maxkey + 1 ] ;
MinColumns = new double [ maxkey + 1 ] ;
MeanColumns = new double [ maxkey + 1 ] ;
IsIntColumns = new int [ maxkey + 1 ] ;
IsDoubleColumns = new int [ maxkey + 1 ] ;
IsHexColumns = new int [ maxkey + 1 ] ;
IsUTCColumns = new int [ maxkey + 1 ] ;
IsLatColumns = new int [ maxkey + 1 ] ;
IsLonColumns = new int [ maxkey + 1 ] ;
IsAltColumns = new int [ maxkey + 1 ] ;
IsTrackColumns = new int [ maxkey + 1 ] ;
IsSpeedColumns = new int [ maxkey + 1 ] ;
IsTypeColumns = new int [ maxkey + 1 ] ;
IsRegColumns = new int [ maxkey + 1 ] ;
DetectedColumns = new bool [ maxkey + 1 ] ;
for ( int i = 0 ; i < maxkey + 1 ; i + + )
{
MaxColumns [ i ] = 0 ;
MinColumns [ i ] = 0 ;
MeanColumns [ i ] = 0 ;
IsIntColumns [ i ] = 0 ;
IsDoubleColumns [ i ] = 0 ;
IsHexColumns [ i ] = 0 ;
IsUTCColumns [ i ] = 0 ;
IsLatColumns [ i ] = 0 ;
IsAltColumns [ i ] = 0 ;
IsTrackColumns [ i ] = 0 ;
IsSpeedColumns [ i ] = 0 ;
IsTypeColumns [ i ] = 0 ;
IsRegColumns [ i ] = 0 ;
DetectedColumns [ i ] = false ;
}
// initially set all indices already found
PropertyInfo [ ] properties = typeof ( PlaneFeedPluginSettings ) . GetProperties ( BindingFlags . Public | BindingFlags . Instance ) ;
foreach ( PropertyInfo p in properties )
{
// find all index properties
if ( p . Name . StartsWith ( "Index_" ) & & ( p . PropertyType = = typeof ( int ) ) )
{
int index = ( int ) p . GetValue ( Settings , null ) ;
// mark detected column as true
if ( ( index > = 0 ) & & ( index < DetectedColumns . Length ) )
DetectedColumns [ index ] = true ;
}
}
// get min/max info per column
GetColumnInfo ( ) ;
}
[System.Diagnostics.DebuggerNonUserCode]
private string ReadPropertyString ( dynamic o , string propertyname )
{
string s = null ;
try
{
s = o [ propertyname ] ;
}
catch
{
}
return s ;
}
[System.Diagnostics.DebuggerNonUserCode]
private int ReadPropertyInt ( dynamic o , string propertyname )
{
int i = int . MinValue ;
double d = ReadPropertyDouble ( o , propertyname ) ;
if ( ( d ! = double . MinValue ) & & ( d > = int . MinValue ) & & ( d < = int . MaxValue ) )
i = ( int ) d ;
return i ;
}
[System.Diagnostics.DebuggerNonUserCode]
private double ReadPropertyDouble ( dynamic o , string propertyname )
{
double d = double . MinValue ;
try
{
string s = o [ propertyname ] . ToString ( CultureInfo . InvariantCulture ) ;
d = double . Parse ( s , CultureInfo . InvariantCulture ) ;
}
catch
{
// do nothing if something went wrong
}
return d ;
}
[System.Diagnostics.DebuggerNonUserCode]
private long ReadPropertyLong ( dynamic o , string propertyname )
{
long l = long . MinValue ;
try
{
l = o [ propertyname ] ;
}
catch
{
// do nothing if something went wrong
}
return l ;
}
[System.Diagnostics.DebuggerNonUserCode]
private bool ReadPropertyBool ( dynamic o , string propertyname )
{
bool b = false ;
try
{
string s = o [ propertyname ] . ToString ( ) ;
b = s . ToLower ( ) = = "true" ;
}
catch
{
// do nothing if something went wrong
}
return b ;
}
}
/// <summary>
/// //////////////////////////////////////////// Helpers ////////////////////////////////////////////
/// </summary>
public static class UnitConverter
{
public static double ft_m ( double feet )
{
return feet / 3.28084 ;
}
public static double m_ft ( double m )
{
return m * 3.28084 ;
}
public static double kts_kmh ( double kts )
{
return kts * 1.852 ;
}
public static double kmh_kts ( double kmh )
{
return kmh / 1.852 ;
}
public static double km_mi ( double km )
{
return km * 1.609 ;
}
public static double mi_km ( double mi )
{
return mi / 1.609 ;
}
}
public class VarConverter : Dictionary < string , object >
{
public readonly char VarSeparator = '%' ;
public void AddVar ( string var , object value )
{
// adds a new var<>value pair to dictionary
object o ;
if ( this . TryGetValue ( var , out o ) )
{
// item found --> update value
o = value ;
}
else
{
// item not found --> add new
this . Add ( var , value ) ;
}
}
public object GetValue ( string var )
{
// finds a var in dictionary and returns its value
object o ;
if ( this . TryGetValue ( var , out o ) )
{
// item found --> return value
return o ;
}
// item not found --> return null
return null ;
}
public string ReplaceAllVars ( string s )
{
// check for var separotors first
if ( s . Contains ( VarSeparator ) )
{
// OK, string is containing vars --> crack the string first and replace vars
try
{
string [ ] a = s . Split ( VarSeparator ) ;
// as we are always using a pair of separators the length of a[] must be odd
if ( a . Length % 2 = = 0 )
throw new ArgumentException ( "Number of separators is not an even number." ) ;
// create new string and replace all vars (on odd indices)
s = "" ;
for ( int i = 0 ; i < a . Length ; i + + )
{
if ( i % 2 = = 0 )
{
// cannot be not a var on that position
s = s + a [ i ] ;
}
else
{
// var identifier: upper the string and try to convert
a [ i ] = a [ i ] . ToUpper ( ) ;
object o ;
if ( this . TryGetValue ( a [ i ] , out o ) )
{
// convert floating points with invariant culture info
if ( o . GetType ( ) = = typeof ( double ) )
s = s + ( ( double ) o ) . ToString ( CultureInfo . InvariantCulture ) ;
else if ( o . GetType ( ) = = typeof ( float ) )
s = s + ( ( float ) o ) . ToString ( CultureInfo . InvariantCulture ) ;
else
s = s + o . ToString ( ) ;
}
else
{
throw new ArgumentException ( "Var identifier not found: " + a [ i ] ) ;
}
}
}
}
catch ( Exception ex )
{
// throw an excecption
throw new ArgumentException ( "Error while parsing string for variables [" + ex . Message + "]: " + s ) ;
}
}
return s ;
}
}
}