Skip to content

Commit 80a7ff7

Browse files
committed
feat: implement BitcoinExchange class with file processing and validation
1 parent c8af50b commit 80a7ff7

File tree

1 file changed

+212
-0
lines changed

1 file changed

+212
-0
lines changed

ex00/BitcoinExchange.cpp

Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
#include "BitcoinExchange.hpp"
2+
3+
BitcoinExchange::BitcoinExchange(){}
4+
5+
BitcoinExchange::~BitcoinExchange(){}
6+
7+
BitcoinExchange::BitcoinExchange(const BitcoinExchange &other)
8+
{
9+
priceData = other.priceData;
10+
}
11+
12+
BitcoinExchange &BitcoinExchange::operator=(const BitcoinExchange &other)
13+
{
14+
if (this != &other)
15+
{
16+
priceData = other.priceData;
17+
}
18+
return *this;
19+
}
20+
void BitcoinExchange::processArgsAndFiles(int ac, char **av)
21+
{
22+
if (ac != 2) {
23+
throw FileOpenException();
24+
}
25+
loadDatabase("data.csv");
26+
processInputFile(av[1]);
27+
}
28+
29+
bool BitcoinExchange::loadDatabase(const std::string& filename)
30+
{
31+
std::ifstream file(filename.c_str());
32+
if (!file.is_open()) {
33+
throw FileOpenException();
34+
}
35+
36+
std::string line;
37+
getline(file, line);
38+
39+
while (getline(file, line))
40+
{
41+
std::stringstream ss(line);
42+
std::string date, priceStr;
43+
44+
if (!getline(ss, date, ',') || !getline(ss, priceStr)) {
45+
continue;
46+
}
47+
48+
trim(date);
49+
trim(priceStr);
50+
51+
if (!isValidDate(date)) {
52+
throw InvalidDateException();
53+
}
54+
55+
double price;
56+
std::stringstream priceStream(priceStr);
57+
priceStream >> price;
58+
59+
if (priceStream.fail()) {
60+
throw std::runtime_error("Error: Invalid price in database.");
61+
}
62+
priceData[date] = price;
63+
}
64+
65+
file.close();
66+
return true;
67+
}
68+
69+
void BitcoinExchange::processInputFile(const std::string& filename)
70+
{
71+
std::ifstream file(filename.c_str());
72+
if (!file.is_open())
73+
throw FileOpenException();
74+
75+
std::string line;
76+
getline(file, line);
77+
78+
while (getline(file, line))
79+
{
80+
if (!isValidFormat(line))
81+
{
82+
std::cerr << "Error: Bad input => " << line << std::endl;
83+
continue;
84+
}
85+
86+
std::stringstream ss(line);
87+
std::string date, valueStr;
88+
getline(ss, date, '|');
89+
getline(ss, valueStr);
90+
91+
trim(date);
92+
trim(valueStr);
93+
94+
try {
95+
if (!isValidDate(date))
96+
throw InvalidDateException();
97+
98+
if (!isValidValue(valueStr))
99+
throw InvalidValueException();
100+
101+
double value;
102+
std::stringstream valueStream(valueStr);
103+
valueStream >> value;
104+
105+
double rate = findClosestPrice(date);
106+
double result = value * rate;
107+
108+
std::cout << date << " => " << value << " = " << result << std::endl;
109+
} catch (const std::exception& e) {
110+
std::cerr << e.what() << std::endl;
111+
}
112+
}
113+
file.close();
114+
}
115+
116+
double BitcoinExchange::findClosestPrice(const std::string& date)
117+
{
118+
std::map<std::string, double>::iterator it = priceData.lower_bound(date);
119+
120+
if (it == priceData.end() || it->first != date)
121+
{
122+
if (it == priceData.begin())
123+
throw std::runtime_error("Error: No earlier data available.");
124+
--it;
125+
}
126+
return it->second;
127+
}
128+
129+
bool BitcoinExchange::isValidDate(const std::string& date)
130+
{
131+
if (date.size() != 10 || date[4] != '-' || date[7] != '-')
132+
return false;
133+
134+
int year, month, day;
135+
char dash1, dash2;
136+
std::stringstream ss(date);
137+
ss >> year >> dash1 >> month >> dash2 >> day;
138+
139+
if (ss.fail() || dash1 != '-' || dash2 != '-') {
140+
return false;
141+
}
142+
143+
if (month < 1 || month > 12 || day < 1 || day > 31) {
144+
return false;
145+
}
146+
147+
if ((month == 4 || month == 6 || month == 9 || month == 11) && day > 30) {
148+
return false;
149+
}
150+
151+
if (month == 2)
152+
{
153+
if (isLeapYear(year) && day > 29)
154+
return false;
155+
if (!isLeapYear(year) && day > 28)
156+
return false;
157+
}
158+
return true;
159+
}
160+
161+
bool BitcoinExchange::isLeapYear(int year)
162+
{
163+
return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
164+
}
165+
166+
bool BitcoinExchange::isValidValue(const std::string& value)
167+
{
168+
double val;
169+
std::stringstream ss(value);
170+
ss >> val;
171+
172+
if (ss.fail() || val < 0 || val > 1000) {
173+
return false;
174+
}
175+
return true;
176+
}
177+
178+
bool BitcoinExchange::isValidFormat(const std::string& line)
179+
{
180+
size_t pos = line.find('|');
181+
if (pos == std::string::npos)
182+
return false;
183+
184+
std::string date = line.substr(0, pos);
185+
std::string value = line.substr(pos + 1);
186+
187+
trim(date);
188+
trim(value);
189+
190+
if (date.empty() || value.empty())
191+
return false;
192+
return true;
193+
}
194+
195+
void BitcoinExchange::trim(std::string& str)
196+
{
197+
size_t first = str.find_first_not_of(" \t");
198+
size_t last = str.find_last_not_of(" \t");
199+
200+
if (first == std::string::npos || last == std::string::npos)
201+
str = "";
202+
else
203+
str = str.substr(first, last - first + 1);
204+
}
205+
206+
bool BitcoinExchange::isDigitsOnly(const std::string& str)
207+
{
208+
for (size_t i = 0; i < str.length(); i++) {
209+
if (!isdigit(str[i])) return false;
210+
}
211+
return true;
212+
}

0 commit comments

Comments
 (0)