2016-10-26 21:02:01 -07:00
using System ;
2017-01-11 17:27:25 -08:00
using System.Collections.Generic ;
2020-08-20 14:36:36 -07:00
2020-12-07 14:29:45 -08:00
using SabreTools.Logging ;
2016-10-26 21:02:01 -07:00
2020-12-08 13:48:57 -08:00
namespace SabreTools.Filtering
2016-10-26 21:02:01 -07:00
{
2019-01-08 17:40:28 -08:00
/// <summary>
/// Represents the filtering operations that need to be performed on a set of items, usually a DAT
/// </summary>
2020-12-12 22:16:43 -08:00
public abstract class Filter
2019-01-08 17:40:28 -08:00
{
2020-10-07 15:42:30 -07:00
#region Logging
/// <summary>
/// Logging object
/// </summary>
2020-12-12 22:16:43 -08:00
protected Logger logger ;
2020-10-07 15:42:30 -07:00
#endregion
2020-10-07 16:37:10 -07:00
#region Constructors
/// <summary>
/// Constructor
/// </summary>
public Filter ( )
{
logger = new Logger ( this ) ;
}
#endregion
2020-07-18 21:35:17 -07:00
#region Filter Population
/// <summary>
/// Populate the filters object using a set of key:value filters
/// </summary>
/// <param name="filters">List of key:value where ~key/!key is negated</param>
2020-12-12 22:16:43 -08:00
public abstract void PopulateFromList ( List < string > filters ) ;
2020-07-18 21:35:17 -07:00
2020-12-12 22:03:04 -08:00
/// <summary>
2020-12-12 22:16:43 -08:00
/// Split the parts of a filter statement
2020-12-12 22:03:04 -08:00
/// </summary>
2020-12-12 22:16:43 -08:00
/// <param name="filter">key:value where ~key/!key is negated</param>
protected ( string field , string value , bool negate ) ProcessFilterPair ( string filter )
2020-12-12 22:03:04 -08:00
{
2020-12-12 22:16:43 -08:00
// If we don't even have a possible filter pair
if ( ! filter . Contains ( ":" ) )
2020-12-12 22:03:04 -08:00
{
2020-12-12 22:16:43 -08:00
logger . Warning ( $"'{filter}` is not a valid filter string. Valid filter strings are of the form 'key:value'. Please refer to README.1ST or the help feature for more details." ) ;
return ( null , null , false ) ;
2020-12-12 22:03:04 -08:00
}
2020-12-12 22:16:43 -08:00
string filterTrimmed = filter . Trim ( '"' , ' ' , '\t' ) ;
bool negate = filterTrimmed . StartsWith ( "!" )
| | filterTrimmed . StartsWith ( "~" )
| | filterTrimmed . StartsWith ( "not-" ) ;
filterTrimmed = filterTrimmed . TrimStart ( '!' , '~' ) ;
2020-12-14 16:01:28 -08:00
filterTrimmed = filterTrimmed . StartsWith ( "not-" ) ? filterTrimmed [ 4. . ] : filterTrimmed ;
2020-12-12 22:03:04 -08:00
2020-12-12 22:16:43 -08:00
string filterFieldString = filterTrimmed . Split ( ':' ) [ 0 ] . ToLowerInvariant ( ) . Trim ( '"' , ' ' , '\t' ) ;
2020-12-14 16:01:28 -08:00
string filterValue = filterTrimmed [ ( filterFieldString . Length + 1 ) . . ] . Trim ( '"' , ' ' , '\t' ) ;
2020-12-12 22:16:43 -08:00
return ( filterFieldString , filterValue , negate ) ;
2020-12-12 22:03:04 -08:00
}
2020-09-03 23:27:05 -07:00
/// <summary>
/// Set a bool? filter
/// </summary>
/// <param name="filterItem">FilterItem to populate</param>
/// <param name="value">String value to add</param>
/// <param name="negate">True to set negative filter, false otherwise</param>
2020-12-12 22:16:43 -08:00
protected void SetBooleanFilter ( FilterItem < bool? > filterItem , string value , bool negate )
2020-09-03 23:27:05 -07:00
{
if ( negate | | value . Equals ( "false" , StringComparison . OrdinalIgnoreCase ) )
filterItem . Neutral = false ;
else
filterItem . Neutral = true ;
}
2020-09-04 11:04:58 -07:00
/// <summary>
/// Set a long? filter
/// </summary>
/// <param name="filterItem">FilterItem to populate</param>
/// <param name="value">String value to add</param>
/// <param name="negate">True to set negative filter, false otherwise</param>
2020-12-12 22:16:43 -08:00
protected void SetDoubleFilter ( FilterItem < double? > filterItem , string value , bool negate )
2020-09-04 11:04:58 -07:00
{
bool? operation = null ;
if ( value . StartsWith ( ">" ) )
operation = true ;
else if ( value . StartsWith ( "<" ) )
operation = false ;
else if ( value . StartsWith ( "=" ) )
operation = null ;
string valueString = value . TrimStart ( '>' , '<' , '=' ) ;
if ( ! Double . TryParse ( valueString , out double valueDouble ) )
return ;
// Equal
if ( operation = = null & & ! negate )
{
filterItem . Neutral = valueDouble ;
}
// Not Equal
else if ( operation = = null & & negate )
{
filterItem . Negative = valueDouble - 1 ;
filterItem . Positive = valueDouble + 1 ;
}
// Greater Than or Equal
else if ( operation = = true & & ! negate )
{
filterItem . Positive = valueDouble ;
}
// Strictly Less Than
else if ( operation = = true & & negate )
{
filterItem . Negative = valueDouble - 1 ;
}
// Less Than or Equal
else if ( operation = = false & & ! negate )
{
filterItem . Negative = valueDouble ;
}
// Strictly Greater Than
else if ( operation = = false & & negate )
{
filterItem . Positive = valueDouble + 1 ;
}
}
2020-09-03 23:27:05 -07:00
/// <summary>
/// Set a long? filter
/// </summary>
/// <param name="filterItem">FilterItem to populate</param>
/// <param name="value">String value to add</param>
/// <param name="negate">True to set negative filter, false otherwise</param>
2020-12-12 22:16:43 -08:00
protected void SetLongFilter ( FilterItem < long? > filterItem , string value , bool negate )
2020-09-03 23:27:05 -07:00
{
bool? operation = null ;
if ( value . StartsWith ( ">" ) )
operation = true ;
else if ( value . StartsWith ( "<" ) )
operation = false ;
else if ( value . StartsWith ( "=" ) )
operation = null ;
string valueString = value . TrimStart ( '>' , '<' , '=' ) ;
if ( ! Int64 . TryParse ( valueString , out long valueLong ) )
return ;
// Equal
if ( operation = = null & & ! negate )
{
filterItem . Neutral = valueLong ;
}
// Not Equal
else if ( operation = = null & & negate )
{
filterItem . Negative = valueLong - 1 ;
filterItem . Positive = valueLong + 1 ;
}
// Greater Than or Equal
else if ( operation = = true & & ! negate )
{
filterItem . Positive = valueLong ;
}
// Strictly Less Than
else if ( operation = = true & & negate )
{
filterItem . Negative = valueLong - 1 ;
}
// Less Than or Equal
else if ( operation = = false & & ! negate )
{
filterItem . Negative = valueLong ;
}
// Strictly Greater Than
else if ( operation = = false & & negate )
{
filterItem . Positive = valueLong + 1 ;
}
}
/// <summary>
/// Set a string filter
/// </summary>
/// <param name="filterItem">FilterItem to populate</param>
/// <param name="value">String value to add</param>
/// <param name="negate">True to set negative filter, false otherwise</param>
2020-12-12 22:16:43 -08:00
protected void SetStringFilter ( FilterItem < string > filterItem , string value , bool negate )
2020-09-03 23:27:05 -07:00
{
if ( negate )
filterItem . NegativeSet . Add ( value ) ;
else
filterItem . PositiveSet . Add ( value ) ;
}
2020-07-18 21:35:17 -07:00
#endregion
2020-09-08 12:54:41 -07:00
#region Filter Running
/// <summary>
/// Determines if a value passes a bool? filter
/// </summary>
/// <param name="filterItem">Filter item to check</param>
/// <param name="value">Value to check</param>
/// <returns>True if the value passes, false otherwise</returns>
2020-12-13 13:22:06 -08:00
public static bool PassBoolFilter ( FilterItem < bool? > filterItem , bool? value )
2020-09-08 12:54:41 -07:00
{
if ( filterItem . MatchesNeutral ( null , value ) = = false )
return false ;
return true ;
}
/// <summary>
/// Determines if a value passes a double? filter
/// </summary>
/// <param name="filterItem">Filter item to check</param>
/// <param name="value">Value to check</param>
/// <returns>True if the value passes, false otherwise</returns>
2020-12-13 13:22:06 -08:00
public static bool PassDoubleFilter ( FilterItem < double? > filterItem , double? value )
2020-09-08 12:54:41 -07:00
{
if ( filterItem . MatchesNeutral ( null , value ) = = false )
return false ;
else if ( filterItem . MatchesPositive ( null , value ) = = false )
return false ;
else if ( filterItem . MatchesNegative ( null , value ) = = false )
return false ;
return true ;
}
/// <summary>
/// Determines if a value passes a long? filter
/// </summary>
/// <param name="filterItem">Filter item to check</param>
/// <param name="value">Value to check</param>
/// <returns>True if the value passes, false otherwise</returns>
2020-12-13 13:22:06 -08:00
public static bool PassLongFilter ( FilterItem < long? > filterItem , long? value )
2020-09-08 12:54:41 -07:00
{
if ( filterItem . MatchesNeutral ( null , value ) = = false )
return false ;
else if ( filterItem . MatchesPositive ( null , value ) = = false )
return false ;
else if ( filterItem . MatchesNegative ( null , value ) = = false )
return false ;
return true ;
}
/// <summary>
/// Determines if a value passes a string filter
/// </summary>
/// <param name="filterItem">Filter item to check</param>
/// <param name="value">Value to check</param>
/// <returns>True if the value passes, false otherwise</returns>
2020-12-13 13:22:06 -08:00
public static bool PassStringFilter ( FilterItem < string > filterItem , string value )
2020-09-08 12:54:41 -07:00
{
if ( filterItem . MatchesPositiveSet ( value ) = = false )
return false ;
if ( filterItem . MatchesNegativeSet ( value ) = = true )
return false ;
return true ;
}
#endregion
2019-01-08 17:40:28 -08:00
}
2016-10-26 21:02:01 -07:00
}