using System; using System.Collections.Generic; using System.Linq; using System.Web.Mvc; using NHibernate; using NHibernate.Linq; using Sleis.Models; using Sleis.Infrastructure; using log4net; using Sleis.Utility; using Sleis.Data; using Sleis.ViewModels; using System.IO; using System.Text; using Ionic.Zip; using Windsor.Commons.Core; using Sleis.Models.CustomFields; using Sleis.Models.ErrorHandling; using Microsoft.VisualBasic.FileIO; using Sleis.Validation.Spring; namespace Sleis.Service { public abstract class ProcessEmissionService : BaseService, Sleis.Service.IProcessEmissionService { public IUnitProcessService UnitProcessService { get; set; } public IProcessEmissionData ProcessEmissionData { get; set; } public IEmissionData EmissionData { get; set; } public IUnitProcessData UnitProcessData { get; set; } public IEmissionUnitData EmissionUnitData { get; set; } //public ReportFacilityData ReportFacilityData { get; set; } //private UnitProcessService _UnitProcessService = SpringServiceProvider.GetService(); public override void Init() { base.Init(); ArgumentValidationUtility.ThrowOnNull(ProcessEmissionData, "ProcessEmissionData"); } public abstract void LoadEmissions(ProcessEmission pe); public abstract void LoadUnitProcessDetails(ProcessEmission processEmission); public abstract ProcessEmission GetProcessEmission(int id); public abstract List GetProcessEmissionList(int reportId); public abstract List GetProcessEmissionList(int reportId, bool fullyLoad); public abstract ProcessEmission GetProcessEmission(int id, int unitProcessId); public abstract ProcessEmission GetProcessEmission(int id, UnitProcess unitProcess); public abstract ProcessEmission SaveProcessEmission(ProcessEmission processEmission, List customFields); public abstract List GetProcessEmissionListItemsByReport(int reportId, int reportYear); public abstract List GetProcessEmissionListItemsByReport(int reportId, int pageNum, int pageSize); public abstract List GetProcessEmissionListItems(int reportId, int emissionUnitId); public abstract List GetProcessEmissionListItemsByUnitProcess(int unitProcessId); public abstract int CountProcessEmissions(int reportId); public abstract void DeleteProcessEmission(int id); public void DeleteProcessEmission(ProcessEmission processEmission) { DeleteProcessEmission(processEmission.Id); } public List GetEmissionFactors(string pollutantCode, string calculationMethodCode, string sccCode, string emissionFactorUomCode) { return ProcessEmissionData.GetEmissionFactors(pollutantCode, calculationMethodCode, sccCode, emissionFactorUomCode); } public decimal CalculateControlEfficiency(int unitProcessId, string pollutantCode) { return ProcessEmissionData.CalculateControlEfficiency(SessionUtility.CurrentReport.Number, unitProcessId, pollutantCode); } public List GetProcessEmissionList(int reportId, int emissionUnitId) { List filtered = new List(); foreach (ProcessEmission pe in GetProcessEmissionList(reportId)) { if (pe.UnitProcess.EmissionUnit.Id == emissionUnitId) { filtered.Add(pe); } } return filtered; } protected void SetEmissionDefaultValues(Emission emission) { emission.UomCode = "TON"; //default value. currently not set from UI. } public int RecalculateEmissionsByControlDevice(int controlDeviceId) { List processes = ProcessEmissionData.GetProcessEmissionsByControlDevice(controlDeviceId); return RecalculateEmissionsAndSave(processes); } public int RecalculatemMissionsByEmissionUnit(int emissionUnitId) { List processes = ProcessEmissionData.GetProcessEmissionsByEmissionUnit(emissionUnitId); return RecalculateEmissionsAndSave(processes); } public int RecalculateEmissionsByUnitProcess(int unitProcessId) { ProcessEmission process = GetProcessEmission(0, unitProcessId); List processes = new List(); processes.Add(process); return RecalculateEmissionsAndSave(processes); } public List RecalculateEmissions(List emissions) { List errors = new List(); //LoadEmissions(pe); foreach (Emission emis in emissions) { //make sure PE has all necessary calculated values //CalculateSeasonalTotals(emis.ProcessEmission); EmissionCalculation cal = new EmissionCalculation ( emis.ProcessEmission.UnitProcessId, emis.ProcessEmission.Value, emis.ProcessEmission.ValueUomCode, emis.PollutantCode, emis.CalculationMethodCode, emis.Factor, emis.FactorDenomenatorUomCode, emis.ProcessEmission.ValueTypeCode, emis.ProcessEmission.AshContentPercent, emis.ProcessEmission.SulfurContentPercent, emis.ProcessEmission.ActualSummerSeasonDays, emis.ProcessEmission.SummerActivityPercent, CalculatePercentOzoneSeasonActivity(emis.ProcessEmission), emis.TotalEmissions, emis.ProcessEmission.UnitProcess.UnitProcessClassCode ); //recalculate total emissions ProcessEmissionData.CalculateEmissions(SessionUtility.CurrentReport.Number, cal); //set new total - TODO://Might need to check for error code.... if (cal.CalculationResult == 0) { emis.TotalEmissions = cal.TotalEmissions; emis.SummerDayEmissions = cal.SummerDayEmissions; emis.OzoneSeasonEmissions = cal.OzoneSeasonEmissions; } else if (cal.CalculationResult == -1) { emis.SummerDayEmissions = cal.SummerDayEmissions; emis.OzoneSeasonEmissions = cal.OzoneSeasonEmissions; } else { emis.SetContext(""); var err = new RuleError(null, cal.ErrorMessage); err.Context = emis.ValidationContxt; errors.Add(err); } } return errors; } public int RecalculateEmissionsAndSave(List processes) { int count = 0; using (ISession session = ProcessEmissionData.GetSession()) { using (ITransaction trans = session.BeginTransaction()) { foreach (ProcessEmission pe in processes) { LoadCompleteModel(pe); LoadEmissions(pe); foreach (Emission emis in pe.Emissions) { EmissionCalculation cal = new EmissionCalculation ( pe.UnitProcessId, pe.Value, pe.ValueUomCode, emis.PollutantCode, emis.CalculationMethodCode, emis.Factor, emis.FactorDenomenatorUomCode, pe.ValueTypeCode, pe.AshContentPercent, pe.SulfurContentPercent, pe.ActualSummerSeasonDays, pe.SummerActivityPercent, CalculatePercentOzoneSeasonActivity(pe), emis.TotalEmissions, pe.UnitProcess.UnitProcessClassCode ); //recalculate total emissions ProcessEmissionData.CalculateEmissions(SessionUtility.CurrentReport.Number, cal); //set new total - TODO://Might need to check for error code.... if (cal.CalculationResult == 0) { emis.TotalEmissions = cal.TotalEmissions; emis.SummerDayEmissions = cal.SummerDayEmissions; emis.OzoneSeasonEmissions = cal.OzoneSeasonEmissions; //save EmissionData.SaveOrUpdate(emis, session); } else if (cal.CalculationResult == -1) { emis.SummerDayEmissions = cal.SummerDayEmissions; emis.OzoneSeasonEmissions = cal.OzoneSeasonEmissions; //save EmissionData.SaveOrUpdate(emis, session); } count++; } } trans.Commit(); } } return count; } public decimal? CalculatePercentOzoneSeasonActivity(ProcessEmission processEmission) { if (Properties.Get(Constants.EnableMonthlyThroughputTotals).ToLower() == "true") { if (processEmission.MayVal.HasValue && processEmission.JuneVal.HasValue && processEmission.JulyVal.HasValue && processEmission.AugustVal.HasValue && processEmission.SeptemberVal.HasValue && processEmission.Value.HasValue && processEmission.Value.Value > 0) { return ((processEmission.MayVal.Value + processEmission.JuneVal.Value + processEmission.JulyVal.Value + processEmission.AugustVal.Value + processEmission.SeptemberVal.Value) / processEmission.Value.Value) * 100; } else { return null; } } else { if (processEmission.SpringActivityPercent.HasValue && processEmission.SummerActivityPercent.HasValue && processEmission.FallActivityPercent.HasValue) { return (processEmission.SpringActivityPercent.Value * (1 / 3)) + processEmission.SummerActivityPercent.Value + (processEmission.FallActivityPercent.Value * (1 / 3)); } else { return null; } } } public void CalculateSeasonalTotals(ProcessEmission processEmission) { processEmission.WinterActivityPercent = processEmission.DecemberVal + processEmission.JanuaryVal + processEmission.FebruaryVal; processEmission.SpringActivityPercent = processEmission.MarchVal + processEmission.AprilVal + processEmission.MayVal; processEmission.SummerActivityPercent = processEmission.JuneVal + processEmission.JulyVal + processEmission.AugustVal; processEmission.FallActivityPercent = processEmission.SeptemberVal + processEmission.OctoberVal + processEmission.NovemberVal; } public void CalculateAnnualTotal(ProcessEmission pe) { if (Properties.Get(Constants.EnableMonthlyThroughputTotals).ToLower() == "true") { //if all values are null- make sure we set PE Value (Annual Throughput) to null if (pe.JanuaryVal == null && pe.FebruaryVal == null && pe.MarchVal == null && pe.AprilVal == null && pe.MayVal == null && pe.JuneVal == null && pe.JulyVal == null && pe.AugustVal == null && pe.SeptemberVal == null && pe.OctoberVal == null && pe.NovemberVal == null && pe.DecemberVal == null) pe.Value = null; //otherwise sum what we have else { pe.Value = (pe.JanuaryVal ?? 0) + (pe.FebruaryVal ?? 0) + (pe.MarchVal ?? 0) + (pe.AprilVal ?? 0) + (pe.MayVal ?? 0) + (pe.JuneVal ?? 0) + (pe.JulyVal ?? 0) + (pe.AugustVal ?? 0) + (pe.SeptemberVal ?? 0) + (pe.OctoberVal ?? 0) + (pe.NovemberVal ?? 0) + (pe.DecemberVal ?? 0); } } else { //make sure nothing gets saved. pe.JanuaryVal = null; pe.FebruaryVal = null; pe.MarchVal = null; pe.AprilVal = null; pe.MayVal = null; pe.JuneVal = null; pe.JulyVal = null; pe.AugustVal = null; pe.SeptemberVal = null; pe.OctoberVal = null; pe.NovemberVal = null; pe.DecemberVal = null; } } public EmissionCalculation CalculateEmissions(EmissionCalculation emission) { //call to data layer. return ProcessEmissionData.CalculateEmissions(SessionUtility.CurrentReport.Number, emission); } public void GenerateProcessEmissionsTemplatesZip(int reportId, Stream outputStream) { AgencyReport report = ProcessEmissionData.GetById(reportId); List processes = GetProcessEmissionList(reportId, true); MemoryStream processesCsvStream = new MemoryStream(GenerateProcessesCsv(processes)); MemoryStream processEmissionsCsvStream = new MemoryStream(GenerateProcessEmissionsCsv(processes)); MemoryStream referenceDataValuesCsvStream = new MemoryStream(GenerateReferenceValuesCsv(report.Number)); try { using (ZipFile zip = new ZipFile()) { zip.AddFileStream("Processes.csv", "", processesCsvStream); zip.AddFileStream("ProcessEmissions.csv", "", processEmissionsCsvStream); zip.AddFileStream("ReferenceDataValues.csv", "", referenceDataValuesCsvStream); zip.Save(outputStream); } } catch (Exception err) { Log.Error("Error creating Csv Templates for Process Emissions : ", err); } finally { processEmissionsCsvStream.Dispose(); processesCsvStream.Dispose(); referenceDataValuesCsvStream.Dispose(); } } public List ImportEmissions(Stream processEmissionsCsv, int reportId, List processes) { CsvParserError exception = new CsvParserError("ProcessEmissions"); List emissions = new List(); long numOfLines = 0; try { emissions = ImportProcessEmissionsFromCsv(processEmissionsCsv, exception, out numOfLines); } catch (CsvParserError parserError) { //swallow the exception and keep going. this way we have a giant descriptive error at the end. exception = parserError; } finally { for (int i = 0; i < emissions.Count; i++) { ValidateAndSetEmissionForeignKeys(Convert.ToInt32(numOfLines - emissions.Count + i + 1), emissions[i], reportId, exception, emissions, processes); } if (exception.HasErrors) { //now that we have the cumulative list - throw it. throw exception; } //SaveProcessEmissions(emissions); } return emissions; } public List SaveProcessEmissions(List emissions) { //create list of processEmission Ids so that we can delete all emissions currently associated in system List processes = new List(); foreach (Emission e in emissions) { if (!processes.Exists(p => p.Id == e.ProcessEmissionId)) { processes.Add(GetProcessEmission(e.ProcessEmissionId)); } } using (ISession session = ProcessEmissionData.GetSession()) { using (ITransaction trans = session.BeginTransaction()) { trans.Begin(); foreach (ProcessEmission p in processes) { EmissionData.DeleteAllByProcessEmission(p.Id, session); } //Save all of the new data foreach (Emission e in emissions) { if (processes.Single(x=>x.Id == e.ProcessEmissionId).IsReported.Value) { SetEmissionDefaultValues(e); EmissionData.Create(e, session); } } trans.Commit(); } } return emissions; } public List ImportProcesses(Stream processesCsv, int reportId, out CsvParserError error) { error = new CsvParserError("Processes"); List processes = new List(); long numOfLines = 0; try { processes = ImportProcessesFromCsv(processesCsv, error, out numOfLines); } catch (CsvParserError parserError) { //swallow the exception and keep going. this way we have a giant descriptive error at the end. error = parserError; } finally { for (int i = 0; i < processes.Count; i++) { ValidateAndSetProcessEmssionForeignKeys(Convert.ToInt32(numOfLines - processes.Count + i + 1), processes[i], reportId, error, processes); CalculateAnnualTotal(processes[i]); } /* Commented out. * if (exception.HasErrors) { //now that we have the cumulative list - throw it. throw exception; } * */ } //SaveProcesses(processes); return processes; } public List SaveProcesses(List processes) { using (ISession session = ProcessEmissionData.GetSession()) { using (ITransaction trans = session.BeginTransaction()) { trans.Begin(); foreach (ProcessEmission pe in processes) { //make sure IsCbi is always false if set to false in deployment.config regardless of what imported value may be if (Convert.ToBoolean(Properties.Get(Constants.UseProcessIsCbi)) == false) { pe.IsCbi = false; } if (!pe.IsReported.Value) { pe.SetValuesAsNull(); } pe.LastUpdated = DateTime.Now; pe.LastUpdatedBy = SessionUtility.CurrentUser; SetProcessEmissionDefaultValues(pe); ProcessEmissionData.SaveOrUpdate(pe, session); } trans.Commit(); } } return processes; } public byte[] GenerateProcessEmissionsCsv(List processes) { StringBuilder sb = new StringBuilder(); sb.AppendLine ( string.Join ("," ,"EmissionUnitId" ,"ProcessId" ,"PollutantCode" ,"CalculationMethod" ,"EmissionFactor" ,"EmissionFactorUnit" ,"EmissionQty" ,"Comments" ) ); //sort by EmissionUnitId ASC, //ProcesssId ASC, //PollutantCode ASC List emissions = new List(); foreach (ProcessEmission p in processes) { emissions.AddRange(p.Emissions); } foreach (Emission emission in emissions.OrderBy(e=>e.EmissionUnitIdentifier).ThenBy(e=>e.ProcessEmissionId).ThenBy(e=>e.PollutantCode)) { sb.AppendLine ( CsvUtility.CreateLine ( emission.EmissionUnitIdentifier , emission.UnitProcessIdentifier , emission.PollutantCode , emission.CalculationMethodCode , emission.Factor , emission.FactorDenomenatorUomCode , emission.TotalEmissions , emission.Comment ) ); } return Encoding.ASCII.GetBytes(sb.ToString()); } public byte[] GenerateProcessesCsv(List processes) { StringBuilder sb = new StringBuilder(); //make csv header sb.AppendLine ( string.Join ("," ,EmissionUnitIdCsvHeader ,ProcessIdCsvHeader ,AnnualThroughputQuantityCsvHdr ,AnnualThroughputUnitCsvHdr ,ThroughputTypeCsvHdr ,AnnualThroughputMaterialCsvHdr ,JanThroughputCsvHdr ,FebThroughputCsvHdr ,MarchThroughputCsvHdr ,AprilThroughputCsvHdr ,MayThroughputCsvHdr ,JuneThroughputCsvHdr ,JulyThroughputCsvHdr ,AugThroughputCsvHdr ,SeptThroughputCsvHdr ,OctThroughputCsvHdr ,NovThroughputCsvHdr ,DecThroughputCsvHdr ,ActlHrsOperationCsvHdr ,AvgHrsPerDayCsvHdr ,AvgDaysPerWeekCsvHdr ,AvgWeeksPerYearCsvHdr ,WinterOpPctCsvHdr ,SpringOpPctCsvHdr ,SummerOpPctCsvHdr ,FallOpPctCsvHdr ,TotalOzoneSeasonDaysCsvHdr ,TotalSummerSeasonDaysCsvHdr ,TotalCOSeasonDaysCsvHdr ,AshPctCntCsvHdr ,SulfurPctCntCsvHdr ,HeatContentCsvHdr ,IsReportedCsvHdr ,IsConfidentialCsvHdr ,CommentsCsvHdr ) ); //append values foreach (ProcessEmission pe in processes.OrderBy(pe => pe.UnitProcess.EmissionIdentifier).ThenBy(pe => pe.UnitProcess.Identifier)) { sb.AppendLine ( CsvUtility.CreateLine ( pe.UnitProcess.EmissionIdentifier , pe.UnitProcess.Identifier , pe.Value , pe.ValueUomCode , pe.ValueTypeCode , pe.MaterialTypeCode , pe.JanuaryVal , pe.FebruaryVal , pe.MarchVal , pe.AprilVal , pe.MayVal , pe.JuneVal , pe.JulyVal , pe.AugustVal , pe.SeptemberVal , pe.OctoberVal , pe.NovemberVal , pe.DecemberVal , pe.ActualHoursPerPeriod , pe.AvgHoursPerDay , pe.AvgDaysPerWeek , pe.AvgWeeksPerPeriod , pe.WinterActivityPercent , pe.SpringActivityPercent , pe.SummerActivityPercent , pe.FallActivityPercent , pe.TotalOzoneSeasonDays , pe.ActualSummerSeasonDays , pe.TotalCoSeasonDays , pe.AshContentPercent , pe.SulfurContentPercent , pe.HeatContent , pe.IsReported , pe.IsCbi , pe.Comment ) ); } return Encoding.ASCII.GetBytes(sb.ToString()); } /// /// Generate a list of LookupTypes and Applicable Codes - Descriptions that will be possible for Processes and ProcessEmissions /// /// public byte[] GenerateReferenceValuesCsv(int reportYear) { List emissionCalculationUomList = LookupUtility.Get(reportYear); List parameterTypes = LookupUtility.Get(reportYear); List materialTypes = LookupUtility.Get(reportYear); List calculationMethods = LookupUtility.Get(reportYear); List factorDenomenatorUomTypes = LookupUtility.Get(reportYear); List pollutantTypes = LookupUtility.Get(reportYear); List throughputTypes = LookupUtility.Get(reportYear); StringBuilder sb = new StringBuilder(); //header sb.AppendLine(string.Join(",", "AttributeName", "Value", "Description","Notes")); foreach (SimpleLookupItem i in emissionCalculationUomList) { sb.AppendLine(CsvUtility.CreateLine("ThroughputUnit",i.Code,i.Value,"")); } foreach (SimpleLookupItem i in parameterTypes) { sb.AppendLine(CsvUtility.CreateLine("ThroughputType", i.Code, i.Value, "")); } foreach (SimpleLookupItem i in materialTypes) { sb.AppendLine(CsvUtility.CreateLine("ThroughputMaterial", i.Code, i.Value, "")); } foreach (SimpleLookupItem i in calculationMethods) { sb.AppendLine(CsvUtility.CreateLine("CalculationMethod", i.Code, i.Value, "")); } foreach (SimpleLookupItem i in factorDenomenatorUomTypes) { sb.AppendLine(CsvUtility.CreateLine("EmissionFactorUnit", i.Code, i.Value, "")); } foreach (SimpleLookupItem i in pollutantTypes) { sb.AppendLine(CsvUtility.CreateLine("PollutantTypes", i.Code, i.Value, "")); } return Encoding.ASCII.GetBytes(sb.ToString()); } public List ImportProcessesFromCsv(Stream csvStream, CsvParserError parserError, out long numOfLines) { List processes = new List(); //CsvParserException parserError = new CsvParserException(); using (SleisCsvParser parser = new SleisCsvParser(csvStream)) { numOfLines = parser.LineNumber-1; while (parser.NextLine()) { numOfLines++; //if (parser.LineNumber > 0) { numOfLines = parser.LineNumber; } ProcessEmission pe = new PublicProcessEmission(); //TODO: refactor for Agency pe.UnitProcess.EmissionIdentifier = ParseColumn(parser, numOfLines, EmissionUnitIdCsvHeader, parserError); pe.UnitProcess.Identifier = ParseColumn(parser, numOfLines, ProcessIdCsvHeader, parserError); pe.Value = ParseColumn(parser, numOfLines, AnnualThroughputQuantityCsvHdr, parserError); pe.ValueUomCode = ParseColumn(parser, numOfLines, AnnualThroughputUnitCsvHdr, parserError); pe.ValueTypeCode = ParseColumn(parser, numOfLines, ThroughputTypeCsvHdr, parserError); pe.MaterialTypeCode = ParseColumn(parser, numOfLines, AnnualThroughputMaterialCsvHdr, parserError); pe.JanuaryVal = ParseColumn(parser, numOfLines, JanThroughputCsvHdr, parserError); pe.FebruaryVal = ParseColumn(parser, numOfLines, FebThroughputCsvHdr, parserError); pe.MarchVal = ParseColumn(parser, numOfLines, MarchThroughputCsvHdr, parserError); pe.AprilVal = ParseColumn(parser, numOfLines, AprilThroughputCsvHdr, parserError); pe.MayVal = ParseColumn(parser, numOfLines, MayThroughputCsvHdr, parserError); pe.JuneVal = ParseColumn(parser, numOfLines, JuneThroughputCsvHdr, parserError); pe.JulyVal = ParseColumn(parser, numOfLines, JulyThroughputCsvHdr, parserError); pe.AugustVal = ParseColumn(parser, numOfLines, AugThroughputCsvHdr, parserError); pe.SeptemberVal = ParseColumn(parser, numOfLines, SeptThroughputCsvHdr, parserError); pe.OctoberVal = ParseColumn(parser, numOfLines, OctThroughputCsvHdr, parserError); pe.NovemberVal = ParseColumn(parser, numOfLines, NovThroughputCsvHdr, parserError); pe.DecemberVal = ParseColumn(parser, numOfLines, DecThroughputCsvHdr, parserError); pe.ActualHoursPerPeriod = ParseColumn(parser, numOfLines, ActlHrsOperationCsvHdr, parserError); pe.AvgHoursPerDay = ParseColumn(parser, numOfLines, AvgHrsPerDayCsvHdr, parserError); pe.AvgDaysPerWeek = ParseColumn(parser, numOfLines, AvgDaysPerWeekCsvHdr, parserError); pe.AvgWeeksPerPeriod = ParseColumn(parser, numOfLines, AvgWeeksPerYearCsvHdr, parserError); pe.WinterActivityPercent = ParseColumn(parser, numOfLines, WinterOpPctCsvHdr, parserError); pe.SpringActivityPercent = ParseColumn(parser, numOfLines, SpringOpPctCsvHdr, parserError); pe.SummerActivityPercent = ParseColumn(parser, numOfLines, SummerOpPctCsvHdr, parserError); pe.FallActivityPercent = ParseColumn(parser, numOfLines, FallOpPctCsvHdr, parserError); pe.TotalOzoneSeasonDays = ParseColumn(parser, numOfLines, TotalOzoneSeasonDaysCsvHdr, parserError); pe.ActualSummerSeasonDays = ParseColumn(parser, numOfLines, TotalSummerSeasonDaysCsvHdr, parserError); pe.TotalCoSeasonDays = ParseColumn(parser, numOfLines, TotalCOSeasonDaysCsvHdr, parserError); pe.AshContentPercent = ParseColumn(parser, numOfLines, AshPctCntCsvHdr, parserError); pe.SulfurContentPercent = ParseColumn(parser, numOfLines, SulfurPctCntCsvHdr, parserError); pe.HeatContent = ParseColumn(parser, numOfLines, HeatContentCsvHdr, parserError); pe.IsReported = ParseColumn(parser, numOfLines, IsReportedCsvHdr, parserError); pe.IsCbi = ParseColumn(parser, numOfLines, IsConfidentialCsvHdr, parserError); pe.Comment = ParseColumn(parser, numOfLines, CommentsCsvHdr, parserError); //set default import values for non specified fields if (!pe.IsCbi.HasValue) { pe.IsCbi = false; } if (!pe.IsReported.HasValue) { pe.IsReported = true; } processes.Add(pe); } } //if (parserError.HasErrors) { throw parserError; } return processes; } public List ImportProcessEmissionsFromCsv(Stream csvStream, CsvParserError parserError, out long numOfLines) { List emissions = new List(); //CsvParserException parserError = new CsvParserException(); using (SleisCsvParser parser = new SleisCsvParser(csvStream)) { numOfLines = parser.LineNumber-1; //line number parser is starting at while (parser.NextLine()) { numOfLines++; //if (parser.LineNumber > 0) { numOfLines = parser.LineNumber; } Emission emission = new PublicEmission(); //TODO: change for Agency emission.UnitProcessIdentifier = ParseColumn(parser, numOfLines, ProcessIdCsvHeader, parserError); emission.EmissionUnitIdentifier = ParseColumn(parser, numOfLines, EmissionUnitIdCsvHeader, parserError); emission.PollutantCode = ParseColumn(parser, numOfLines, PollutantCodeCsvHeader, parserError); emission.CalculationMethodCode = ParseColumn(parser, numOfLines, CalcMethodCsvHeader, parserError); emission.Factor = ParseColumn(parser, numOfLines, EmissionFactorCsvHeader, parserError); emission.FactorDenomenatorUomCode = ParseColumn(parser, numOfLines, EmissionFactorUnitCsvHeader, parserError); emission.TotalEmissions = ParseColumn(parser, numOfLines, EmissionQtyCsvHeader, parserError); emission.Comment = ParseColumn(parser, numOfLines, CommentsCsvHdr, parserError); emissions.Add(emission); } } //if (parserError.HasErrors) { throw parserError; } return emissions; } private T ParseColumn(SleisCsvParser parser, long currentLineNum, string columnName, CsvParserError parserErr) { try { //need to convert scientfici notation vals and allow for nulls if (typeof(T) == typeof(decimal?)) { string val = parser.GetValue(columnName); if (!String.IsNullOrEmpty(val)) { Double d = 0; Double.TryParse(val, out d); return d.ConvertTo(); //return Convert.ToDecimal(val).ConvertTo(); } return default(T); } return parser.GetValue(columnName); } catch (Exception err) { parserErr.AddLineError(currentLineNum, columnName, err.Message); return default(T); } } protected void LoadModel(List list) { foreach (ProcessEmission model in list) { LoadModel(model); } } protected void LoadModel(ProcessEmission process) { if(process != null) { if (!String.IsNullOrWhiteSpace(process.ValueUomCode)) { process.ParameterUom = LookupUtility.Get(process.ValueUomCode); } if (!String.IsNullOrWhiteSpace(process.ValueTypeCode)) { process.ParameterType = LookupUtility.Get(process.ValueTypeCode); } if (!String.IsNullOrWhiteSpace(process.MaterialTypeCode)) { process.MaterialType = LookupUtility.Get(process.MaterialTypeCode); } if (!String.IsNullOrWhiteSpace(process.OperatingTypeCode)) { process.OperatingType = LookupUtility.Get(process.OperatingTypeCode); } } } protected void LoadCompleteModel(ProcessEmission process) { LoadModel(process); LoadUnitProcessDetails(process); foreach (Emission em in process.Emissions) { //TODO: Currently we populate ProcessEmission field needed for validation. Might be a better way to do this. feels a bit hacky. em.ProcessEmission = process; em.UnitProcessIdentifier = process.UnitProcess.Identifier; em.EmissionUnitIdentifier = process.UnitProcess.EmissionIdentifier; } } protected void SetProcessEmissionDefaultValues(ProcessEmission processEmission) { processEmission.TypeCode = "A"; processEmission.OperatingTypeCode = "R"; if (!processEmission.IsReported.HasValue) { processEmission.IsReported = false; } if (!processEmission.IsCbi.HasValue) { processEmission.IsCbi = false; } } #region validation private void ValidateAndSetEmissionForeignKeys(int lineNumber, Emission emission, int reportId, CsvParserError exception, List emissions, List processes) { //check for duplicate pollutants if (emissions.Where(x => x.UnitProcessIdentifier == emission.UnitProcessIdentifier && x.EmissionUnitIdentifier == emission.EmissionUnitIdentifier && x.PollutantCode == emission.PollutantCode).Count() > 1) { exception.AddLineError(lineNumber, "Duplicate pollutant."); } //get unit process PublicUnitProcess up = (PublicUnitProcess)UnitProcessData.GetByIdentifierAndEmissionUnitIdentifier(emission.UnitProcessIdentifier, emission.EmissionUnitIdentifier, reportId); //TODO REFACTOR if (up == null || up.Id < 1) { exception.AddLineError(lineNumber, String.Format("{0} or {1} is invalid.", ProcessIdCsvHeader, EmissionUnitIdCsvHeader)); } else { ProcessEmission pe = ProcessEmissionData.GetProcessEmission(reportId, up.Id); if (pe == null || pe.Id <= 0) { exception.AddLineError(lineNumber, "Process Emission record has not been created for this emission."); } else { emission.ProcessEmissionId = pe.Id; //looks like PE is not getting found. Possibly due to EU having a leading 0 in ID...... emission.ProcessEmission = processes.SingleOrDefault(x => x.Id == pe.Id); //single or default so that no error is thrown in the even that PE was not determined. //emission.ProcessEmission = pe; //was causing problems with validation } } // if (!String.IsNullOrWhiteSpace(emission.PollutantCode) && LookupUtility.Get(emission.PollutantCode) == null) { exception.AddLineError(lineNumber, PollutantCodeCsvHeader, "Invalid code."); } if (!String.IsNullOrWhiteSpace(emission.FactorDenomenatorUomCode) && LookupUtility.Get(emission.FactorDenomenatorUomCode) == null) { exception.AddLineError(lineNumber, EmissionFactorUnitCsvHeader, "Invalid code."); } if (!String.IsNullOrWhiteSpace(emission.CalculationMethodCode) && LookupUtility.Get(emission.CalculationMethodCode) == null) { exception.AddLineError(lineNumber, CalcMethodCsvHeader, "Invalid code."); } // // } private void ValidateAndSetProcessEmssionForeignKeys(int lineNumber, ProcessEmission processEmission, int reportId, CsvParserError exception, List processes) { //check for duplicate processes if (processes.Where(x => x.UnitProcess.Identifier == processEmission.UnitProcess.Identifier && x.UnitProcess.EmissionIdentifier == processEmission.UnitProcess.EmissionIdentifier).Count() > 1) { exception.AddLineError(lineNumber, "Duplicate processes."); } //get unit process PublicUnitProcess up = (PublicUnitProcess)UnitProcessData.GetByIdentifierAndEmissionUnitIdentifier(processEmission.UnitProcess.Identifier, processEmission.UnitProcess.EmissionIdentifier, reportId); //TODO REFACTOR if (up == null || up.Id < 1) { exception.AddLineError(lineNumber, String.Format("{0} or {1} is invalid.", ProcessIdCsvHeader, EmissionUnitIdCsvHeader)); } else { processEmission.UnitProcess = up; //Not sure why we were copying the complete record... processEmission.UnitProcessId = up.Id; //TODO: Clean this up. This is friggin hacktastic feeling. processEmission.UnitProcess.EmissionUnit = UnitProcessData.GetById(up.EmissionUnitId); processEmission.UnitProcess.EmissionIdentifier = processEmission.UnitProcess.EmissionUnit.Identifier; } //lookup ProcessEmission if there is one ProcessEmission peToUpdate = ProcessEmissionData.GetProcessEmission(reportId, processEmission.UnitProcessId); if (peToUpdate != null && peToUpdate.Id > 0) { processEmission.Id = peToUpdate.Id; } //TODO: ignore these fields. set by default //processEmission.TypeCode = "A"; //processEmission.OperatingTypeCode = "R"; //check ParameterUom if (!String.IsNullOrWhiteSpace(processEmission.ValueUomCode) && LookupUtility.Get(processEmission.ValueUomCode) == null) { exception.AddLineError(lineNumber, AnnualThroughputUnitCsvHdr, "Invalid code."); } //check MaterialType if(!String.IsNullOrWhiteSpace(processEmission.MaterialTypeCode) && LookupUtility.Get(processEmission.MaterialTypeCode) == null) { exception.AddLineError(lineNumber, AnnualThroughputMaterialCsvHdr, "Invalid code."); } if(!String.IsNullOrWhiteSpace(processEmission.ValueTypeCode) && LookupUtility.Get(processEmission.ValueTypeCode) == null) { exception.AddLineError(lineNumber, ThroughputTypeCsvHdr, "Invalid code."); } } #endregion #region CSV Header Constants private const string EmissionUnitIdCsvHeader = "EmissionUnitId"; private const string ProcessIdCsvHeader = "ProcessId"; private const string AnnualThroughputQuantityCsvHdr = "ThroughputQuantity"; private const string AnnualThroughputUnitCsvHdr = "ThroughputUnit"; private const string AnnualThroughputMaterialCsvHdr = "ThroughputMaterial"; private const string ThroughputTypeCsvHdr = "ThroughputType"; private const string JanThroughputCsvHdr = "JanuaryThroughput"; private const string FebThroughputCsvHdr = "FebruaryThroughput"; private const string MarchThroughputCsvHdr = "MarchThroughput"; private const string AprilThroughputCsvHdr = "AprilThroughput"; private const string MayThroughputCsvHdr = "MayThroughput"; private const string JuneThroughputCsvHdr = "JuneThroughput"; private const string JulyThroughputCsvHdr = "JulyThroughput"; private const string AugThroughputCsvHdr = "AugustThroughput"; private const string SeptThroughputCsvHdr = "SeptemberThroughput"; private const string OctThroughputCsvHdr = "OctoberThroughputQuantity"; private const string NovThroughputCsvHdr = "NovemberThroughputQuantity"; private const string DecThroughputCsvHdr = "DecemberThroughputQuantity"; private const string ActlHrsOperationCsvHdr = "ActualHrsOperation"; private const string AvgHrsPerDayCsvHdr = "AvgHrsPerDay"; private const string AvgDaysPerWeekCsvHdr = "AvgDaysPerWeek"; private const string AvgWeeksPerYearCsvHdr = "AvgWeeksPerYear"; private const string WinterOpPctCsvHdr = "DecToFebPercent"; private const string SpringOpPctCsvHdr = "MarToMayPercent"; private const string SummerOpPctCsvHdr = "JunToAugPercent"; private const string FallOpPctCsvHdr = "SepToNovPercent"; private const string TotalOzoneSeasonDaysCsvHdr = "TotalOzoneSeasonDays"; private const string TotalSummerSeasonDaysCsvHdr = "TotalSummerSeasonDays"; private const string TotalCOSeasonDaysCsvHdr = "TotalCOSeasonDays"; private const string AshPctCntCsvHdr = "AshContentPercent"; private const string SulfurPctCntCsvHdr = "SulfurContentPercent"; private const string HeatContentCsvHdr = "HeatContent"; private const string IsReportedCsvHdr = "IsReported"; private const string IsConfidentialCsvHdr = "IsConfidential"; private const string CommentsCsvHdr = "Comments"; // PRocess EMission Csv Headers private const string PollutantCodeCsvHeader = "PollutantCode"; private const string CalcMethodCsvHeader = "CalculationMethod"; private const string EmissionFactorCsvHeader = "EmissionFactor"; private const string EmissionFactorUnitCsvHeader = "EmissionFactorUnit"; private const string EmissionQtyCsvHeader = "EmissionQty"; #endregion } }