Add rtest and rrecite function to test reversely
[FreeRecite.git] / src / ui / Cui.cpp
blob99b7a425938082df6399b7a39c06196be166986e
1 #include <set>
2 #include <fstream>
3 #include <cstdlib>
4 #include <iostream>
5 #include <cstdio>
6 #include <string>
7 #include <sstream>
8 #include <cstring>
9 #include <Manager.h>
10 #include <Dict.h>
11 #include <Task.h>
12 #include <Reciter.h>
13 #include <Tester.h>
14 #include <ConfigHolder.h>
15 #include <iomanip>
16 #include "Cui.h"
18 namespace freeRecite {
20 CUI::CUI()
22 if(!manager.load()) {
23 std::cerr << "Can't load " << configHolder.mgrFile() << ".\n";
24 std::cerr << "You should use command \'frt-init\' to initialize.\n";
25 exit(EXIT_FAILURE);
27 if(!dictionary.load()) {
28 std::cerr << "Can't load the dictionary.\n";
29 std::cerr << "You should use command \'frt-init\' to initialize.\n";
30 exit(EXIT_FAILURE);
34 CUI::~CUI()
38 void CUI::run(int argc, char *argv[]) {
39 if(argc == 1) {
40 help();
41 return;
42 }else if(argc == 2){
43 if(!strcmp(argv[1],"--help")) {
44 help();
45 return;
46 }else if(!strcmp(argv[1],"--version")) {
47 std::cout << "Free Recite version 1.0" << std::endl;
48 return;
49 }else if(!strcmp(argv[1],"all")) {
50 showAll();
51 return;
52 }else if(!strcmp(argv[1],"cls")) {
53 cleanStress();
54 return;
55 }else if(!strcmp(argv[1],"done")) {
56 exportDone();
57 return;
58 }else if(!strcmp(argv[1],"ls")) {
59 showActive();
60 return;
61 }else if(!strcmp(argv[1],"modify")) {
62 modify(std::string(""));
63 return;
64 }else if(!strcmp(argv[1],"stress")) {
65 exportStress();
66 return;
68 }else if(argc == 3) {
69 time_t taskID;
70 if(!strcmp(argv[1],"export")) { //frt export <taskID>
71 if( ( taskID = atoid(argv[2]) ) != 0 ) {
72 exportTask(taskID);
73 return;
74 } else { //frt export <filename>
75 exportFromFile(argv[2]);
76 return;
78 }else if(!strcmp(argv[1],"new")) {
79 createNew(argv[2]);
80 return;
81 }else if(!strcmp(argv[1],"merge")) {
82 merge(argv[2]);
83 return;
84 }else if(!strcmp(argv[1],"modify")) {
85 modify(std::string(argv[2]));
86 return;
87 }else if(!strcmp(argv[1],"recite")) { //frt recite <taskID>
88 if( ( taskID = atoid(argv[2]) ) != 0 ) {
89 recite(taskID,false);
90 return;
91 }else { //frt recite <fileName>
92 recite(argv[2],false);
93 return;
95 }else if(!strcmp(argv[1],"rrecite")) { //frt recite <taskID>
96 if( ( taskID = atoid(argv[2]) ) != 0 ) {
97 recite(taskID,true);
98 return;
99 }else { //frt recite <fileName>
100 recite(argv[2],true);
101 return;
103 }else if(!strcmp(argv[1],"remove")) {
104 if( ( taskID = atoid(argv[2]) ) != 0 ){
105 remove(taskID);
106 return;
108 }else if(!strcmp(argv[1],"test")) {
109 if( ( taskID = atoid(argv[2]) ) != 0 ) {
110 test(taskID,false);
111 return;
113 }else if(!strcmp(argv[1],"rtest")) {
114 if( ( taskID = atoid(argv[2]) ) != 0 ) {
115 test(taskID,true);
116 return;
119 } //else if(argc == 3)
121 std::cout << "frt: \'" << argv[argc-1] << "\' is not a frt-command. "
122 << "See \'frt --help\'." << std::endl;
123 } //End of run().
125 time_t CUI::atoid(const char *argv) {
126 std::istringstream ssm(argv);
127 unsigned tid;
128 if((ssm >> tid))
129 return static_cast<time_t>(tid);
130 else
131 return static_cast<time_t>(0);
134 void CUI::cleanStress() {
135 ::remove(configHolder.keyFile().c_str());
138 void CUI::clear() {
139 for(int i = 0; i < 10; ++i)
140 std::cerr << std::endl;
143 void CUI::createNew(const char *fileName) {
144 std::string taskName;
145 std::ifstream ifs(fileName);
146 if(!ifs.is_open()) {
147 std::cout << "Can't find the file." << std::endl;
148 return;
150 std::set<std::string> wordSet;
151 std::string word, name, cmd;
152 std::cout << "Give a task name for it?" << std::endl;
153 std::cout << "(Press Enter will give a default name): ";
154 std::getline(std::cin,name);
155 while(ifs.good()) {
156 std::getline(ifs,word);
157 while(!dictionary.lookUp(word) && !word.empty()) {
158 std::cout << '\"' << word << '\"'
159 << " can't be fond in your dictionary"<<std::endl
160 << "Remove(R),Modify(M) or Add to dictionary(A)? (R/m/a)"
161 << std::endl;
162 std::getline(std::cin,cmd);
164 if(cmd == "A" || cmd == "a")
165 while(!modify(word)) /* An empty sentance. */;
166 else if(cmd == "M" || cmd == "m") {
167 std::cout << "Input the new word: ";
168 std::getline(std::cin,word); //Get a new word from the user.
169 continue;
170 } else
171 std::getline(ifs,word); //Read a new word from file.
174 wordSet.insert(word);
176 unsigned taskMaxWords = 0;
177 if(wordSet.size() > 30)
178 taskMaxWords = 20;
179 else
180 taskMaxWords = 30;
181 if(manager.createTask(wordSet,name.c_str(),taskMaxWords)) {
182 std::cout << "Creat a task SUCCESS!" << std::endl;
183 manager.refresh();
184 }else
185 std::cerr << "Can't creat a task :}" << std::endl;
189 void CUI::exportFromFile(const char *fileName) {
190 std::ifstream ifs(fileName);
191 std::string tmpWord;
192 std::set<std::string> wdSet;
193 if(!ifs.is_open()) {
194 return;
196 while(ifs.good()) {
197 std::getline(ifs, tmpWord);
198 if(!tmpWord.empty())
199 wdSet.insert(tmpWord);
201 ifs.close();
202 std::set<std::string>::const_iterator itr = wdSet.begin();
203 while(itr != wdSet.end()) {
204 if(dictionary.lookUp(*itr)) {
205 std::cout << std::setw(12) << std::setfill(' ') << std::left
206 << dictionary.word() << ' ';
207 if(!dictionary.phonetics().empty())
208 std::cout << '[' << dictionary.phonetics() << ']';
209 std::cout << ' ' << dictionary.translation() << std::endl;
210 }else {
211 std::cout << *itr << " *** " << std::endl;
213 ++itr;
217 void CUI::exportDone() {
218 exportFromFile(configHolder.doneFile().c_str());
221 void CUI::exportTask(time_t taskID) {
222 if(!manager.hasTask(taskID)) {
223 std::cout << "There's no this task!" << std::endl;
224 return;
226 std::string fileName = Scanner::getTaskFileName(taskID);
227 exportFromFile(fileName.c_str());
230 void CUI::exportStress(){
231 exportFromFile(configHolder.keyFile().c_str());
234 void CUI:: merge(const char *fileName) {
235 if(!dictionary.merge(fileName))
236 std::cerr << "FAIL" << std::endl;
237 else
238 std::cerr << "SUCCESS" << std::endl;
242 void CUI::test(time_t taskID, bool reverse) {
243 Tester tester;
244 if(!manager.hasTask(taskID)) {
245 std::cout << "There's no this task!" << std::endl;
246 return;
248 if(!tester.load(taskID)) {
249 std::cerr << "error when load words!" << std::endl;
250 return;
252 time_t startTime = 0;
253 time_t endTime = 0;
254 time(&startTime);
256 if(reverse == true)
257 r_scanProcess(tester);
258 else
259 scanProcess(tester);
261 time(&endTime);
262 startTime = endTime - startTime;
263 std::cout << std::endl << "Used Time: "
264 << startTime/60 << "minutes" << std::endl;
265 int testResult = manager.test(taskID,tester.getScore());
266 if(testResult == 0) {
267 std::cout<<"Your score is " << tester.getScore() << std::endl;
268 std::cout<<"You passed it!"<<std::endl;
269 time_t nextTime = manager.getNextTime(taskID);
270 struct tm * timeinfo;
271 char buffer[30];
272 timeinfo = localtime(&nextTime);
273 strftime(buffer,30,"%Y.%m.%d %H:%M:%S",timeinfo);
274 std::cout << "Then next reviewing time is: " << buffer
275 << std::endl;
276 }else if(testResult == -1){
277 std::cout<<"Your score is " << tester.getScore() << std::endl
278 <<"You haven't passed it :} "<<std::endl;
279 }else { // testResult == 1
280 std::cout << "Congratulations! You have complish this task!"
281 << std::endl;
285 void CUI::recite(const char *fileName, bool reverse) {
286 Reciter reciter;
287 if(!reciter.load(fileName)) {
288 std::cerr << "Can't open this file!" << std::endl;
289 return;
291 time_t startTime = 0;
292 time_t endTime = 0;
293 time(&startTime);
294 if(reverse == true)
295 r_scanProcess(reciter);
296 else
297 scanProcess(reciter);
298 time(&endTime);
299 startTime = (endTime - startTime)/60;
300 time_t usedTime = startTime > 0 ? startTime : 1;
301 std::cout << std::endl << "Used Time: "
302 << usedTime << " minutes" << std::endl;
303 float r_num = reciter.capability() - reciter.getScore();
304 std::cout << "There're " << reciter.capability() << " words in this task. "
305 << reciter.getScore() << " of them you have known before."
306 << std::endl << "Your Reciting Rate is: "
307 << r_num / usedTime
308 << " word(s)/min" << std::endl;
311 void CUI::recite(time_t taskID, bool reverse) {
312 if(!manager.hasTask(taskID)) {
313 std::cerr<< "There's no this task!" << std::endl;
314 return;
317 Reciter reciter;
318 if(!reciter.load(taskID)) {
319 std::cerr << "error when load words!" << std::endl;
320 return;
322 time_t startTime = 0;
323 time_t endTime = 0;
324 time(&startTime);
325 if(reverse == true)
326 r_scanProcess(reciter);
327 else
328 scanProcess(reciter);
329 time(&endTime);
330 startTime = (endTime - startTime)/60;
331 time_t usedTime = startTime > 0 ? startTime : 1;
332 std::cout << std::endl << "Used Time: "
333 << usedTime << " minutes" << std::endl;
334 float r_num = reciter.capability() - reciter.getScore();
335 std::cout << "There're " << reciter.capability() << " words in this task. "
336 << reciter.getScore() << " of them you have known before."
337 << std::endl << "Your Reciting Rate is: "
338 << r_num / usedTime
339 << " word(s)/min" << std::endl;
342 void CUI::remove(time_t taskID) {
343 if(!manager.hasTask(taskID)) {
344 std::cerr<< "There's no this task!" << std::endl;
345 return;
347 manager.removeTask(taskID);
350 bool CUI::modify(const std::string &word) {
351 std::string newItem,inputStr;
352 if(word.empty()) {
353 std::cout<<"[W]: ";
354 std::getline(std::cin,inputStr);
355 newItem.append("[W]"+inputStr);
356 }else
357 newItem.append("[W]"+word);
359 std::cout<<"θ_ɑ_ʌ_ә_є_æ_ɔ_ʃ_ð_ŋ_ʒ"<<std::endl;
360 std::cout<<"0_1_2_3_4_5_6_7_8_9_="<<std::endl;
361 std::cout<<"[T]: ";
362 std::getline(std::cin,inputStr);
363 newItem.append("[T]"+inputStr);
364 std::cout<<"[M]: ";
365 std::getline(std::cin,inputStr);
366 newItem.append("[M]"+inputStr);
368 if(!dictionary.modify(newItem)) {
369 std::cout<<"ERROR!" << std::endl;
370 return false;
372 std::cout<<"SUCCESS!"<<std::endl;
373 return true;
376 void CUI::showActive() {
377 if(!manager.refresh()) {
378 std::cout << "The configure file is broken!" << std::endl;
379 exit(EXIT_FAILURE);
381 if(manager.getActiveTaskNum() == 0) {
383 std::cout << "There's no new task should be review,type \"new\" to creat one."
384 << std::endl;
386 if(manager.getNextTime() != 0) {
387 time_t nextTime = manager.getNextTime();
388 struct tm * timeinfo;
389 char buffer[30];
390 timeinfo = localtime(&nextTime);
391 strftime(buffer,30,"%Y.%m.%d %H:%M:%S",timeinfo);
392 std::cout << "The nearest reviewing time is at " << buffer
393 << std::endl
394 << "Please use FreeRecite at that time!"
395 << std::endl;
398 else {
399 std::cout << std::setw(5) << std::setfill(' ') << std::left << "N"
400 << std::setw(25) << std::setfill(' ') << std::left << "Name"
401 << std::setw(5) << std::setfill(' ') << std::left << "Step"
402 << std::setw(10) << std::setfill(' ') << std::left << " ID"
403 <<std::endl;
405 for(int i = 0; i < manager.getActiveTaskNum(); ++i) {
406 std::cout << std::setw(5) << std::setfill(' ') << std::left << i+1
407 << std::setw(25) << std::setfill(' ') << std::left
408 << manager.getTaskName(manager.getActiveTasks().at(i)) << ' '
409 << std::setw(5) << std::setfill(' ') << std::left
410 << manager.getTaskStep(manager.getActiveTasks().at(i))
411 << std::setw(10) << std::setfill(' ') << std::right
412 << manager.getActiveTasks().at(i)
413 << std::endl;
418 void CUI::showAll() {
419 if(!manager.refresh()) {
420 std::cout << "The configure file is broken!" << std::endl;
421 exit(EXIT_FAILURE);
423 if(manager.getAllTasks().empty()) {
424 std::cout << "There's no new task should be review,type \"new\" to creat one."
425 << std::endl;
427 else {
428 std::cout << "There's " << manager.getAllTasks().size()
429 << " tasks should review." << std::endl;
430 std::cout << std::setw(5) << std::setfill(' ') << std::left << "N"
431 << std::setw(20) << std::setfill(' ') << std::left << "Name"
432 << std::setw(5) << std::setfill(' ') << std::left << "Step"
433 << std::setw(12) << std::setfill(' ') << std::left << " ID"
434 << std::setw(12) << std::setfill(' ') << std::left << " Review Time"
435 <<std::endl;
437 std::map<time_t,Task>::const_iterator itr = manager.getAllTasks().begin();
438 unsigned i = 0;
439 while(++i,itr != manager.getAllTasks().end()) {
440 std::cout << std::setw(5) << std::setfill(' ') << std::left << i
441 << std::setw(20) << std::setfill(' ') << std::left
442 << manager.getTaskName(itr->first) << ' '
443 << std::setw(5) << std::setfill(' ') << std::left
444 << manager.getTaskStep(itr->first)
445 << std::setw(12) << std::setfill(' ') << std::right
446 << itr->first << " ";
447 time_t nextTime = manager.getNextTime(itr->first);
448 struct tm * timeinfo;
449 char buffer[30];
450 timeinfo = localtime(&nextTime);
451 strftime(buffer,30,"%Y.%m.%d %H:%M:%S",timeinfo);
452 std::cout << std::setw(12) << std::setfill(' ') << std::left
453 << buffer << std::endl;
454 ++itr;
459 void CUI::showResult(bool result) {
460 if(result) {
461 std::cout<<" ** * * "<<std::endl;
462 std::cout<<" * * * * "<<std::endl;
463 std::cout<<" * * ** "<<std::endl;
464 std::cout<<" * * * * "<<std::endl;
465 std::cout<<" ** * * "<<std::endl;
467 else {
468 std::cout<<"##### #### #### "<<std::endl;
469 std::cout<<"# # # # # "<<std::endl;
470 std::cout<<"##### #### #### "<<std::endl;
471 std::cout<<"# # # # # "<<std::endl;
472 std::cout<<"##### # # # # "<<std::endl;
476 void CUI::r_scanProcess(Scanner &scanner) {
477 bool result = true;
478 std::string inputStr;
479 while(scanner.isValid()) {
480 if(dictionary.lookUp(scanner.getWord())) {
481 std::cout <<" Amount: "<< scanner.capability()
482 <<" R_Num: " << scanner.size()
483 <<" R_Times: "<< scanner.times() << std::endl;
484 std::cout <<"**********************************************" << std::endl;
485 std::cout<<"*[W]: "<< dictionary.word();
486 std::getline(std::cin,inputStr);
487 if( !dictionary.phonetics().empty() )
488 std::cout << "*[T]: /" << dictionary.phonetics() << "/" << std::endl;
489 std::cout << "*[M]: " << dictionary.translation() << std::endl;
490 std::cout << "**********************************************" << std::endl;
491 std::cout << "Type \'\\help\' to show the implicit command!" << std::endl;
492 std::cout << "Do you remember it?(Y/n) ";
494 std::getline(std::cin,inputStr);
495 if(inputStr == "\\help"){
496 scanProHelp();
497 continue;
498 } else if(inputStr == "\\modify"){
499 modify(scanner.getWord());
500 continue;
501 } else if(inputStr == "\\add"){
502 std::cout << "Input new word: ";
503 std::getline(std::cin,inputStr);
504 scanner.add(inputStr);
505 std::cout << "SUCCESS!" << std::endl;
506 continue;
507 } else if(inputStr == "\\rm"){
508 inputStr = scanner.getWord();
509 scanner.remove(inputStr);
510 std::cout << "SUCCESS!" << std::endl;
511 continue;
512 } else if(inputStr == "\\stop") {
513 exit(EXIT_SUCCESS);
515 if(inputStr == "N" || inputStr == "n")
516 result = false;
517 else
518 result = true;
520 std::cout << std::endl;
521 showResult(result);
522 clear();
523 scanner.test(result);
524 } else { //If the dictionary can't look up the current word
525 std::cout << '\"' << scanner.getWord() << '\"'
526 << " can't be found in your dictionary."
527 << "\n Modify Or Remove it from task(M/r) ";
528 std::string m_r;
529 std::getline(std::cin,m_r);
530 if(m_r == "R" || m_r == "r") {
531 inputStr = scanner.getWord();
532 scanner.remove(inputStr);
533 std::cout << "SUCCESS!" << std::endl;
534 } else {
535 modify(scanner.getWord());
538 } //End of while()
541 void CUI::scanProcess(Scanner &scanner) {
542 bool result;
543 std::string inputStr;
544 while(scanner.isValid()) {
545 if(dictionary.lookUp(scanner.getWord())){
546 std::cout <<" Type \'\\help\' to show the implicit command!"
547 << std::endl;
548 std::cout <<" Amount: "<< scanner.capability()
549 <<" R_Num: " << scanner.size()
550 <<" R_Times: "<< scanner.times()<<std::endl;
551 std::cout<<"[M]: "<<dictionary.translation()<<std::endl;
552 std::cout <<"**********************************************" << std::endl;
553 std::cout<<"*Input : ";
554 std::getline(std::cin,inputStr);
556 if(inputStr == "\\hint") {
557 std::cout << "*Hint : " << dictionary.word().at(0);
558 for(unsigned i = 1; i < dictionary.word().size(); ++i)
559 std::cout << '_';
560 if( !dictionary.phonetics().empty() )
561 std::cout << " /" << dictionary.phonetics() << "/";
562 std::cout << std::endl <<"*Input : ";
563 std::getline(std::cin,inputStr);
566 if(inputStr == "\\help"){
567 scanProHelp();
568 continue;
569 } else if(inputStr == "\\modify"){
570 modify(scanner.getWord());
571 continue;
572 } else if(inputStr == "\\add"){
573 std::cout << "Input new word: ";
574 std::getline(std::cin,inputStr);
575 scanner.add(inputStr);
576 std::cout << "SUCCESS!" << std::endl;
577 continue;
578 } else if(inputStr == "\\rm"){
579 inputStr = scanner.getWord();
580 scanner.remove(inputStr);
581 std::cout << "SUCCESS!" << std::endl;
582 continue;
583 } else if(inputStr == "\\stop") {
584 exit(EXIT_SUCCESS);
586 result = ( inputStr == scanner.getWord() ? true : false );
587 std::cout << "*Answer: " << dictionary.word();
588 if( !dictionary.phonetics().empty() )
589 std::cout << " /" << dictionary.phonetics() << "/";
590 std::cout << std::endl;
591 std::cout <<"**********************************************" << std::endl;
592 showResult(result);
593 clear();
594 scanner.test(result);
595 } else { //If the dictionary can't look up the current word
596 std::cout << '\"' << scanner.getWord() << '\"'
597 << " can't be found in your dictionary."
598 << "\n Modify Or Remove it from task(M/r) ";
599 std::string m_r;
600 std::getline(std::cin,m_r);
601 if(m_r == "R" || m_r == "r") {
602 inputStr = scanner.getWord();
603 scanner.remove(inputStr);
604 std::cout << "SUCCESS!" << std::endl;
605 } else {
606 modify(scanner.getWord());
609 } //End of while()
612 void CUI::scanProHelp() {
613 std::cout << std::endl << "usage: \\command " << std::endl
614 << "\\help Show this help information" << std::endl
615 << "\\add Add new word to this task" << std::endl
616 << "\\rm Remove the current word from this task" << std::endl
617 << "\\modify Modify the current word in the dictionary" << std::endl
618 << "\\hint Get the hint of current word, but the translation can't use"
619 << std::endl
620 << "\\stop Stop Free Recite at once" << std::endl;
623 void CUI::help() {
624 std::cout << "usage: frt [--version] [--help] COMMAND [ARGS]" << std::endl
625 << "The most commonly used git commands are:" << std::endl
626 << " all Show the detail of all the tasks"
627 << std::endl
628 << " cls Clean the strees' words in the system"
629 << std::endl
630 << " done Export the words which you have remembered"
631 <<std::endl
632 << " export <taskID> Export a tasks' words to the screen"
633 << std::endl
634 << " export <filename> Export the words in the file as it is a task"
635 << std::endl
636 << " ls List the tasks that should be reviewed"
637 << std::endl
638 << " new <filename> Creat new tasks with the words in the file"
639 << std::endl
640 << " merge <filename> Merge the dictionary into file"
641 << std::endl
642 << " modify [word] Modify the word in the dictionary"
643 << std::endl
644 << " recite <taskID> Recite the task whose ID is taskID"
645 << std::endl
646 << " recite <filename> Recite the words in the specified file"
647 << std::endl
648 << " rrecite <taskID> Recite from the translationg to word"
649 << std::endl
650 << " rrecite <filename> Recite from the translationg to word"
651 << std::endl
652 << " remove <taskID> Remove a task which you don't want to recite"
653 << std::endl
654 << " stress Show some words which may be difficult for you"
655 << std::endl
656 << " test <taskID> Test the task whose ID is taskID"
657 << std::endl
658 << " rtest <taskID> Test from translation to word"
659 << std::endl
660 << " --help Show this help information"
661 << std::endl
662 << " --version Show the current version"
663 << std::endl;
666 } // namespace freeRecite End.