readtest/source/app.d

260 lines
7.6 KiB
D
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import singlog;
import core.stdc.stdlib : exit, EXIT_SUCCESS, EXIT_FAILURE;
import std.stdio, std.conv, std.path, std.file, std.format, std.regex, std.array, std.algorithm, std.uuid;
import source.database;
import source.sql;
enum {
GROUP_THEME = 2,
GROUP_THEME_TEXT = 5,
GROUP_QUESTION = 7,
GROUP_QUESTION_TEXT = 10,
GROUP_ANSWER = 12,
GROUP_ANSWER_TEXT = 15,
GROUP_ANSWER_RIGHT = 17,
GROUP_ANSWER_RIGHT_TEXT = 20,
GROUP_IMAGE = 22,
GROUP_IMAGE_NAME = 25,
}
int main(string[] args)
{
log.level(log.level.debugging)
.output(log.output.stdout.stderr)
.color(true);
const string pictures = "./images";
string testFilePath;
string databaseFile;
if (args.length != 3) {
log.e("Не было передано необходимое количество параметров для запуска программы");
return EXIT_FAILURE;
}
databaseFile = args[1];
testFilePath = args[2];
const string pattern = "^((( |\\t)*\\#( |\\t)*)(.*[^\\s]))|((( |\\t)*\\?( |\\t)*)(.*[^\\s]))"
~ "|((( |\\t)*-( |\\t)*)(.*[^\\s]))|((( |\\t)*\\+( |\\t)*)(.*[^\\s]))|((( |\\t)*\\*( |\\t)*)(.*[^\\s]))$";
File testFile;
try {
testFile = File(testFilePath, "r");
} catch (Exception e) {
log.w("Unable to open the test file " ~ testFilePath);
log.e(e);
return EXIT_FAILURE;
}
dbliteConnect(databaseFile);
auto regular = regex(pattern, "m");
struct Answer {
int number;
string text;
bool truth;
bool addToDB(int question_id) {
int id = sqlAddNewAnswer(question_id, this.number, this.text, this.truth);
if (!id)
return false;
return true;
}
}
struct Question {
int number;
string text;
Answer[int] answers;
bool hasPicture;
ubyte[] picture;
string pictureName;
int pictureSize;
ulong count() {
return answers.length;
}
bool isValid() {
bool error = false;
if (answers.length <= 1)
error = true;
if (hasPicture && pictureSize > 256)
error = true;
return !error;
}
bool addToDB(int topic_id) {
int id = sqlAddNewQuestion(
topic_id,
this.number,
this.text,
this.hasPicture,
this.picture,
this.pictureName);
if (!id)
return false;
foreach (answer; answers.byKeyValue.array.sort!((a, b) => a.key < b.key)) {
if (!answer.value.addToDB(id))
return false;
}
return true;
}
}
struct Theme {
string text;
Question[int] questions;
ulong count() {
return questions.length;
}
bool isValid() {
return questions.length > 1;
}
bool addToDB() {
if (!check())
return false;
int id = sqlAddNewTheme(this.text);
if (!id)
return false;
foreach (question; this.questions.byKeyValue.array.sort!((a, b) => a.key < b.key)) {
if (!question.value.addToDB(id))
return false;
}
return true;
}
void print() {
writeln("Количество вопросов: %s".format(this.count()));
foreach (question; this.questions.byKeyValue.array.sort!((a, b) => a.key < b.key)) {
writeln("\tВопрос №%d: %s".format(question.key, question.value.text));
if (question.value.hasPicture)
writeln("\tСодержит изображение: %s (%d kB)"
.format(question.value.pictureName, question.value.pictureSize));
writeln("\tКоличество ответов: %d".format(question.value.count()));
foreach (answer; question.value.answers.byKeyValue.array.sort!((a, b) => a.key < b.key)) {
writeln("\t\tОтвет №%d: %s".format(answer.key, answer.value.text));
}
}
}
bool check() {
bool error = false;
if (!this.isValid()) {
writeln("Недостаточное количество вопросов: %d".format(this.count()));
error = true;
}
if (!error) {
foreach (question; this.questions.byKeyValue.array.sort!((a, b) => a.key < b.key)) {
if (!question.value.isValid()) {
writeln("Вопрос №%d \"%s\" содержит недостаточное количество ответов (%d) или большой (> 256 kB) размер изображения (%d kB)"
.format(question.key, question.value.text, question.value.count(), question.value.pictureSize));
error = true;
}
int truth;
foreach (answer; question.value.answers) {
if (answer.truth)
++truth;
}
if (truth > 1) {
writeln("Вопрос №%d \"%s\" содержит более одного правильного ответа".format(
question.key, question.value.text
));
error = true;
}
}
}
return !error;
}
}
Theme theme;
int numQuestion;
int numAnswer;
while (!testFile.eof())
{
string line = testFile.readln();
auto match = matchFirst(line, regular);
if (match.length == 0)
continue;
if (match[GROUP_THEME].length)
{
theme.text = match[GROUP_THEME_TEXT];
continue;
}
if (match[GROUP_QUESTION].length)
{
numAnswer = 0;
theme.questions[++numQuestion] = Question(numQuestion, match[GROUP_QUESTION_TEXT]);
continue;
}
if (match[GROUP_ANSWER].length)
{
theme.questions[numQuestion].answers[++numAnswer] = Answer(numAnswer, match[GROUP_ANSWER_TEXT], false);
continue;
}
if (match[GROUP_ANSWER_RIGHT].length)
{
theme.questions[numQuestion].answers[++numAnswer] = Answer(numAnswer, match[GROUP_ANSWER_RIGHT_TEXT], true);
continue;
}
if (match[GROUP_IMAGE].length)
{
string currentPicture = buildPath(pictures, match[GROUP_IMAGE_NAME]);
if (currentPicture.exists) {
auto picFile = File(currentPicture, "r");
theme.questions[numQuestion].hasPicture = true;
theme.questions[numQuestion].picture = cast(ubyte[])read(currentPicture);
theme.questions[numQuestion].pictureName =
md5UUID(theme.questions[numQuestion].picture).to!string ~ currentPicture.extension;
theme.questions[numQuestion].pictureSize = picFile.size().to!int / 1024;
} else {
log.e("Файл \"%s\" не найден".format(currentPicture));
}
continue;
}
}
// theme.print();
// theme.check();
theme.addToDB();
return EXIT_SUCCESS;
}