Icarus
Vehicle Simulation as a Transformable Computational Graph, built on Vulcan and Janus
Loading...
Searching...
No Matches
FlightManifest.hpp
Go to the documentation of this file.
1#pragma once
2
10
15
16#include <chrono>
17#include <ctime>
18#include <filesystem>
19#include <fstream>
20#include <iomanip>
21#include <iostream>
22#include <map>
23#include <sstream>
24#include <string>
25
26namespace icarus {
27
39 public:
40 explicit FlightManifest(const Console &console) : console_(console) {}
41
42 // === Configuration ===
43
45 void SetOutputPath(const std::filesystem::path &path) { output_path_ = path; }
46
48 void SetVersion(const std::string &version) { version_ = version; }
49
51 void SetConfigSource(const std::string &component, const std::string &source) {
52 config_sources_[component] = source;
53 }
54
56 void SetFullConsoleOutput(bool enabled) { full_console_ = enabled; }
57
58 // === Generation ===
59
61 void Generate(const DataDictionary &dict) {
62 WriteToFile(dict);
63 PrintSummary(dict);
64 }
65
67 [[nodiscard]] std::string GenerateFull(const DataDictionary &dict) const {
68 std::ostringstream oss;
69
70 // Header
71 oss << GenerateHeader();
72 oss << "\n\n";
73
74 // System summary
75 oss << "[ SYSTEM SUMMARY ]\n";
76 oss << " Total Components: " << std::setw(4) << dict.components.size()
77 << " Total Outputs: " << dict.total_outputs << "\n";
78 oss << " Total Inputs: " << std::setw(4) << dict.total_inputs
79 << " Total Params: " << dict.total_parameters << "\n";
80 oss << " Integrable States: " << std::setw(3) << dict.integrable_states
81 << " Config Values: " << dict.total_config << "\n";
82 oss << "\n";
83
84 // Component sections
85 for (const auto &comp : dict.components) {
86 oss << GenerateComponentSection(comp);
87 oss << "\n";
88 }
89
90 return oss.str();
91 }
92
94 [[nodiscard]] std::string GenerateSummary(const DataDictionary &dict) const {
95 std::ostringstream oss;
96
97 oss << Banner::GetSectionHeader("FLIGHT MANIFEST") << "\n";
98 oss << "Signal Dictionary written to: " << output_path_.string() << "\n\n";
99
100 oss << " Components: " << std::setw(4) << dict.components.size()
101 << " Outputs: " << std::setw(4) << dict.total_outputs << "\n";
102 oss << " Inputs: " << std::setw(4) << dict.total_inputs
103 << " Parameters: " << std::setw(4) << dict.total_parameters << "\n";
104 oss << " States: " << std::setw(4) << dict.integrable_states
105 << " Config: " << std::setw(4) << dict.total_config << "\n";
106
107 // Unwired inputs warning
108 if (dict.unwired_inputs > 0) {
109 oss << "\n ⚠ Unwired inputs: " << dict.unwired_inputs << "\n";
110 for (const auto &comp : dict.components) {
111 for (const auto &input : comp.inputs) {
112 if (input.wired_to.empty()) {
113 oss << " - " << comp.name << "." << input.name << "\n";
114 }
115 }
116 }
117 }
118
119 oss << "\nSee " << output_path_.string() << " for full signal listing.\n";
120 oss << std::string(80, '-') << "\n";
121
122 return oss.str();
123 }
124
126 void WriteToFile(const DataDictionary &dict) const {
127 std::ofstream file(output_path_);
128 if (!file.is_open()) {
129 std::cerr << "[ERR] Failed to write manifest to: " << output_path_ << "\n";
130 return;
131 }
132 file << GenerateFull(dict);
133 file.close();
134 }
135
137 void PrintSummary(const DataDictionary &dict) const {
138 std::string summary = GenerateSummary(dict);
139 if (console_.IsColorEnabled()) {
140 // Colorize warnings (⚠ Unwired inputs) in yellow
141 const std::string warning_marker = "⚠ Unwired";
142 std::size_t pos = summary.find(warning_marker);
143 if (pos != std::string::npos) {
144 // Find the end of the warning section (next blank line or end)
145 std::size_t end_pos = summary.find("\n\nSee ", pos);
146 if (end_pos == std::string::npos) {
147 end_pos = summary.length();
148 }
149 // Insert ANSI yellow before warning, reset after
150 std::string colored = summary.substr(0, pos);
151 colored += console_.Colorize(summary.substr(pos, end_pos - pos), AnsiColor::Yellow);
152 colored += summary.substr(end_pos);
153 std::cout << colored;
154 } else {
155 std::cout << summary;
156 }
157 } else {
158 std::cout << summary;
159 }
160 }
161
163 void PrintFull(const DataDictionary &dict) const { std::cout << GenerateFull(dict); }
164
165 private:
166 const Console &console_;
167 std::filesystem::path output_path_ = "signal_dictionary.dict";
168 std::string version_ = icarus::Version();
169 std::map<std::string, std::string> config_sources_;
170 bool full_console_ = false;
171
172 [[nodiscard]] std::string GenerateHeader() const {
173 std::ostringstream oss;
174
175 // Get current time
176 auto now = std::chrono::system_clock::now();
177 auto time_t = std::chrono::system_clock::to_time_t(now);
178 std::tm tm_buf{};
179#ifdef _WIN32
180 localtime_s(&tm_buf, &time_t);
181#else
182 localtime_r(&time_t, &tm_buf);
183#endif
184
185 oss << Banner::GetRule(80) << "\n";
186 oss << " ICARUS SIMULATION ENGINE | DATA DICTIONARY\n";
187 oss << " Generated: " << std::put_time(&tm_buf, "%Y-%m-%d %H:%M:%S");
188 oss << " | Ver: " << version_ << "\n";
189 oss << Banner::GetRule(80);
190
191 return oss.str();
192 }
193
194 [[nodiscard]] std::string
195 GenerateComponentSection(const DataDictionary::ComponentEntry &comp) const {
196 std::ostringstream oss;
197
198 oss << std::string(80, '-') << "\n";
199 oss << "COMPONENT: " << comp.name << "\n";
200 oss << " Type: " << comp.type << "\n";
201
202 auto it = config_sources_.find(comp.name);
203 if (it != config_sources_.end()) {
204 oss << " Source: " << it->second << "\n";
205 }
206
207 oss << std::string(80, '-') << "\n";
208
209 if (!comp.outputs.empty()) {
210 oss << GenerateSignalTable("OUTPUTS", comp.outputs);
211 }
212 if (!comp.inputs.empty()) {
213 oss << GenerateSignalTable("INPUTS", comp.inputs);
214 }
215 if (!comp.parameters.empty()) {
216 oss << GenerateSignalTable("PARAMETERS", comp.parameters);
217 }
218 if (!comp.config.empty()) {
219 oss << GenerateSignalTable("CONFIG", comp.config);
220 }
221
222 return oss.str();
223 }
224
225 [[nodiscard]] std::string
226 GenerateSignalTable(const std::string &title,
227 const std::vector<SignalDescriptor> &signals) const {
228 std::ostringstream oss;
229
230 oss << " [" << title << "]\n";
231
232 AsciiTable table;
233 table.AddColumn("SIGNAL NAME", 40);
234 table.AddColumn("UNIT", 12);
235 table.AddColumn("DESCRIPTION", 80);
236
237 for (const auto &sig : signals) {
238 table.AddRow({sig.name, sig.unit, sig.description});
239 }
240
241 // Indent the table
242 std::istringstream iss(table.Render());
243 std::string line;
244 while (std::getline(iss, line)) {
245 oss << " " << line << "\n";
246 }
247
248 return oss.str();
249 }
250};
251
252} // namespace icarus
ASCII table generator with box-drawing characters.
ASCII art banners and headers.
Console abstraction with ANSI color support.
Complete catalog of simulation interface.
static std::string GetSectionHeader(const std::string &title)
Get section header (for data dictionary, etc.).
Definition Banner.hpp:57
static std::string GetRule(int width=80, char c='=')
Get horizontal rule.
Definition Banner.hpp:43
Console output with color and formatting support.
Definition Console.hpp:111
std::string GenerateSummary(const DataDictionary &dict) const
Generate summary string (for console).
Definition FlightManifest.hpp:94
void SetFullConsoleOutput(bool enabled)
Enable/disable full console output (default: false, summary only).
Definition FlightManifest.hpp:56
void PrintSummary(const DataDictionary &dict) const
Print summary to console (default behavior).
Definition FlightManifest.hpp:137
void PrintFull(const DataDictionary &dict) const
Print full manifest to console (opt-in, use sparingly).
Definition FlightManifest.hpp:163
void SetConfigSource(const std::string &component, const std::string &source)
Set config source for a component.
Definition FlightManifest.hpp:51
void WriteToFile(const DataDictionary &dict) const
Write full manifest to file.
Definition FlightManifest.hpp:126
std::string GenerateFull(const DataDictionary &dict) const
Generate full manifest string (for file or explicit request).
Definition FlightManifest.hpp:67
void SetVersion(const std::string &version)
Set simulation version string.
Definition FlightManifest.hpp:48
void SetOutputPath(const std::filesystem::path &path)
Set output file path (default: "signal_dictionary.dict").
Definition FlightManifest.hpp:45
FlightManifest(const Console &console)
Definition FlightManifest.hpp:40
void Generate(const DataDictionary &dict)
Generate manifest: write full to file, summary to console.
Definition FlightManifest.hpp:61
Definition AggregationTypes.hpp:13
constexpr const char * Version()
Version string (derived from components).
Definition CoreTypes.hpp:152
static constexpr const char * Yellow
Definition Console.hpp:60
Complete catalog of simulation interface.
Definition DataDictionary.hpp:45
std::size_t total_parameters
Definition DataDictionary.hpp:65
std::size_t total_inputs
Definition DataDictionary.hpp:64
std::vector< ComponentEntry > components
All registered components.
Definition DataDictionary.hpp:60
std::size_t total_outputs
Definition DataDictionary.hpp:63
std::size_t integrable_states
Definition DataDictionary.hpp:67
std::size_t total_config
Definition DataDictionary.hpp:66
std::size_t unwired_inputs
Definition DataDictionary.hpp:68