Léo
Léo

Reputation: 39

Exponential progress reporting

I would like to report to an user the current progress about a background counter, however, I'm stuck in my method. Indeed, I want more the counter timeout is higher and more there will be information.

For example, if the user sets a counter with a timeout of 60 secs, the counter will display at 30secs the remaining time, but if the user sets a counter with a one day timeout, the counter will display approximately every hour the remaining time.

So I did this, but I think it could largely be optimized with an exponential way.. Could you help me please Here's my code:

TimeSpan time = TimeSpan.FromSeconds(Seconds - i);
string strTime;

if (Seconds > 30 && Seconds <= 300)
{
    if (i == Seconds / 2)
    {
        strTime = time.ToString(@"mm\:ss");
        account.Logger.LogMessage(LanguageManager.Translate("165"), LanguageManager.Translate("614", strTime));
    }
}
else if (Seconds > 300 && Seconds <= 1800)
{
    int firstOcc = System.Convert.ToInt32(Math.Ceiling((double)Seconds / 3));
    int secondOcc = System.Convert.ToInt32(Math.Ceiling((double)Seconds * (2/3)));

    if (i == firstOcc || i == secondOcc || i == Seconds - 60)
    {
        strTime = time.ToString(@"mm\:ss");
        account.Logger.LogMessage(LanguageManager.Translate("165"), LanguageManager.Translate("614", strTime));
    }
}
else if (Seconds > 1800 && Seconds <= 7200)
{
    int firstOcc = System.Convert.ToInt32(Math.Ceiling((double)Seconds / 5));
    int secondOcc = System.Convert.ToInt32(Math.Ceiling((double)Seconds * (2 / 5)));
    int thirdOcc = System.Convert.ToInt32(Math.Ceiling((double)Seconds * (3 / 5)));
    int fourthOcc = System.Convert.ToInt32(Math.Ceiling((double)Seconds * (4 / 5)));

    if (i == firstOcc || i == secondOcc || i == thirdOcc || i == fourthOcc || i == Seconds - 60)
    {
        strTime = time.ToString(@"H\:mm\:ss");
        account.Logger.LogMessage(LanguageManager.Translate("165"), LanguageManager.Translate("614", strTime));
    }
}
else if (Seconds > 7200 && Seconds <= 43200)
{
    int firstOcc = System.Convert.ToInt32(Math.Ceiling((double)Seconds / 8));
    int secondOcc = System.Convert.ToInt32(Math.Ceiling((double)Seconds * (2 / 8)));
    int thirdOcc = System.Convert.ToInt32(Math.Ceiling((double)Seconds * (3 / 8)));
    int fourthOcc = System.Convert.ToInt32(Math.Ceiling((double)Seconds * (4 / 8)));
    int fifthOcc = System.Convert.ToInt32(Math.Ceiling((double)Seconds * (5 / 8)));
    int sixthOcc = System.Convert.ToInt32(Math.Ceiling((double)Seconds * (6 / 8)));
    int seventhOcc = System.Convert.ToInt32(Math.Ceiling((double)Seconds * (7 / 8)));

    if (i == firstOcc || i == secondOcc || i == thirdOcc || i == fourthOcc || i == fifthOcc || i == sixthOcc || i == seventhOcc || i == Seconds - 60)
    {
        strTime = time.ToString(@"H\:mm\:ss");
        account.Logger.LogMessage(LanguageManager.Translate("165"), LanguageManager.Translate("614", strTime));
    }
}
else if (Seconds > 43200)
{

Which is very redundant

Upvotes: 2

Views: 76

Answers (2)

Evan Trimboli
Evan Trimboli

Reputation: 30082

Here is an (untested) example of how you might go about refactoring your code to prevent repetition.

var time = TimeSpan.FromSeconds(seconds - i);

if (seconds <= 30)
{
    // What to do here?
    return;
}

int factor;
string format;

if (seconds <= 300)
{
    factor = 2;
    format = @"mm\:ss";
}
else if (seconds <= 1800)
{
    factor = 3;
    format = @"mm\:ss";
}
else if (seconds <= 7200)
{
    factor = 5;
    format = @"H\:mm\:ss";
}
else if (seconds <= 43200)
{
    factor = 8;
    format = @"H\:mm\:ss";
}
else
{
    // Defaults when no other condition is met.
    factor = 10;
    format = @"H\:mm\:ss";
}

if (i == seconds - 60 || Enumerable.Range(1, factor - 1).Any(n => i == seconds / factor * n))
{
    string timeDisplay = time.ToString(format);
    account.Logger.LogMessage(LanguageManager.Translate("165"), LanguageManager.Translate("614", timeDisplay));
}

Upvotes: 1

jdweng
jdweng

Reputation: 34421

I would use the log base 2. So the timers would be 32 seconds, 64 seconds, 128 seconds, 256 seconds, 512 seconds, 1024 seconds, 2048 seconds. So code would look something like this :

            List<int> seconds = new List<int>() { 60, 200, 400, 600, 800, 2300, 3599 };

            foreach (int second in seconds)
            {
                int timer = (second < 64)? 32 : (int)Math.Pow(2,(int)Math.Log(second, 2));
                Console.WriteLine("Seconds : '{0}'; Timer : '{1}'", second, timer);
            }
            Console.ReadLine();

Upvotes: 2

Related Questions