///
/// Copyright © 2003-2008 JetBrains s.r.o.
/// You may distribute under the terms of the GNU General Public License, as published by the Free Software Foundation, version 2 (see License.txt in the repository root folder).
///
using System;
using System.Collections;
using System.Globalization;
using JetBrains.Omea.OpenAPI;
namespace JetBrains.Omea.ResourceStore
{
public class ResourceComparer: IComparer
{
///
/// Queried for a property provider when comparing its resources.
///
protected ResourceList _owner;
protected static SortSettings _emptySortSettings = new SortSettings();
protected SortSettings _sortSettings;
protected PropDataType[] _propTypes;
protected static PropDataType[] _emptyPropTypes = new PropDataType[] {};
protected bool _propsEquivalent;
protected bool _customSortAscending;
protected IResourceComparer _customComparer;
///
/// Constructs a comparer that uses a hierarchical set of properties to compare by.
///
/// A resource list that has a property provider
/// that will be queried to get the property values for individual resources.
/// Deinfes the sorting columns and ascending/descending directions for them.
/// Specifies whether all the properties are treated equivalent,
/// which means that if two sorting properties are suggested, the first of them which is defined for that particular object
/// will take part in the comparison, not necessarily the same props on both objects.
public ResourceComparer( IResourceList owner, SortSettings sortSettings, bool propsEquivalent )
{
if(sortSettings == null)
throw new ArgumentNullException("sortSettings");
_owner = (ResourceList) owner;
_sortSettings = sortSettings;
_propTypes = new PropDataType [_sortSettings.SortProps.Length];
for( int i=0; i<_sortSettings.SortProps.Length; i++ )
{
_propTypes [i] = GetSortPropType( _sortSettings.SortProps [i] );
}
_propsEquivalent = propsEquivalent;
}
///
/// Allows to delegate all the comparison operations to a custom resource comparer.
///
/// Reserved. This value is ignored when sorting against a custom comparer.
/// The custom comparer that handles all the comparison operations for this object.
/// Property IDs are converted to resources before getting into the custom comparer.
/// True if you would like to accept the sorting direction of the custom comparer,
/// and False if you'd like to reverse it.
public ResourceComparer( IResourceList owner, IResourceComparer customComparer, bool dontReverse )
{
_owner = (ResourceList) owner;
_sortSettings = _emptySortSettings;
_propTypes = _emptyPropTypes;
_customComparer = customComparer;
_customSortAscending = dontReverse;
}
///
/// A helper function that returnes a property type of the given property ID.
///
protected PropDataType GetSortPropType( int propID )
{
switch( propID )
{
case ResourceProps.Type: return PropDataType.String;
case ResourceProps.DisplayName: return PropDataType.String;
case ResourceProps.Id: return PropDataType.Int;
default:
return MyPalStorage.Storage.GetPropDataType( propID );
}
}
///
/// Sort settings.
///
public SortSettings SortSettings
{
get { return _sortSettings; }
}
///
/// Gets or sets whether all the properties supplied for sorting are equivalent, and sorting can be performed against any of them that are defined on the resource.
///
public bool PropsEquivalent
{
get { return _propsEquivalent; }
set { _propsEquivalent = value; }
}
///
/// Checks whether this comparer is sorting the resources only by their IDs in ascending order.
///
internal bool IsIdSort()
{
return _sortSettings.SortProps.Length == 1
&& _sortSettings.SortProps [0] == ResourceProps.Id
&& _sortSettings.SortDirections [0];
}
///
/// A comparer that can compare both IResource instances and resource IDs.
///
int IComparer.Compare( object x, object y )
{
IResource r1 = x as IResource;
IResource r2;
if ( r1 == null )
{
int id1 = (int) x;
int id2 = (int) y;
if ( id1 == id2 )
return 0;
r1 = MyPalStorage.Storage.LoadResource( id1 );
r2 = MyPalStorage.Storage.LoadResource( id2 );
}
else
{
r2 = (IResource) y;
}
if ( x == y )
return 0;
if ( _customComparer != null )
{
return _customComparer.CompareResources( r1, r2 ) * (_customSortAscending ? 1 : -1);
}
if ( _propsEquivalent )
{
return CompareResourcesEquivalent( r1, r2 );
}
return CompareResources( r1, r2 );
}
///
/// Compares resources where properties are hierarchical (when sorting by P1 and P2,
/// if a resource doesn't have the value for P1, it is considered smaller than any
/// resource which has a value for P1).
///
public int CompareResources( IResource r1, IResource r2 )
{
int propEquals = 0;
for( int i=0; i<_sortSettings.SortProps.Length; i++ )
{
// Compare the current pair of properties
int propId = _sortSettings.SortProps [i];
if ( propId == ResourceProps.Type )
{
propEquals = r1.Type.CompareTo( r2.Type );
}
else if ( propId == ResourceProps.DisplayName )
{
propEquals = String.Compare( r1.DisplayName, r2.DisplayName, true, CultureInfo.CurrentCulture );
}
else if ( propId == ResourceProps.Id )
{
propEquals = r1.Id - r2.Id;
}
else if ( _propTypes [i] == PropDataType.Link )
{
propEquals = r1.GetPropText( propId ).CompareTo( r2.GetPropText( propId ) );
}
else
{
object prop1 = (_owner != null) ? _owner.GetPropValue( r1, propId ) : r1.GetProp( propId );
object prop2 = (_owner != null) ? _owner.GetPropValue( r2, propId ) : r2.GetProp( propId );
if ( prop1 != null || prop2 != null )
{
propEquals = CompareProps( prop1, prop2 );
}
}
if ( propEquals != 0 )
return propEquals * (_sortSettings.SortDirections [i] ? 1 : -1);
}
return 0;
}
///
/// Compares resources where the values of all properties are equivalent
/// (when sorting by P1 and P2, if a resource doesn't have the value for P1,
/// the value of P2 is taken and compared with other resources' values of P1.
///
public int CompareResourcesEquivalent( IResource r1, IResource r2 )
{
object prop1 = GetAnySortProperty( r1 );
object prop2 = GetAnySortProperty( r2 );
if ( prop1 == null && prop2 == null )
{
return 0;
}
return CompareProps( prop1, prop2 ) * (_sortSettings.SortAscending ? 1 : -1);
}
///
/// Returns the first available property from the list of sort properties
/// for the specified resource.
///
protected object GetAnySortProperty( IResource res )
{
for( int i=0; i<_sortSettings.SortProps.Length; i++ )
{
int propId = _sortSettings.SortProps [i];
if ( propId == ResourceProps.Type )
{
return res.Type;
}
else if ( propId == ResourceProps.DisplayName )
{
return res.DisplayName;
}
else if ( propId == ResourceProps.Id )
{
return res.Id;
}
else if ( _propTypes [i] == PropDataType.Link )
{
if ( res.HasProp( propId ) )
{
return res.GetPropText( propId );
}
}
else
{
object propValue = (_owner != null) ? _owner.GetPropValue( res, propId ) : res.GetProp( propId );
if ( propValue != null )
{
return propValue;
}
}
}
return null;
}
///
/// Compares two generic object values.
/// If either is null, it's smaller.
/// If the first prop implements IComparable, it's used to compare it to the second one.
/// Otherwise, the values are considered to be equal.
///
protected int CompareProps( object prop1, object prop2 )
{
if ( prop1 != null && prop2 == null )
return 1;
if ( prop1 == null && prop2 != null )
return -1;
IComparable prop1Comparable = prop1 as IComparable;
if ( prop1Comparable == null )
return 0;
int cmp = prop1Comparable.CompareTo( prop2 );
if ( cmp != 0 )
return cmp;
return 0;
}
}
}