217 lines
6.9 KiB
C
217 lines
6.9 KiB
C
#include "sqlite_ex.h"
|
|
|
|
static char date_string[STR_SIZE];
|
|
static meas *measurements;
|
|
static int meas_count;
|
|
static Datetime twnth_day;
|
|
static Cost costs;
|
|
static char *zErrMsg = NULL;
|
|
static sqlite3 *db;
|
|
|
|
int main(int argc, char **argv) {
|
|
int respCode;
|
|
if ((respCode = sqlite3_open("communal.db", &db))) {
|
|
fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
|
|
sqlite3_close(db);
|
|
return 1;
|
|
}
|
|
|
|
if (argc == 2) {
|
|
if (!strcmp(argv[1], "-t")) {
|
|
sqlite_list_tables(db);
|
|
} else if (!strcmp(argv[1], "-i")) {
|
|
char *ms[] = {"gas", "water", "electricity"};
|
|
float ms_num[] = {0, 0, 0};
|
|
|
|
for (int i = 0; i < 3; ++i) {
|
|
printf("Enter %s measurement: ", ms[i]);
|
|
scanf("%f", &ms_num[i]);
|
|
}
|
|
|
|
sqlite3_stmt *st;
|
|
respCode = sqlite3_prepare_v2(db, INSERT_MEASUREMENT, -1, &st, NULL);
|
|
if (respCode != SQLITE_OK) {
|
|
fprintf(stderr, "Prepared statement error: %d\n", respCode);
|
|
}
|
|
sqlite3_bind_double(st, 1, ms_num[0]);
|
|
sqlite3_bind_double(st, 2, ms_num[1]);
|
|
sqlite3_bind_double(st, 3, ms_num[2]);
|
|
respCode = sqlite3_step(st);
|
|
if (respCode != SQLITE_DONE) {
|
|
fprintf(stderr, "Error while executing statement: %d", respCode);
|
|
}
|
|
|
|
respCode = sqlite3_finalize(st);
|
|
if (respCode != SQLITE_OK) {
|
|
fprintf(stderr, "Prepared statement finalization error: %d\n",
|
|
respCode);
|
|
sqlite3_free(zErrMsg);
|
|
}
|
|
}
|
|
} else {
|
|
sqlite_exec_query(SELECT_COUNT_MEAS, count_measurements);
|
|
measurements = malloc(sizeof(meas) * meas_count);
|
|
|
|
sqlite_exec_query(SELECT_MEASUREMENTS, parse_measurements);
|
|
measurements -= meas_count; // bring it back to the start of array
|
|
|
|
sqlite_exec_query(SELECT_TWNTH_DAY, select_twnth_day);
|
|
|
|
sqlite3_stmt *st;
|
|
respCode = sqlite3_prepare_v2(db, SELECT_CURRENT_COSTS, -1, &st, NULL);
|
|
if (respCode != SQLITE_OK) {
|
|
fprintf(stderr, "Prepared statement error: %d\n", respCode);
|
|
}
|
|
sqlite3_bind_int(st, 1, measurements[meas_count - 1].cost_id);
|
|
respCode = sqlite3_step(st);
|
|
if (respCode == SQLITE_ROW) {
|
|
int n_cols = sqlite3_column_count(st);
|
|
for (int col_ind = 0; col_ind < n_cols; ++col_ind) {
|
|
const char *col_name = sqlite3_column_name(st, col_ind);
|
|
if (!strcmp(col_name, "gas_cost")) {
|
|
costs.gas_c = sqlite3_column_double(st, col_ind);
|
|
} else if (!strcmp(col_name, "water_cost")) {
|
|
costs.water_c = sqlite3_column_double(st, col_ind);
|
|
} else if (!strcmp(col_name, "electricity_cost")) {
|
|
costs.electricity_c = sqlite3_column_double(st, col_ind);
|
|
} else if (!strcmp(col_name, "other_cost")) {
|
|
costs.housing_c = sqlite3_column_double(st, col_ind);
|
|
}
|
|
}
|
|
}
|
|
respCode = sqlite3_finalize(st);
|
|
if (respCode != SQLITE_OK) {
|
|
fprintf(stderr, "Prepared statement finalization error: %d\n", respCode);
|
|
sqlite3_free(zErrMsg);
|
|
}
|
|
|
|
print_measurements();
|
|
|
|
for (int i = meas_count - 1; i >= 0; --i) {
|
|
Datetime *dt = measurements[i].datetime;
|
|
if (dates_same(dt, &twnth_day)) {
|
|
if (i == meas_count - 1) {
|
|
printf("No measurements were made since last time!\n");
|
|
goto free;
|
|
}
|
|
double total = communal_difference(&measurements[meas_count - 1],
|
|
&measurements[i]);
|
|
strftime(date_string, STR_SIZE, "%x",
|
|
measurements[meas_count - 1].datetime);
|
|
printf("date of last measurement: %s\n", date_string);
|
|
printf("total: %f\n", total);
|
|
}
|
|
}
|
|
|
|
free:
|
|
free_measurements();
|
|
}
|
|
|
|
sqlite3_close(db);
|
|
return 0;
|
|
}
|
|
|
|
void sqlite_exec_query(char *query, void *callback) {
|
|
int respCode = sqlite3_exec(db, query, callback, 0, &zErrMsg);
|
|
if (respCode != SQLITE_OK) {
|
|
fprintf(stderr, "SQL error: %s\n", zErrMsg);
|
|
sqlite3_free(zErrMsg);
|
|
}
|
|
}
|
|
|
|
int count_measurements(void *_, int n_cols, char **row_vals, char **cols) {
|
|
meas_count = atoi(row_vals[0]);
|
|
return 0;
|
|
}
|
|
|
|
int parse_measurements(void *_, int n_cols, char **row_vals, char **cols) {
|
|
meas measurement;
|
|
|
|
for (int col = 0; col < n_cols; ++col) {
|
|
if (!strcmp(cols[col], "gas")) {
|
|
measurement.gas = atof(row_vals[col]);
|
|
} else if (!strcmp(cols[col], "water")) {
|
|
measurement.water = atof(row_vals[col]);
|
|
} else if (!strcmp(cols[col], "electricity")) {
|
|
measurement.electricity = atof(row_vals[col]);
|
|
} else if (!strcmp(cols[col], "date")) {
|
|
Datetime *dt = malloc(sizeof(Datetime));
|
|
strptime(row_vals[col], "%F", dt);
|
|
measurement.datetime = dt;
|
|
} else if (!strcmp(cols[col], "costs")) {
|
|
measurement.cost_id = atoi(row_vals[col]);
|
|
}
|
|
}
|
|
*measurements++ = measurement;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void sqlite_list_tables(sqlite3 *db) {
|
|
char *errMsg = NULL;
|
|
int respCode = sqlite3_exec(db, SELECT_ALL_TABLES, print_tables, 0, &errMsg);
|
|
if (respCode != SQLITE_OK) {
|
|
fprintf(stderr, "SQL error: %s\n", errMsg);
|
|
sqlite3_free(errMsg);
|
|
}
|
|
}
|
|
|
|
int print_tables(void *_, int rows_n, char **rows, char **cols) {
|
|
for (int i = 0; i < rows_n; ++i) {
|
|
printf("%s = %s\n", cols[i], rows[i] ? rows[i] : "NULL");
|
|
}
|
|
printf("\n");
|
|
return 0;
|
|
}
|
|
|
|
int select_twnth_day(void *_, int n_cols, char **row_vals, char **cols) {
|
|
strptime(row_vals[0], "%F", &twnth_day);
|
|
return 0;
|
|
}
|
|
|
|
int dates_same(Datetime *dt1, Datetime *dt2) {
|
|
return dt1->tm_year == dt2->tm_year && dt1->tm_mon == dt2->tm_mon &&
|
|
dt1->tm_mday == dt2->tm_mday;
|
|
}
|
|
|
|
double communal_difference(meas *m_now, meas *m_twnth) {
|
|
double gas_diff = (int)m_now->gas - (int)m_twnth->gas;
|
|
double water_diff = (int)m_now->water - (int)m_twnth->water;
|
|
double electricity_diff = (int)m_now->electricity - (int)m_twnth->electricity;
|
|
|
|
double gas_total = gas_diff * costs.gas_c;
|
|
double water_total = water_diff * costs.water_c;
|
|
double electricity_total = electricity_diff * costs.electricity_c;
|
|
|
|
printf(CALCULATION_FORMAT, "gas", (int)m_now->gas, (int)m_twnth->gas,
|
|
gas_diff, costs.gas_c, gas_total);
|
|
printf(CALCULATION_FORMAT, "water", (int)m_now->water, (int)m_twnth->water,
|
|
water_diff, costs.water_c, water_total);
|
|
printf(CALCULATION_FORMAT "\n", "electricity", (int)m_now->electricity,
|
|
(int)m_twnth->electricity, electricity_diff, costs.electricity_c,
|
|
electricity_total);
|
|
|
|
double grand_total =
|
|
gas_total + water_total + electricity_total + costs.housing_c;
|
|
printf("%.2f + %.2f + %.2f + %.2f = %.2f\n", gas_total, water_total,
|
|
electricity_total, costs.housing_c, grand_total);
|
|
|
|
return grand_total;
|
|
}
|
|
|
|
void print_measurements() {
|
|
for (int i = 0; i < meas_count; ++i) {
|
|
meas m = measurements[i];
|
|
strftime(date_string, STR_SIZE, "%x", m.datetime);
|
|
printf("%-15s%11s\n%-15s%11f\n%-15s%11f\n%-15s%11f\n\n",
|
|
"date:", date_string, "gas:", m.gas, "water:", m.water,
|
|
"electricity:", m.electricity);
|
|
}
|
|
}
|
|
|
|
void free_measurements() {
|
|
for (int i = 0; i < meas_count; ++i)
|
|
free(measurements[i].datetime);
|
|
free(measurements);
|
|
}
|