using System; using System.Linq; using System.Threading.Tasks; using FMSAdmin.Data; using FMSAdmin.Models; using FMSAdmin.Entities; using FMSApp.Services; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using Microsoft.AspNetCore.Authorization; using FMSAdmin.Helpers; using System.Data; using System.IO; using OfficeOpenXml; using System.Text.RegularExpressions; using System.Collections; using System.Collections.Generic; using FMSAdmin.Models.Formula; using FMSAdmin.Helpers.Formula; namespace FMSApp.Controllers { [Authorize] [ApiController] [ApiVersion("1")] [Route("api/app/[controller]")] public class FormulaController : Controller { private static Regex regexParameter = new Regex(@"\b[A-Z]\b", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.IgnoreCase); private static Regex regexFunction = new Regex(@"\$([\w]+).+\$", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.IgnoreCase); private static FormulaTableManager tableManager; private readonly ILogger _logger; private readonly FormulaService _service; private readonly FMSContext _context; public FormulaController( ILogger logger, FormulaService service, FMSContext context ) { _logger = logger; _service = service; _context = context; tableManager = new FormulaTableManager(context); } /// // 성능분석-챠트에 사용되는듯 /// [HttpGet("[action]")] public IActionResult Calculation([FromQuery] int siteId, [FromQuery] int facilityTypeId, [FromQuery] int formulaId, [FromQuery] int facilityCode, [FromQuery] int timeIntervalType, [FromQuery] string sDate, [FromQuery] string eDate) { DateTime startDate = DateTime.Parse(sDate); DateTime endDate = DateTime.Parse(eDate); List list = new List(); BemsFormula formula = GetFormula(Util.ToInt(siteId), Util.ToInt(facilityTypeId), Util.ToInt(facilityCode), Util.ToInt(formulaId)); if (formula == null) return Ok(new { }); TimeInterval timeInterval = (TimeInterval)timeIntervalType; ArrayList parameters = new ArrayList(); MathCalculator calculator = new MathCalculator(); if (false == calculator.Compile(formula.Formula)) { throw new Exception("Failed to compile formula: " + formula.Formula); } var match = regexParameter.Match(formula.Formula); if (match.Success) { var queryParameters = _context.BemsFormulaParameter.Where(x => x.SiteId == siteId && x.FacilityTypeId == facilityTypeId && (facilityTypeId >= 100 || x.FacilityCode == facilityCode) && x.FormulaId == formulaId); if (queryParameters == null || queryParameters.Any() == false) { throw new Exception(string.Format("Not Found Formula Parameters: {0},{1},{2},{3}", siteId, facilityTypeId, facilityCode, formulaId)); } List parametersForArray = new List(); var test = queryParameters.ToList(); foreach (var p in queryParameters.ToList()) { char parameter = p.ParameterId[0]; var pValue = new MathParameterValue { Variable = (MathCalculator.Parameter)(parameter - 'A'), Value = 0, }; parametersForArray.Add(pValue); var values = CreateCalculationValues(startDate, endDate, timeInterval); var pointvalues = _service.GetPointValues(siteId, p.ParameterFacilityCode, p.ParameterPropertyId, timeInterval, startDate, endDate); if (pointvalues == null) continue; CalculationValue pp = null; CalculationValue v = null; for (var i = 0; i < values.Length; i++) { v = values[i]; for (var j = 0; j < pointvalues.Length; j++) { pp = pointvalues[j]; if (pp.DateTime == v.DateTime) { v.Value += pp.Value; } } } parameters.Add(new CalculationParameter { ParameterValue = pValue, Values = values }); } calculator.SetParameter(parametersForArray.ToArray()); } { var functions = calculator.GetFunctions(); if (functions.Any()) { foreach (var f in functions) { var tableValues = tableManager.GetTableValues(f.Function.FunctionName); if (tableValues == null) { throw new Exception("Not Found Function."); } f.Function.FunctionDelegate = (x) => { var index = Array.BinarySearch(tableValues, new FormulaTableManager.TableComparerValue { XValue = (double)x }); if (index < 0) { index = ~index; if (index == 0) { return Math.Round((decimal)tableValues[0].YValue, 2); } else if (index == tableValues.Length) { return Math.Round((decimal)tableValues[tableValues.Length - 1].YValue, 2); } } return Math.Round((decimal)tableValues[index].YValue, 2); }; } } } DateTime dateTime = DateTime.Now; if (parameters.Count > 0) { var ps = parameters.Cast().ToArray(); ParameterBox parameterBox = new ParameterBox(ps); while (parameterBox.Sync()) { var value = calculator.Calculate(); if (value != null) { list.Add(new CalculationResult { DateTime = parameterBox.DateTime, ShortDateTime = timeInterval == TimeInterval.Day ? parameterBox.DateTime.ToString("yyyy.MM.dd") : parameterBox.DateTime.ToString("yyyy.MM"), Value = Math.Round((double)value, 2) //Value = (double)value }); } if (parameterBox.NextStage() == false) { break; } } } else { IList emptyArr = new List(); return Ok(new { total = 0, page = 1, limit = 0, list = emptyArr, maxValue = 0 }); } //list.Select(x=>x.Value).Max(); return Ok(new { total = list.Count(), page = 1, limit = 0, list = list, maxValue = list.Select(x => x.Value).Max() }); } public BemsFormula GetFormula(int siteId, int facilityTypeId, int facilityCode, int formulaId) { var queryFormula = from f in _context.BemsFormula where f.SiteId == siteId && f.FacilityTypeId == facilityTypeId && (facilityTypeId >= 100 || f.FacilityCode == facilityCode) && f.FormulaId == formulaId select f; if (queryFormula == null || queryFormula.Any() == false) { return null; } return queryFormula.Single(); } private CalculationValue[] CreateCalculationValues(DateTime startDate, DateTime endDate, TimeInterval timeIntervalType) { DateTime datetime = startDate; int count = GetCountInTimeRange(startDate, endDate, timeIntervalType); CalculationValue[] values = new CalculationValue[count]; for (var i = 0; i < values.Length; i++) { values[i] = new CalculationValue { DateTime = datetime, Value = 0 }; NextTimeFromTimeInterval(ref datetime, timeIntervalType); } return values; } private int GetCountInTimeRange(DateTime startDate, DateTime endDate, TimeInterval timeIntervalType) { TimeSpan ts = endDate - startDate; switch (timeIntervalType) { case TimeInterval.QuarterMin: return (int)ts.TotalMinutes / 15 + 1; case TimeInterval.Hour: return (int)ts.TotalHours + 1; case TimeInterval.Day: return (int)ts.TotalDays + 1; case TimeInterval.Month: { int count = 0; DateTime date = startDate; //while (date.Year <= endDate.Year && date.Month <= endDate.Month) while (date <= endDate) { count++; date = date.AddMonths(1); } return count; } default: // TimeInterval.Year: { int count = 0; DateTime date = startDate; while (date.Year <= endDate.Year) { count++; date = date.AddYears(1); } return count; } } } private void NextTimeFromTimeInterval(ref DateTime datetime, TimeInterval timeIntervalType) { switch (timeIntervalType) { case TimeInterval.QuarterMin: datetime = datetime.AddMinutes(15); break; case TimeInterval.Hour: datetime = datetime.AddHours(1); break; case TimeInterval.Day: datetime = datetime.AddDays(1); break; case TimeInterval.Month: datetime = datetime.AddMonths(1); break; default: // TimeInterval.Year: datetime = datetime.AddYears(1); break; } } } }