/********************************************************************************************** @author Ben Friedland @version 1.0 Name of the File : Program.cs Creation/Modification History : 17-APR-2007 Created This is the interface for extracting data from Tracy Fire and writing it out to a fixed format, fixed length file. ********************************************************************************************* */ using System; using System.Collections.Generic; using System.Text; using System.Data.SqlClient; using System.IO; using System.Xml; namespace TestGrounds { class Program { private static XmlDocument xdoc; private static string masterIncidentNum; static void Main(string[] args) { XmlNode definitionNode; string connStr = Properties.Settings.Default.Connection; string incidentID = "185627"; string sql = "SELECT TOP 1 i.*, v.Response_Number " + "FROM Response_Master_Incident i " + "LEFT JOIN Response_Vehicles_Assigned v ON " + "i.ID = v.Master_Incident_ID " + "WHERE i.ID = @incidentID\r\n " + "SELECT TOP 100 * FROM Response_Comments " + "WHERE Master_Incident_ID = @incidentID\r\n " + "SELECT TOP 10 * FROM Response_Transports " + "WHERE Master_Incident_ID = @incidentID\r\n " + "SELECT * FROM Response_Vehicles_Assigned rva " + "LEFT JOIN Response_Vehicles_Personnel rvp ON " + "rva.ID = rvp.Veh_Assigned_ID " + "LEFT JOIN Response_Transports rt ON " + "rva.ID = rt.Vehicle_Assigned_ID " + "WHERE rva.Master_Incident_ID = @incidentID\r\n"; /** OPEN DB **/ SqlConnection conn = new SqlConnection(connStr); conn.Open(); SqlCommand cmd = new SqlCommand(sql, conn); cmd.Parameters.Add(new SqlParameter("incidentID", incidentID)); SqlDataReader dr = cmd.ExecuteReader(); /** START INC01 FILE **/ string outFile = "c:\\IncOutput\\INC01.txt"; File.Delete(outFile); FileStream fs = new FileStream(outFile, FileMode.CreateNew); StreamWriter sw = new StreamWriter(fs); /** WRITE HEADER (INC01) **/ sw.Write(GetHeader("INC01")); /** BEGIN MASTER INCIDENT **/ definitionNode = GetDefinitionNode("Response_Master_Incident"); OutputSection(dr, definitionNode, sw, 1); /** BEGIN COMMENTS **/ dr.NextResult(); definitionNode = GetDefinitionNode("Response_Comments"); int repeatCount = int.Parse(definitionNode.Attributes["Count"].Value); OutputSection(dr, definitionNode, sw, repeatCount); /** BEGIN TRANSPORTS **/ dr.NextResult(); definitionNode = GetDefinitionNode("Response_Transports"); repeatCount = int.Parse(definitionNode.Attributes["Count"].Value); OutputSection(dr, definitionNode, sw, repeatCount); /** COURTESY FLUSH **/ sw.Flush(); /** CLOSE FILE **/ sw.Write(GetChar(CharCodes.ETX)); sw.Flush(); sw.Close(); fs.Close(); sw.Dispose(); fs.Dispose(); /** = = = = = = = = = = = = = = = = = = = = = = = **/ /** START INC02 FILE **/ outFile = "c:\\IncOutput\\INC02.txt"; File.Delete(outFile); fs = new FileStream(outFile, FileMode.CreateNew); sw = new StreamWriter(fs); /** WRITE HEADER (INC02) **/ sw.Write(GetHeader("INC02")); /** WRITE AGENCY IDENTIFIER AND INCIDENT NUMBER **/ //TODO: agency identifier sw.Write("??" + GetChar(CharCodes.FS)); sw.Write(masterIncidentNum + GetChar(CharCodes.FS)); /** BEGIN VEHICLES ASSIGNED **/ dr.NextResult(); definitionNode = GetDefinitionNode("Response_Vehicles_Assigned"); OutputSection(dr, definitionNode, sw, 0); /** COURTESY FLUSH **/ sw.Flush(); /** CLOSE FILE **/ sw.Write(GetChar(CharCodes.ETX)); sw.Flush(); sw.Close(); fs.Close(); sw.Dispose(); fs.Dispose(); /** CLOSE DATABASE */ dr.Close(); dr.Dispose(); cmd.Dispose(); conn.Close(); conn.Dispose(); } /// /// Returns a XMLNode containing the definiton of the specified table as /// specified in the FieldDefinitions.xml file. /// /// A string containing the table name for which /// to retrieve the definition. /// A XMLNode containing the definition of the specified /// table. private static XmlNode GetDefinitionNode(string p) { if (xdoc == null) { xdoc = new XmlDocument(); xdoc.InnerXml = File.ReadAllText("FieldDefinitions.xml"); } return xdoc.DocumentElement.SelectSingleNode( "TableDefinition[@Name='"+p+"']"); } /// /// Outputs a section of the data stream. /// /// The DataReader, containing the data to output. /// The data definition XMLNode. /// The StreamWriter to write to. /// The number of times to repeat (or fluff). A /// value of zero (0) means these records are not fixed length, and should /// be repeated for all results - and not padded. private static void OutputSection(SqlDataReader dr, XmlNode defNode, StreamWriter sw, int repeatCount) { int i = 0; while (dr.Read()) { i++; foreach (XmlNode fieldNode in defNode) { // skip comments, etc. if (fieldNode.Name != "Field") continue; string fieldName = fieldNode.Attributes["Name"].Value; int fieldLen = int.Parse(fieldNode.Attributes["Length"].Value); // PERSONNEL: I have to do this ridiculousness for the personnel // subquery if (fieldName == "Personnel") { string personnelFields = GetPersonnel((int)dr["ID"]); sw.Write(personnelFields); continue; } // store master incident number if (fieldName == "Master_Incident_Number") { masterIncidentNum = dr[fieldName].ToString(); } string val = FormatValue(dr[fieldName], fieldLen); sw.Write(val); } } // For non-fixed-length records, just return. No padding necessary. if (repeatCount == 0) return; // if there were fewer records returned than repeatCount, and these // records are fixed-length, we need to add white space to fill // in the rest. if (i < repeatCount) { // determine the record length int recLen = 0; foreach (XmlNode fieldNode in defNode) { recLen += int.Parse(fieldNode.Attributes["Length"].Value); } // fluff with spaces for records that weren't written int fluffLen = recLen * (repeatCount - i); sw.Write("".PadRight(fluffLen, ' ')); } } /// /// Returns the top 6 personnel records for the specified Veh_Assigned_ID /// separated by a FS /// private static string GetPersonnel(int vehAssID) { string connStr = Properties.Settings.Default.Connection; string sql = "SELECT TOP 6 Personnel_Table_ID " + "FROM Response_Vehicles_Personnel " + "WHERE Veh_Assigned_ID = @vehAssID"; /** OPEN DB **/ SqlConnection conn = new SqlConnection(connStr); conn.Open(); SqlCommand cmd = new SqlCommand(sql, conn); cmd.Parameters.Add(new SqlParameter("vehAssID", vehAssID)); SqlDataReader dr = cmd.ExecuteReader(); string ret = ""; for (int i = 0; i < 6; i++) { if (dr.Read()) { ret += dr[0].ToString(); } ret+=GetChar(CharCodes.FS); } /** CLOSE DATABASE */ dr.Close(); dr.Dispose(); cmd.Dispose(); conn.Close(); conn.Dispose(); return ret; } /// /// Formats a value, adding padding or truncating values to match /// fieldLen. Also formats dates and converts bools to 1/0. /// /// Object to format. /// Length to pad/truncate. /// If zero (0), appends a FS to the return val. /// A string, formatted and padded or truncated. private static string FormatValue(object val, int fieldLen) { string ret = val.ToString(); // DateTime if (val is DateTime) { DateTime d = (DateTime)val; if (fieldLen > 0) { ret = d.ToString("MM/dd/yyHH:mm:ss"); } else { ret = d.ToString("MM/dd/yy" + GetChar(CharCodes.FS) + "HH:mm:ss" + GetChar(CharCodes.FS)); } return ret; } // Boolean if (val is Boolean) { ret = ((bool)val)?"1":"0"; if (fieldLen > 0) { ret += GetChar(CharCodes.FS); } return ret; } // String if (fieldLen > 0) { // for fixed width fields, trim or pad them ret = ret.PadRight(fieldLen, ' '); // pad if (ret.Length > fieldLen) ret = ret.Substring(0, fieldLen); // trim } else { // non-fixed-width: just append a field separator ret = ret + GetChar(CharCodes.FS); } return ret; } private static string FormatValue(object val) { return FormatValue(val, 0); } static string GetHeader(string msgType) { string dateString = FormatValue(DateTime.Now, 16); return GetChar(CharCodes.SOH) + msgType + GetChar(CharCodes.FS) + // message type "1.0" + GetChar(CharCodes.FS) + // message format version dateString + GetChar(CharCodes.FS) + // date/time stamp "0" + GetChar(CharCodes.FS) + // supress reply flag GetChar(CharCodes.FS) + // group quantity GetChar(CharCodes.FS) + // originating id GetChar(CharCodes.FS) + // vendor use GetChar(CharCodes.FS) + // reserved GetChar(CharCodes.FS) + // reserved GetChar(CharCodes.STX); // reserved } /// /// Returns a char corresponding to the specified CharCode /// /// /// static char GetChar(CharCodes code) { return Convert.ToChar((int)code); } /// /// An enumeration of character codes, and their ASCII decimal value. /// enum CharCodes { /// /// Start of Header /// SOH = 1, /// /// Start of Text /// STX = 2, /// /// End of Text /// ETX = 3, /// /// Line Feed /// LF = 10, /// /// Carriage Return /// CR = 13, /// /// Field Separator /// FS = 28 } } }