using System; using System.Collections.Generic; using System.Data; using System.Data.OleDb; using System.IO; using System.Linq; using Deltares.Standard.Extensions; using System.Text; using Deltares.Standard.Application; //using log4net.Config; //using log4net.Repository.Hierarchy; namespace Deltares.Dam.Data.Sensors { /// /// Import sensor data from Excel sheet /// public class SensorImportFromExcelSheet { const string SensorProfileSheetName = "SensorProfileID"; const string SensorGroupSheetName = "SensorGroupID"; const string SensorSheetName = "SensorID"; const string DikeLineInProfileSheetName = "DikeLineInProfile"; const string IDColumnName = "ID"; const string SensorNameColumnName = "SensorName"; const string PLLineMappingColumnName = "PLLine-Mapping"; const string ProfileColumnName = "Profile"; internal readonly static LogHelper Logger = LogHelper.Create("Main Program."); /// /// Reads the sensor data from excel. /// /// The source file. /// The dike. /// /// Error reading excel file /// or /// The + PLLineMappingColumnName + column has an error. Make sure the cells are not empty and are formatted as text /// public static void ReadSensorDataFromExcel(string sourceFile, Dike dike) { var sheets = new[] { SensorProfileSheetName, SensorGroupSheetName, SensorSheetName, DikeLineInProfileSheetName }; DataSet ds = null; string fileName = sourceFile; var connectionString = string.Format("Provider=Microsoft.Jet.OLEDB.4.0; data source={0}; Extended Properties=Excel 8.0;", fileName); using (var conn = new OleDbConnection(connectionString)) { ds = FillDataSet(conn, ds, sheets); } if (ds == null) { throw new InvalidOperationException("Error reading excel file"); } var profiles = ds.Tables[SensorProfileSheetName].AsEnumerable(); var groups = ds.Tables[SensorGroupSheetName].AsEnumerable(); var sensors = ParseSensors(ds); var count = 0; foreach (var location in dike.Locations) { var repository = new SensorRepository(location); int id; if (ParseSensorProfileWorksheet(location, profiles, out id)) { continue; } // Parsing sensor groups if (ParseSensorGroups(groups, id, sensors, repository)) { continue; } count++; } Logger.LogInfo(string.Format("Successfully imported {0} sensor groups(s).", count)); Logger.LogInfo(string.Format("Successfully imported {0} sensor profile(s).", count)); } private static List ParseSensors(DataSet ds) { var sensors = new List(); var sensorRows = ds.Tables[SensorSheetName].AsEnumerable(); int count = 0; foreach (var row in sensorRows) { if (row.IsNull(IDColumnName)) { Logger.LogWarning(string.Format( "Error reading row {0} in worksheet {1}. This row will be skipped.", count + 2, SensorSheetName)); continue; } count++; var id = (int) row.Field(IDColumnName); var name = row.Field(SensorNameColumnName); var relativeLocation = row.Field("RelativeLocationSensorAlongProfileManual"); var depth = row.Field("DepthSensor"); var enumTypeIgnoreCase = row.Field("SensorType").ToEnumTypeIgnoreCase(); var sensor = new Sensor { ID = id, Name = name, RelativeLocation = relativeLocation, Depth = depth, Type = enumTypeIgnoreCase //1 255364,05597700000 598646,53034800000 //XRd = 255364.05597700000, //YRd = 598646.53034800000, }; try { var mappings = row.Field(PLLineMappingColumnName) .Split(new[] {';'}, StringSplitOptions.RemoveEmptyEntries) .Select(tag => tag.Trim()) //.Where(tag => !string.IsNullOrWhiteSpace(tag)) .ToArray(); foreach (var mapping in mappings) { switch (mapping) { case "1": sensor.Add(PLLineType.PL1); break; case "2": sensor.Add(PLLineType.PL2); break; case "3": sensor.Add(PLLineType.PL3); break; case "4": sensor.Add(PLLineType.PL4); break; } } } catch (Exception e) { throw new InvalidOperationException( "The " + PLLineMappingColumnName + " column has an error. Make sure the cells are not empty and are formatted as text", e); } Logger.LogInfo(sensor.ToString()); sensors.Add(sensor); } Logger.LogInfo(string.Format("Successfully imported {0} sensor(s).", count)); return sensors; } /// /// Parses the sensor groups. /// /// The sensor groups. /// The identifier. /// The sensors. /// The repository. /// /// /// private static bool ParseSensorGroups(IEnumerable sensorGroups, int id, List sensors, SensorRepository repository) { const string sensorSelectionColumnName = "SensorSelection"; string currentSensorId = ""; try { string[] groupIds = null; foreach (var sensorGroup in sensorGroups) { var idValue = (int)sensorGroup.Field(IDColumnName); if (idValue != id) { continue; } var groupIdValue = sensorGroup.Field(sensorSelectionColumnName); if (groupIdValue == null) { Logger.LogWarning(string.Format("Error reading the value from column {0} for group id {1}", sensorSelectionColumnName, id)); } groupIds = groupIdValue.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries); break; } if (groupIds == null) { Logger.LogWarning(string.Format("Couldn't find group id '{0}' in worksheet {1}", id, SensorGroupSheetName)); return true; } foreach (var groupId in groupIds) { currentSensorId = groupId; var single = sensors.Single(s => s.ID.ToString() == groupId); repository.Add(single); } } catch (InvalidOperationException ioe) { if (!string.IsNullOrWhiteSpace(currentSensorId)) { string message = string.Format("Error finding sensor. The sensor with ID '{0}' was not found in the Excel worksheet '{1}'", currentSensorId, SensorSheetName); throw new InvalidOperationException(message, ioe); } throw ioe; } catch (Exception e) { throw new InvalidOperationException( string.Format("An unknown error occurred in column " + sensorSelectionColumnName + " in the Excel sheet " + SensorGroupSheetName + ". Used the following location ID: " + id, e)); } return false; } /// /// Parses the sensor profile worksheet. /// /// The location. /// The sensor locations. /// The identifier. /// /// An error occurred while parsing row in worksheet + SensorProfileSheetName private static bool ParseSensorProfileWorksheet(Location location, EnumerableRowCollection sensorLocations, out int id) { id = -1; try { var record = sensorLocations .Where(x => x.Field(ProfileColumnName) == location.Name) .Select(x => new { ID = GetLocationIDField(x), GroupID = GetGroupIDField(x), Alias = GetNameAliasField(x), InputPL1OuterWaterLevel = GetPL1WaterLevelRiverSide(x), InputPL1PLLineOffsetBelowDikeTopAtRiver = GetPL1OffsetBelowDikeTopAtRiver(x), InputPL1PLLineOffsetBelowDikeTopAtPolder = GetPL1OffsetBelowDikeTopAtPolder(x), InputPL1PLLineOffsetBelowShoulderBaseInside = GetPL1OffsetBelowShoulderBaseInside(x), InputPL1PLLineOffsetBelowDikeToeAtPolder = GetPL1OffsetBelowDikeToeAtPolder(x), InputPL1PolderLevel = GetPL1PolderLevelSensorType(x), InputPL3 = GetInputPl3(x), InputPL4 = GetInputPl4(x) }).SingleOrDefault(); if (record == null) { Logger.LogWarning(string.Format("Location profile ID '{0}' not found in worksheet {1}. Location profile skipped.", location.Name, SensorProfileSheetName)); return true; } id = record.GroupID; var sensorLocation = location.SensorLocation; sensorLocation.Group.ID = record.GroupID; sensorLocation.Alias = record.Alias; sensorLocation.SourceTypePl1WaterLevelAtRiver = record.InputPL1OuterWaterLevel; sensorLocation.SourceTypePl1PlLineOffsetBelowDikeTopAtRiver = record.InputPL1PLLineOffsetBelowDikeTopAtRiver; sensorLocation.SourceTypePl1PlLineOffsetBelowDikeTopAtPolder = record.InputPL1PLLineOffsetBelowDikeTopAtPolder; sensorLocation.SourceTypePl1PlLineOffsetBelowShoulderBaseInside = record.InputPL1PLLineOffsetBelowShoulderBaseInside; sensorLocation.SourceTypePl1PlLineOffsetBelowDikeToeAtPolder = record.InputPL1PLLineOffsetBelowDikeToeAtPolder; sensorLocation.SourceTypePl1WaterLevelAtPolder = record.InputPL1PolderLevel; sensorLocation.SourceTypePl3 = record.InputPL3; sensorLocation.SourceTypePl4 = record.InputPL4; } catch (Exception e) { throw new InvalidOperationException("An error occurred while parsing row in worksheet " + SensorProfileSheetName, e); } return false; } /// /// Fills the data set. /// /// The connection. /// The ds. /// The sheets. /// private static DataSet FillDataSet(OleDbConnection conn, DataSet ds, string[] sheets) { conn.Open(); ds = new DataSet(); foreach (string sheet in sheets) { // string columns = String.Join(",", columnNames.ToArray()); const string columns = "*"; using (var da = new OleDbDataAdapter( "SELECT " + columns + " FROM [" + sheet + "$]", conn)) { var dt = new DataTable(sheet); da.Fill(dt); ds.Tables.Add(dt); } } return ds; } /// /// Gets the p l1 water level river side. /// /// The x. /// private static DataSourceTypeSensors GetPL1WaterLevelRiverSide(DataRow x) { DataSourceTypeSensors pl1WaterLevelRiverSide; try { pl1WaterLevelRiverSide = x.Field("InputPL1OuterWaterLevel").ToEnumTypeIgnoreCase(); } catch (Exception) { throw; } return pl1WaterLevelRiverSide; } /// /// Gets the p l1 offset below dike top at river. /// /// The x. /// private static DataSourceTypeSensors GetPL1OffsetBelowDikeTopAtRiver(DataRow x) { const string columnName = "InputPL1PLLineOffsetBelowDikeTopAtRiver"; DataSourceTypeSensors pl1OffsetBelowDikeTopAtRiver; try { pl1OffsetBelowDikeTopAtRiver = x.Field(columnName).ToEnumTypeIgnoreCase(); } catch (Exception) { throw; } return pl1OffsetBelowDikeTopAtRiver; } /// /// Gets the p l1 offset below dike top at polder. /// /// The x. /// private static DataSourceTypeSensors GetPL1OffsetBelowDikeTopAtPolder(DataRow x) { const string columnName = "InputPL1PLLineOffsetBelowDikeTopAtPolder"; DataSourceTypeSensors pl1OffsetBelowDikeTopAtPolder; try { pl1OffsetBelowDikeTopAtPolder = x.Field(columnName).ToEnumTypeIgnoreCase(); } catch (Exception) { throw; } return pl1OffsetBelowDikeTopAtPolder; } /// /// Gets the p l1 offset below shoulder base inside. /// /// The x. /// private static DataSourceTypeSensors GetPL1OffsetBelowShoulderBaseInside(DataRow x) { DataSourceTypeSensors pl1OffsetBelowShoulderBaseInside; try { pl1OffsetBelowShoulderBaseInside = x.Field("InputPL1PLLineOffsetBelowShoulderBaseInside").ToEnumTypeIgnoreCase(); } catch (Exception) { throw; } return pl1OffsetBelowShoulderBaseInside; } /// /// Gets the p l1 offset below dike toe at polder. /// /// The x. /// private static DataSourceTypeSensors GetPL1OffsetBelowDikeToeAtPolder(DataRow x) { DataSourceTypeSensors pl1OffsetBelowDikeToeAtPolder; try { pl1OffsetBelowDikeToeAtPolder = x.Field("InputPL1PLLineOffsetBelowDikeToeAtPolder").ToEnumTypeIgnoreCase(); } catch (Exception) { throw; } return pl1OffsetBelowDikeToeAtPolder; } /// /// Gets the type of the p l1 polder level sensor. /// /// The x. /// private static DataSourceTypeSensors GetPL1PolderLevelSensorType(DataRow x) { const string columnName = "InputPL1PolderLevel"; DataSourceTypeSensors pl1PolderLevelSensorType; try { pl1PolderLevelSensorType = x.Field(columnName).ToEnumTypeIgnoreCase(); } catch (Exception) { throw; } return pl1PolderLevelSensorType; } /// /// Gets the input PL4. /// /// The x. /// private static DataSourceTypeSensors GetInputPl4(DataRow x) { DataSourceTypeSensors dataSourceTypeSensors; try { dataSourceTypeSensors = x.Field("InputPL4").ToEnumTypeIgnoreCase(); } catch (Exception) { throw; } return dataSourceTypeSensors; } /// /// Gets the input PL3. /// /// The x. /// private static DataSourceTypeSensors GetInputPl3(DataRow x) { DataSourceTypeSensors pl3; try { pl3 = x.Field("InputPL3").ToEnumTypeIgnoreCase(); } catch (Exception) { throw; } return pl3; } /// /// Gets the name alias field. /// /// The x. /// /// nameAliasField private static string GetNameAliasField(DataRow x) { var nameAliasField = x.Field("NameAlias"); if (nameAliasField == null) { throw new ArgumentNullException("nameAliasField"); } return nameAliasField; } /// /// Gets the group identifier field. /// /// The x. /// /// Error parsing value : + x.Field(columnName) private static int GetGroupIDField(DataRow x) { int groupIdField; const string columnName = "SensorGroup"; try { groupIdField = (int)x.Field(columnName); } catch (InvalidCastException) { throw new InvalidCastException("Error parsing value : " + x.Field(columnName)); } catch (Exception) { throw; } return groupIdField; } /// /// Gets the location identifier field. /// /// The x. /// /// Error parsing value : + x.Field(columnName) + . LocationID should be a numeric value. private static int GetLocationIDField(DataRow x) { int locationIdField; const string columnName = "locationID"; try { locationIdField = (int)x.Field(columnName); } catch (InvalidCastException) { throw new InvalidCastException("Error parsing value : " + x.Field(columnName) + ". LocationID should be a numeric value."); } catch (Exception) { throw; } return locationIdField; } } }