Files
Umbraco-CMS/src/Umbraco.Core/Persistence/Repositories/SimilarNodeName.cs

113 lines
3.4 KiB
C#
Raw Normal View History

2017-09-23 10:08:18 +02:00
using System;
2017-09-15 18:22:19 +02:00
using System.Collections.Generic;
using System.Linq;
namespace Umbraco.Core.Persistence.Repositories
{
internal class SimilarNodeName
{
private int _numPos = -2;
public int Id { get; set; }
public string Text { get; set; }
2017-09-15 18:22:19 +02:00
// cached - reused
public int NumPos
{
get
{
if (_numPos != -2) return _numPos;
var name = Text;
2017-09-15 18:22:19 +02:00
if (name[name.Length - 1] != ')')
return _numPos = -1;
var pos = name.LastIndexOf('(');
if (pos < 2 || pos == name.Length - 2) // < 2 and not < 0, because we want at least "x ("
return _numPos = -1;
return _numPos = pos;
}
}
// not cached - used only once
public int NumVal
{
get
{
if (NumPos < 0)
throw new InvalidOperationException();
int num;
if (int.TryParse(Text.Substring(NumPos + 1, Text.Length - 2 - NumPos), out num))
2017-09-15 18:22:19 +02:00
return num;
return 0;
}
}
// compare without allocating, nor parsing integers
internal class Comparer : IComparer<SimilarNodeName>
{
public int Compare(SimilarNodeName x, SimilarNodeName y)
{
if (x == null) throw new ArgumentNullException("x");
if (y == null) throw new ArgumentNullException("y");
var xpos = x.NumPos;
var ypos = y.NumPos;
var xname = x.Text;
var yname = y.Text;
2017-09-15 18:22:19 +02:00
if (xpos < 0 || ypos < 0 || xpos != ypos)
return string.Compare(xname, yname, StringComparison.Ordinal);
// compare the part before (number)
var n = string.Compare(xname, 0, yname, 0, xpos, StringComparison.Ordinal);
if (n != 0)
return n;
// compare (number) lengths
var diff = xname.Length - yname.Length;
if (diff != 0) return diff < 0 ? -1 : +1;
// actually compare (number)
var i = xpos;
while (i < xname.Length - 1)
{
if (xname[i] != yname[i])
return xname[i] < yname[i] ? -1 : +1;
i++;
}
return 0;
}
}
// gets a unique name
public static string GetUniqueName(IEnumerable<SimilarNodeName> names, int nodeId, string nodeName)
{
var uniqueNumber = 1;
var uniqueing = false;
foreach (var name in names.OrderBy(x => x, new Comparer()))
{
// ignore self
if (nodeId != 0 && name.Id == nodeId) continue;
if (uniqueing)
{
if (name.NumPos > 0 && name.Text.StartsWith(nodeName) && name.NumVal == uniqueNumber)
2017-09-15 18:22:19 +02:00
uniqueNumber++;
else
break;
}
else if (name.Text.InvariantEquals(nodeName))
2017-09-15 18:22:19 +02:00
{
uniqueing = true;
}
}
return uniqueing ? string.Concat(nodeName, " (", uniqueNumber.ToString(), ")") : nodeName;
}
}
2017-09-23 10:08:18 +02:00
}