using System;
using System.Text;
namespace NzbDrone.Core.Parser.RomanNumerals
{
///
/// Represents the numeric system used in ancient Rome, employing combinations of letters from the Latin alphabet to signify values.
/// Implementation adapted from: http://www.c-sharpcorner.com/Blogs/14255/converting-to-and-from-roman-numerals.aspx
///
public class RomanNumeral : IComparable, IComparable, IEquatable, IRomanNumeral
{
///
/// The numeric value of the roman numeral.
///
private readonly int _value;
///
/// Represents the smallest possible value of an . This field is constant.
///
public static readonly int MinValue = 1;
///
/// Represents the largest possible value of an . This field is constant.
///
public static readonly int MaxValue = 3999;
private static readonly string[] Thousands = { "MMM", "MM", "M" };
private static readonly string[] Hundreds = { "CM", "DCCC", "DCC", "DC", "D", "CD", "CCC", "CC", "C" };
private static readonly string[] Tens = { "XC", "LXXX", "LXX", "LX", "L", "XL", "XXX", "XX", "X" };
private static readonly string[] Units = { "IX", "VIII", "VII", "VI", "V", "IV", "III", "II", "I" };
///
/// Initializes a new instance of the class.
///
public RomanNumeral()
{
_value = 1;
}
///
/// Initializes a new instance of the class.
///
/// The value.
public RomanNumeral(int value)
{
_value = value;
}
///
/// Initializes a new instance of the class.
///
/// The roman numeral.
public RomanNumeral(string romanNumeral)
{
if (TryParse(romanNumeral, out var value))
{
_value = value;
}
}
///
/// Converts this instance to an integer.
///
/// A numeric int representation.
public int ToInt()
{
return _value;
}
///
/// Converts this instance to a long.
///
/// A numeric long representation.
public long ToLong()
{
return _value;
}
///
/// Converts the string representation of a number to its 32-bit signed integer equivalent. A return value indicates whether the conversion succeeded.
///
/// A string containing a number to convert.
/// When this method returns, contains the 32-bit signed integer value equivalent of the number contained in ,
/// if the conversion succeeded, or zero if the conversion failed. The conversion fails if the parameter is null or
/// , is not of the correct format, or represents a number less than or greater than . This parameter is passed uninitialized. 1
///
/// true if was converted successfully; otherwise, false.
///
public static bool TryParse(string text, out int value)
{
value = 0;
if (string.IsNullOrEmpty(text))
{
return false;
}
text = text.ToUpper();
var len = 0;
for (var i = 0; i < 3; i++)
{
if (text.StartsWith(Thousands[i]))
{
value += 1000 * (3 - i);
len = Thousands[i].Length;
break;
}
}
if (len > 0)
{
text = text.Substring(len);
len = 0;
}
for (var i = 0; i < 9; i++)
{
if (text.StartsWith(Hundreds[i]))
{
value += 100 * (9 - i);
len = Hundreds[i].Length;
break;
}
}
if (len > 0)
{
text = text.Substring(len);
len = 0;
}
for (var i = 0; i < 9; i++)
{
if (text.StartsWith(Tens[i]))
{
value += 10 * (9 - i);
len = Tens[i].Length;
break;
}
}
if (len > 0)
{
text = text.Substring(len);
len = 0;
}
for (var i = 0; i < 9; i++)
{
if (text.StartsWith(Units[i]))
{
value += 9 - i;
len = Units[i].Length;
break;
}
}
if (text.Length > len)
{
value = 0;
return false;
}
return true;
}
///
/// Converts a number into a roman numeral.
///
/// The number.
///
private static string ToRomanNumeral(int number)
{
RangeGuard(number);
int thousands, hundreds, tens, units;
thousands = number / 1000;
number %= 1000;
hundreds = number / 100;
number %= 100;
tens = number / 10;
units = number % 10;
var sb = new StringBuilder();
if (thousands > 0)
{
sb.Append(Thousands[3 - thousands]);
}
if (hundreds > 0)
{
sb.Append(Hundreds[9 - hundreds]);
}
if (tens > 0)
{
sb.Append(Tens[9 - tens]);
}
if (units > 0)
{
sb.Append(Units[9 - units]);
}
return sb.ToString();
}
///
/// Returns the Roman numeral that was passed in as either an Arabic numeral
/// or a Roman numeral.
///
/// A representing a Roman Numeral
public string ToRomanNumeral()
{
return ToString();
}
///
/// Determines whether a given number is within the valid range of values for a roman numeral.
///
/// The number to validate.
///
/// $Roman numerals can not be larger than {MaxValue}.
/// or
/// $Roman numerals can not be smaller than {MinValue}.
///
private static void RangeGuard(int number)
{
if (number > MaxValue)
{
throw new ArgumentOutOfRangeException(nameof(number), number, $"Roman numerals can not be larger than {MaxValue}.");
}
if (number < MinValue)
{
throw new ArgumentOutOfRangeException(nameof(number), number, $"Roman numerals can not be smaller than {MinValue}.");
}
}
///
/// Implements the operator *.
///
/// The first numeral.
/// The second numeral.
///
/// The result of the operator.
///
public static RomanNumeral operator *(RomanNumeral firstNumeral, RomanNumeral secondNumeral)
{
return new RomanNumeral(firstNumeral._value * secondNumeral._value);
}
///
/// Implements the operator /.
///
/// The numerator.
/// The denominator.
///
/// The result of the operator.
///
public static RomanNumeral operator /(RomanNumeral numerator, RomanNumeral denominator)
{
return new RomanNumeral(numerator._value / denominator._value);
}
///
/// Implements the operator +.
///
/// The first numeral.
/// The second numeral.
///
/// The result of the operator.
///
public static RomanNumeral operator +(RomanNumeral firstNumeral, RomanNumeral secondNumeral)
{
return new RomanNumeral(firstNumeral._value + secondNumeral._value);
}
///
/// Implements the operator -.
///
/// The first numeral.
/// The second numeral.
///
/// The result of the operator.
///
public static RomanNumeral operator -(RomanNumeral firstNumeral, RomanNumeral secondNumeral)
{
return new RomanNumeral(firstNumeral._value - secondNumeral._value);
}
///
///
/// The object.
///
public int CompareTo(object obj)
{
if (obj is sbyte
|| obj is byte
|| obj is short
|| obj is ushort
|| obj is int
|| obj is uint
|| obj is long
|| obj is ulong
|| obj is float
|| obj is double
|| obj is decimal)
{
var value = (int)obj;
return _value.CompareTo(value);
}
else if (obj is string)
{
var numeral = obj as string;
if (TryParse(numeral, out var value))
{
return _value.CompareTo(value);
}
}
return 0;
}
///
/// Compares to.
///
/// The other.
///
public int CompareTo(RomanNumeral other)
{
return _value.CompareTo(other._value);
}
///
/// Equalses the specified other.
///
/// The other.
///
public bool Equals(RomanNumeral other)
{
return _value == other._value;
}
///
/// Returns the Roman Numeral which was passed to this Instance
/// during creation.
///
///
/// A that represents a Roman Numeral.
///
public override string ToString()
{
return ToRomanNumeral(_value);
}
}
}