/*
* Copyright (C) 2016 Vyacheslav Shevelyov (slavash at aha dot ru)
*
* This program 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.
*
* This program 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 this program. If not, see http://www.gnu.org/licenses/.
*/
using IStation.Epanet.Enums;
using System.Globalization;
namespace IStation.Epanet.Util
{
///Epanet utilities methods.
public static class Utilities
{
/// Check if two strings match (case independent), based on the shortest string length.
/// string A.
/// string B.
/// Boolean is the two strings are similar.
public static bool Match2(this string a, string b)
{
if (string.IsNullOrEmpty(a) || string.IsNullOrEmpty(b)) return false;
return a.Length > b.Length
? a.StartsWith(b, StringComparison.OrdinalIgnoreCase)
: b.StartsWith(a, StringComparison.OrdinalIgnoreCase);
}
///
/// Sees if substr matches any part of str (not case sensitive).
///
/// string being searched
/// substring being searched for
/// returns true if substr found in str, false if not
public static bool Match(this string str, string substr)
{
/* Fail if substring is empty */
if (string.IsNullOrEmpty(str) || string.IsNullOrEmpty(substr))
return false;
/* Skip leading blanks of str. */
str = str.TrimStart();
/* Check if substr matches remainder of str. */
return str.StartsWith(substr, StringComparison.OrdinalIgnoreCase);
}
public static int FindMatch(this string str, params string[] substrings)
{
for (int i = 0; i < substrings.Length; i++)
{
if (Match(str, substrings[i]))
{
return i;
}
}
return -1;
}
/// Converts time from units to hours.
/// string containing a time value
/// string containing time units (PM or AM)
/// numerical value of time in hours (1.0 is 3600 seconds), or -1 if an error occurs
public static double GetHour(string time, string units = null)
{
const int COUNT = 3;
double[] y = new double[COUNT];
// Separate clock time into hrs, min, sec.
string[] s = (time ?? string.Empty).Split(':');
int n;
for (n = 0; n < COUNT && n < s.Length; n++)
{
if (!s[n].ToDouble(out y[n])) return -1;
}
// If decimal time with units attached then convert to hours.
if (n == 1)
{
if (string.IsNullOrEmpty(units)) return y[0];
if (Match(units, Keywords.w_SECONDS)) return y[0] / 3600.0;
if (Match(units, Keywords.w_MINUTES)) return y[0] / 60.0;
if (Match(units, Keywords.w_HOURS)) return y[0];
if (Match(units, Keywords.w_DAYS)) return y[0] * 24.0;
}
// Convert hh:mm:ss format to decimal hours
if (n > 1) y[0] = y[0] + y[1] / 60.0 + y[2] / 3600.0;
// If am/pm attached then adjust hour accordingly
// (12 am is midnight, 12 pm is noon)
if (string.IsNullOrEmpty(units)) return y[0];
if (units.Equals(Keywords.w_AM, StringComparison.OrdinalIgnoreCase))
{
if (y[0] >= 13.0) return -1.0;
if (y[0] >= 12.0) return y[0] - 12.0;
return y[0];
}
if (units.Equals(Keywords.w_PM, StringComparison.OrdinalIgnoreCase))
{
if (y[0] >= 13.0) return -1.0;
if (y[0] >= 12.0) return y[0];
return y[0] + 12.0;
}
return -1.0;
}
public static TimeSpan TimeOfDay(this TimeSpan t)
{
return new TimeSpan(t.Ticks % TimeSpan.TicksPerDay);
}
/// Converts time from units to hours.
/// string containing a time value
/// string containing time units (PM or AM)
/// numerical value of time in hours (1.0 is 3600 seconds), or -1 if an error occurs
public static TimeSpan ToTimeSpan(string time, string units = null)
{
const int COUNT = 3;
double[] y = new double[COUNT];
// Separate clock time into hrs, min, sec.
string[] s = (time ?? string.Empty).Split(':');
int n;
for (n = 0; n < COUNT && n < s.Length; n++)
{
if (!s[n].ToDouble(out y[n]))
return TimeSpan.MinValue;
}
// If decimal time with units attached then convert to hours.
if (n == 1)
{
if (string.IsNullOrEmpty(units)) return TimeSpan.FromHours(y[0]);
if (Match(units, Keywords.w_SECONDS)) return TimeSpan.FromSeconds(y[0]);
if (Match(units, Keywords.w_MINUTES)) return TimeSpan.FromMinutes(y[0]);
if (Match(units, Keywords.w_HOURS)) return TimeSpan.FromHours(y[0]);
if (Match(units, Keywords.w_DAYS)) return TimeSpan.FromDays(y[0]);
}
// Convert hh:mm:ss format to decimal hours
if (n > 1)
y[0] = y[0] + y[1] / 60.0 + y[2] / 3600.0;
// If am/pm attached then adjust hour accordingly
// (12 am is midnight, 12 pm is noon)
if (string.IsNullOrEmpty(units))
return TimeSpan.FromHours(y[0]);
if (units.Equals(Keywords.w_AM, StringComparison.OrdinalIgnoreCase))
{
if (y[0] >= 13.0) return TimeSpan.MinValue;
if (y[0] >= 12.0) return TimeSpan.FromHours(y[0] - 12.0);
return TimeSpan.FromHours(y[0]);
}
if (units.Equals(Keywords.w_PM, StringComparison.OrdinalIgnoreCase))
{
if (y[0] >= 13.0) return TimeSpan.MinValue;
if (y[0] >= 12.0) return TimeSpan.FromHours(y[0]);
return TimeSpan.FromHours(y[0] + 12.0);
}
return TimeSpan.MinValue;
}
public static string GetClockTime(this TimeSpan ts) => string.Format("{0:00}:{1:00}:{2:00}", (int)ts.TotalHours, ts.Minutes, ts.Seconds);
///Get value signal, if bigger than 0 returns 1, -1 otherwise.
/// Any real number.
/// -1 or 1
public static double Sign(this double val) => val < 0 ? -1d : 1d;
public static void Reverse(this LinkedList linkedList)
{
if (linkedList == null || linkedList.Count < 2) return;
LinkedListNode next;
var head = linkedList.First;
while ((next = head.Next) != null)
{
linkedList.Remove(next);
linkedList.AddFirst(next.Value);
}
}
public static bool ToDouble(this string s, out double result)
{
return double.TryParse(
s,
NumberStyles.Float | NumberStyles.AllowThousands,
NumberFormatInfo.InvariantInfo,
out result);
}
private const double DOUBLE_EPSILON = double.Epsilon * 100;
public static bool IsZero(this double value)
{
return Math.Abs(value) < DOUBLE_EPSILON;
}
public static bool EqualsTo(this double value, double other)
{
return Math.Abs(value - other) < DOUBLE_EPSILON;
}
public static bool IsZero(this TimeSpan value) { return value.Ticks == 0L; }
}
}