using System.Collections.Generic;
using SabreTools.Core;
using SabreTools.Core.Tools;
using SabreTools.Logging;
namespace SabreTools.Filtering
{
///
/// Represents the filtering operations that need to be performed on a set of items, usually a DAT
///
/// TODO: Can clever use of Filtering allow for easier external splitting methods?
/// TODO: Investigate how to reduce the amount of hardcoded filter statements
public class MachineFilter
{
#region Fields
#region Filters
#region Common
public FilterItem Name { get; private set; } = new FilterItem();
public FilterItem Comment { get; private set; } = new FilterItem();
public FilterItem Description { get; private set; } = new FilterItem();
public FilterItem Year { get; private set; } = new FilterItem();
public FilterItem Manufacturer { get; private set; } = new FilterItem();
public FilterItem Publisher { get; private set; } = new FilterItem();
public FilterItem Category { get; private set; } = new FilterItem();
public FilterItem RomOf { get; private set; } = new FilterItem();
public FilterItem CloneOf { get; private set; } = new FilterItem();
public FilterItem SampleOf { get; private set; } = new FilterItem();
public FilterItem Type { get; private set; } = new FilterItem() { Positive = 0x0, Negative = 0x0 };
#endregion
#region AttractMode
public FilterItem Players { get; private set; } = new FilterItem();
public FilterItem Rotation { get; private set; } = new FilterItem();
public FilterItem Control { get; private set; } = new FilterItem();
public FilterItem Status { get; private set; } = new FilterItem();
public FilterItem DisplayCount { get; private set; } = new FilterItem();
public FilterItem DisplayType { get; private set; } = new FilterItem();
public FilterItem Buttons { get; private set; } = new FilterItem();
#endregion
#region ListXML
public FilterItem SourceFile { get; private set; } = new FilterItem();
public FilterItem Runnable { get; private set; } = new FilterItem() { Positive = Core.Runnable.NULL, Negative = Core.Runnable.NULL };
#endregion
#region Logiqx
public FilterItem Board { get; private set; } = new FilterItem();
public FilterItem RebuildTo { get; private set; } = new FilterItem();
#endregion
#region Logiqx EmuArc
public FilterItem TitleID { get; private set; } = new FilterItem();
public FilterItem Developer { get; private set; } = new FilterItem();
public FilterItem Genre { get; private set; } = new FilterItem();
public FilterItem Subgenre { get; private set; } = new FilterItem();
public FilterItem Ratings { get; private set; } = new FilterItem();
public FilterItem Score { get; private set; } = new FilterItem();
public FilterItem Enabled { get; private set; } = new FilterItem();
public FilterItem CRC { get; private set; } = new FilterItem() { Neutral = null };
public FilterItem RelatedTo { get; private set; } = new FilterItem();
#endregion
#region OpenMSX
public FilterItem GenMSXID { get; private set; } = new FilterItem();
public FilterItem System { get; private set; } = new FilterItem();
public FilterItem Country { get; private set; } = new FilterItem();
#endregion
#region SoftwareList
public FilterItem Supported { get; private set; } = new FilterItem() { Positive = Core.Supported.NULL, Negative = Core.Supported.NULL };
#endregion
#endregion // Machine Filters
#region Additional Flags
///
/// Include romof and cloneof when filtering machine names
///
public bool IncludeOfInGame { get; set; }
#endregion
#endregion // Fields
#region Logging
///
/// Logging object
///
private readonly Logger logger;
#endregion
#region Constructors
///
/// Constructor
///
public MachineFilter()
{
logger = new Logger(this);
}
#endregion
#region Filter Population
///
/// Populate the filters object using a set of key:value filters
///
/// List of key:value where ~key/!key is negated
public void PopulateFromList(List filters)
{
foreach (string filterPair in filters)
{
// If we don't even have a possible filter pair
if (!filterPair.Contains(":"))
{
logger.Warning($"'{filterPair}` 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.");
continue;
}
string filterPairTrimmed = filterPair.Trim('"', ' ', '\t');
bool negate = filterPairTrimmed.StartsWith("!")
|| filterPairTrimmed.StartsWith("~")
|| filterPairTrimmed.StartsWith("not-");
filterPairTrimmed = filterPairTrimmed.TrimStart('!', '~');
filterPairTrimmed = filterPairTrimmed.StartsWith("not-") ? filterPairTrimmed.Substring(4) : filterPairTrimmed;
string filterFieldString = filterPairTrimmed.Split(':')[0].ToLowerInvariant().Trim('"', ' ', '\t');
string filterValue = filterPairTrimmed.Substring(filterFieldString.Length + 1).Trim('"', ' ', '\t');
MachineField filterField = filterFieldString.AsMachineField();
SetFilter(filterField, filterValue, negate);
}
}
///
/// Set multiple filters from key
///
/// Key for the filter to be set
/// List of values for the filter
/// True if negative filter, false otherwise
public void SetFilter(MachineField key, List values, bool negate)
{
foreach (string value in values)
{
SetFilter(key, value, negate);
}
}
///
/// Set a single filter from key
///
/// Key for the filter to be set
/// Value of the filter
/// True if negative filter, false otherwise
public void SetFilter(MachineField key, string value, bool negate)
{
switch (key)
{
#region Common
case MachineField.Name:
SetStringFilter(Name, value, negate);
break;
case MachineField.Comment:
SetStringFilter(Comment, value, negate);
break;
case MachineField.Description:
SetStringFilter(Description, value, negate);
break;
case MachineField.Year:
SetStringFilter(Year, value, negate);
break;
case MachineField.Manufacturer:
SetStringFilter(Manufacturer, value, negate);
break;
case MachineField.Publisher:
SetStringFilter(Publisher, value, negate);
break;
case MachineField.Category:
SetStringFilter(Category, value, negate);
break;
case MachineField.RomOf:
SetStringFilter(RomOf, value, negate);
break;
case MachineField.CloneOf:
SetStringFilter(CloneOf, value, negate);
break;
case MachineField.SampleOf:
SetStringFilter(SampleOf, value, negate);
break;
case MachineField.Type:
if (negate)
Type.Negative |= value.AsMachineType();
else
Type.Positive |= value.AsMachineType();
break;
#endregion
#region AttractMode
case MachineField.Players:
SetStringFilter(Players, value, negate);
break;
case MachineField.Rotation:
SetStringFilter(Rotation, value, negate);
break;
case MachineField.Control:
SetStringFilter(Control, value, negate);
break;
case MachineField.Status:
SetStringFilter(Status, value, negate);
break;
case MachineField.DisplayCount:
SetStringFilter(DisplayCount, value, negate);
break;
case MachineField.DisplayType:
SetStringFilter(DisplayType, value, negate);
break;
case MachineField.Buttons:
SetStringFilter(Buttons, value, negate);
break;
#endregion
#region ListXML
case MachineField.SourceFile:
SetStringFilter(SourceFile, value, negate);
break;
case MachineField.Runnable:
if (negate)
Runnable.Negative |= value.AsRunnable();
else
Runnable.Positive |= value.AsRunnable();
break;
#endregion
#region Logiqx
case MachineField.Board:
SetStringFilter(Board, value, negate);
break;
case MachineField.RebuildTo:
SetStringFilter(RebuildTo, value, negate);
break;
#endregion
#region Logiqx EmuArc
case MachineField.TitleID:
SetStringFilter(TitleID, value, negate);
break;
case MachineField.Developer:
SetStringFilter(Developer, value, negate);
break;
case MachineField.Genre:
SetStringFilter(Genre, value, negate);
break;
case MachineField.Subgenre:
SetStringFilter(Subgenre, value, negate);
break;
case MachineField.Ratings:
SetStringFilter(Ratings, value, negate);
break;
case MachineField.Score:
SetStringFilter(Score, value, negate);
break;
case MachineField.Enabled:
SetStringFilter(Enabled, value, negate);
break;
case MachineField.CRC:
SetBooleanFilter(CRC, value, negate);
break;
case MachineField.RelatedTo:
SetStringFilter(RelatedTo, value, negate);
break;
#endregion
#region OpenMSX
case MachineField.GenMSXID:
SetStringFilter(GenMSXID, value, negate);
break;
case MachineField.System:
SetStringFilter(System, value, negate);
break;
case MachineField.Country:
SetStringFilter(Country, value, negate);
break;
#endregion
#region SoftwareList
case MachineField.Supported:
if (negate)
Supported.Negative |= value.AsSupported();
else
Supported.Positive |= value.AsSupported();
break;
#endregion
}
}
#endregion
}
}