/*
* Copyright (c) 2025 Proton AG
*
* This file is part of ProtonVPN.
*
* ProtonVPN is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ProtonVPN is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ProtonVPN. If not, see .
*/
namespace ProtonVPN.Common.Core.Extensions;
public static class ExponentialExtensions
{
public static string ToShortString(this long number, string unit, UnitSpacing spacing)
{
int numOfDigits = Math.Abs(number).ToString().Length;
double shortValue = GenerateShortValue(number);
if (Math.Abs(shortValue).ToString().Length > 3) // Ex.: number=999500, shortValue=1000
{
numOfDigits++;
shortValue = GenerateShortValue(shortValue);
}
int thousandsExponent = (numOfDigits - 1) / 3;
string metricPrefix = GetMetricPrefix(thousandsExponent);
return $"{shortValue}{(spacing is UnitSpacing.WithSpace ? " " : "")}{metricPrefix}{unit}";
}
///
/// Returns the highest value digits, already prepared for the metric prefix
/// Ex.: 9876 > 9.9, 54321 > 54, 123456 > 123, Corner case: 999500 > 1000
///
private static double GenerateShortValue(double number)
{
int numOfDigits = Math.Abs(number).ToString().Length;
int remainderOfNumOfDigits = numOfDigits % 3;
if (remainderOfNumOfDigits == 0)
{
return Math.Round(number / Math.Pow(10, numOfDigits - 3));
}
else if (remainderOfNumOfDigits == 1)
{
return Math.Round(number / Math.Pow(10, numOfDigits - 2)) / 10;
}
else // remainderOfNumOfDigits == 2
{
return Math.Round(number / Math.Pow(10, numOfDigits - 2));
}
}
public enum UnitSpacing
{
WithSpace,
WithoutSpace,
}
/// Returns the metric prefix for 1000^X, with 0 being empty, 1 being K (Kilo), 2 being M (Mega)...
private static string GetMetricPrefix(int unit)
{
switch (unit)
{
case 0:
return string.Empty;
case 1:
return "K";
case 2:
return "M";
case 3:
return "G";
case 4:
return "T";
case 5:
return "P";
case 6:
return "E";
case 7:
return "Z";
case 8:
return "Y";
case 9:
return "R";
case 10:
return "Q";
default:
return "ERR";
}
}
}