FreeRecite Version 2.0
[FreeRecite.git] / src / ui / Cui.cpp
blob1a3ddbf35fe6eda82dc3c053232fdf2cdd5a4b3f
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 the config file.\n";
24 exit(EXIT_FAILURE);
26 if(!dictionary.load()) {
27 std::cerr << "Can't load the dictionary.\n";
28 exit(EXIT_FAILURE);
32 CUI::~CUI()
36 void CUI::run(int argc, char *argv[]) {
37 if(argc == 1) {
38 help();
39 return;
40 }else if(argc == 2){
41 if(!strcmp(argv[1],"--help")) {
42 help();
43 return;
44 }else if(!strcmp(argv[1],"--version")) {
45 std::cout << "Free Recite version 1.0" << std::endl;
46 return;
47 }else if(!strcmp(argv[1],"all")) {
48 showAll();
49 return;
50 }else if(!strcmp(argv[1],"cls")) {
51 cleanStress();
52 return;
53 }else if(!strcmp(argv[1],"done")) {
54 exportDone();
55 return;
56 }else if(!strcmp(argv[1],"ls")) {
57 showActive();
58 return;
59 }else if(!strcmp(argv[1],"modify")) {
60 modify(std::string(""));
61 return;
62 }else if(!strcmp(argv[1],"status")) {
63 status();
64 return;
65 }else if(!strcmp(argv[1],"stress")) {
66 exportStress();
67 return;
69 }else if(argc == 3) {
70 time_t taskID;
71 if(!strcmp(argv[1],"export")) { //frt export <taskID>
72 if( ( taskID = atoid(argv[2]) ) != 0 ) {
73 exportTask(taskID);
74 return;
75 } else { //frt export <filename>
76 exportFromFile(argv[2]);
77 return;
79 }else if(!strcmp(argv[1],"new")) {
80 createNew(argv[2]);
81 return;
82 }else if(!strcmp(argv[1],"merge")) {
83 merge(argv[2]);
84 return;
85 }else if(!strcmp(argv[1],"modify")) {
86 modify(std::string(argv[2]));
87 return;
88 }else if(!strcmp(argv[1],"recite")) { //frt recite <taskID>
89 if( ( taskID = atoid(argv[2]) ) != 0 ) {
90 recite(taskID,false);
91 return;
92 }else { //frt recite <fileName>
93 recite(argv[2],false);
94 return;
96 }else if(!strcmp(argv[1],"rrecite")) { //frt recite <taskID>
97 if( ( taskID = atoid(argv[2]) ) != 0 ) {
98 recite(taskID,true);
99 return;
100 }else { //frt recite <fileName>
101 recite(argv[2],true);
102 return;
104 }else if(!strcmp(argv[1],"remove")) {
105 if( ( taskID = atoid(argv[2]) ) != 0 ){
106 remove(taskID);
107 return;
109 }else if(!strcmp(argv[1],"test")) {
110 if( ( taskID = atoid(argv[2]) ) != 0 ) {
111 test(taskID,false);
112 return;
113 }else { //frt test <fileName>
114 test(argv[2],false);
115 return;
117 }else if(!strcmp(argv[1],"rtest")) {
118 if( ( taskID = atoid(argv[2]) ) != 0 ) {
119 test(taskID,true);
120 return;
121 }else { //frt rtest <fileName>
122 test(argv[2],true);
123 return;
126 } //else if(argc == 3)
128 std::cout << "frt: \'" << argv[argc-1] << "\' is not a frt-command. "
129 << "See \'frt --help\'." << std::endl;
130 } //End of run().
132 time_t CUI::atoid(const char *argv) {
133 std::istringstream ssm(argv);
134 unsigned tid;
135 if((ssm >> tid))
136 return static_cast<time_t>(tid);
137 else
138 return static_cast<time_t>(0);
141 void CUI::cleanStress() {
142 ::remove(configHolder.keyFile().c_str());
145 void CUI::clear() {
146 for(int i = 0; i < 10; ++i)
147 std::cerr << std::endl;
150 void CUI::createNew(const char *fileName) {
151 std::string taskName;
152 std::ifstream ifs(fileName);
153 if(!ifs.is_open()) {
154 std::cout << "Can't find the file." << std::endl;
155 return;
157 std::set<std::string> wordSet;
158 std::string word, name, cmd;
159 std::cout << "Give a task name for it?" << std::endl;
160 std::cout << "(Press Enter will give a default name): ";
161 std::getline(std::cin,name);
162 while(ifs.good()) {
163 std::getline(ifs,word);
164 while(word[word.size()-1] == ' ')
165 word.erase(word.size()-1);
166 while(!dictionary.lookUp(word) && !word.empty()) {
167 std::cout << '\"' << word << '\"'
168 << " can't be fond in your dictionary"<<std::endl
169 << "Remove(R),Modify(M) or Add to dictionary(A)? (R/m/a)"
170 << std::endl;
171 std::getline(std::cin,cmd);
173 if(cmd == "A" || cmd == "a")
174 while(!modify(word)) /* An empty sentance. */;
175 else if(cmd == "M" || cmd == "m") {
176 std::cout << "Input the new word: ";
177 std::getline(std::cin,word); //Get a new word from the user.
178 continue;
179 } else
180 std::getline(ifs,word); //Read a new word from file.
183 wordSet.insert(word);
185 unsigned taskMaxWords = 0;
186 if(wordSet.size() > 30)
187 taskMaxWords = 20;
188 else
189 taskMaxWords = 30;
190 if(manager.createTask(wordSet,name.c_str(),taskMaxWords)) {
191 std::cout << "Creat a task SUCCESS!" << std::endl;
192 manager.refresh();
193 }else
194 std::cerr << "Can't creat a task :}" << std::endl;
198 void CUI::exportFromFile(const char *fileName) {
199 std::ifstream ifs(fileName);
200 std::string tmpWord;
201 std::set<std::string> wdSet;
202 if(!ifs.is_open()) {
203 return;
205 while(ifs.good()) {
206 std::getline(ifs, tmpWord);
207 while(tmpWord[tmpWord.size()-1] == ' ')
208 tmpWord.erase(tmpWord.size()-1);
209 if(!tmpWord.empty())
210 wdSet.insert(tmpWord);
212 ifs.close();
213 std::set<std::string>::const_iterator itr = wdSet.begin();
214 while(itr != wdSet.end()) {
215 if(dictionary.lookUp(*itr)) {
216 std::cout << std::setw(12) << std::setfill(' ') << std::left
217 << dictionary.word() << ' ';
218 std::cout << '[' << dictionary.phonetics() << ']';
219 std::cout << ' ' << dictionary.translation() << std::endl;
220 }else {
221 std::cout << *itr << " *** " << std::endl;
223 ++itr;
227 void CUI::exportDone() {
228 exportFromFile(configHolder.doneFile().c_str());
231 void CUI::exportTask(time_t taskID) {
232 if(!manager.hasTask(taskID)) {
233 std::cout << "There's no this task!" << std::endl;
234 return;
236 std::string fileName = Scanner::getTaskFileName(taskID);
237 exportFromFile(fileName.c_str());
240 void CUI::exportStress(){
241 exportFromFile(configHolder.keyFile().c_str());
244 void CUI:: merge(const char *fileName) {
245 if(!dictionary.merge(fileName))
246 std::cerr << "FAIL" << std::endl;
247 else
248 std::cerr << "SUCCESS" << std::endl;
251 void CUI::test(const char *fileName, bool reverse) {
252 Tester tester;
253 if(!tester.load(fileName)) {
254 std::cerr << "Can't open this file!" << std::endl;
255 return;
258 time_t startTime = 0;
259 time_t endTime = 0;
260 time(&startTime);
262 if(reverse == true)
263 r_scanProcess(tester);
264 else
265 scanProcess(tester);
267 time(&endTime);
268 startTime = (endTime - startTime)/60;
269 time_t usedTime = startTime > 0 ? startTime : 1;
270 std::cout << std::endl << "Used Time: "
271 << usedTime << " minutes" << std::endl;
272 std::cout << "There're " << tester.capability() << " words in this task. "
273 << tester.getScore() << "% of them you have remembered."
274 << std::endl;
277 void CUI::test(time_t taskID, bool reverse) {
278 Tester tester;
279 if(!manager.hasTask(taskID)) {
280 std::cout << "There's no this task!" << std::endl;
281 return;
283 if(!tester.load(taskID)) {
284 std::cerr << "error when load words!" << std::endl;
285 return;
287 time_t startTime = 0;
288 time_t endTime = 0;
289 time(&startTime);
291 if(reverse == true)
292 r_scanProcess(tester);
293 else
294 scanProcess(tester);
296 time(&endTime);
297 startTime = endTime - startTime;
298 std::cout << std::endl << "Used Time: "
299 << startTime/60 << "minutes" << std::endl;
300 int testResult = manager.test(taskID,tester.getScore());
301 if(testResult == 0) {
302 std::cout<<"Your score is " << tester.getScore() << std::endl;
303 std::cout<<"You passed it!"<<std::endl;
304 time_t nextTime = manager.getNextTime(taskID);
305 struct tm * timeinfo;
306 char buffer[30];
307 timeinfo = localtime(&nextTime);
308 strftime(buffer,30,"%Y.%m.%d %H:%M:%S",timeinfo);
309 std::cout << "Then next reviewing time is: " << buffer
310 << std::endl;
311 }else if(testResult == -1){
312 std::cout<<"Your score is " << tester.getScore() << std::endl
313 <<"You haven't passed it :} "<<std::endl;
314 }else { // testResult == 1
315 std::cout << "Congratulations! You have complish this task!"
316 << std::endl;
320 void CUI::recite(const char *fileName, bool reverse) {
321 Reciter reciter;
322 if(!reciter.load(fileName)){
323 std::cerr << "Can't open this file!" << std::endl;
324 return;
326 time_t startTime = 0;
327 time_t endTime = 0;
328 time(&startTime);
329 if(reverse == true)
330 r_scanProcess(reciter);
331 else
332 scanProcess(reciter);
333 time(&endTime);
334 startTime = (endTime - startTime)/60;
335 time_t usedTime = startTime > 0 ? startTime : 1;
336 std::cout << std::endl << "Used Time: "
337 << usedTime << " minutes" << std::endl;
338 float r_num = reciter.capability() - reciter.getScore();
339 std::cout << "There're " << reciter.capability() << " words in this task. "
340 << reciter.getScore() << " of them you have known before."
341 << std::endl << "Your Reciting Rate is: "
342 << r_num / usedTime
343 << " word(s)/min" << std::endl;
346 void CUI::recite(time_t taskID, bool reverse) {
347 if(!manager.hasTask(taskID)) {
348 std::cerr<< "There's no this task!" << std::endl;
349 return;
352 Reciter reciter;
353 if(!reciter.load(taskID)) {
354 std::cerr << "error when load words!" << std::endl;
355 return;
357 time_t startTime = 0;
358 time_t endTime = 0;
359 time(&startTime);
360 if(reverse == true)
361 r_scanProcess(reciter);
362 else
363 scanProcess(reciter);
364 time(&endTime);
365 startTime = (endTime - startTime)/60;
366 time_t usedTime = startTime > 0 ? startTime : 1;
367 std::cout << std::endl << "Used Time: "
368 << usedTime << " minutes" << std::endl;
369 float r_num = reciter.capability() - reciter.getScore();
370 std::cout << "There're " << reciter.capability() << " words in this task. "
371 << reciter.getScore() << " of them you have known before."
372 << std::endl << "Your Reciting Rate is: "
373 << r_num / usedTime
374 << " word(s)/min" << std::endl;
377 void CUI::remove(time_t taskID) {
378 if(!manager.hasTask(taskID)) {
379 std::cerr<< "There's no this task!" << std::endl;
380 return;
382 manager.removeTask(taskID);
385 bool CUI::modify(const std::string &word) {
386 std::string newItem,inputStr;
387 if(word.empty()) {
388 std::cout<<"[W]: ";
389 std::getline(std::cin,inputStr);
390 newItem.append("[W]"+inputStr);
391 }else
392 newItem.append("[W]"+word);
394 std::cout<<"θ_ɑ_ʌ_ә_є_æ_ɔ_ʃ_ð_ŋ_ʒ"<<std::endl;
395 std::cout<<"0_1_2_3_4_5_6_7_8_9_="<<std::endl;
396 std::cout<<"[T]: ";
397 std::getline(std::cin,inputStr);
398 newItem.append("[T]"+inputStr);
399 std::cout<<"[M]: ";
400 std::getline(std::cin,inputStr);
401 newItem.append("[M]"+inputStr);
403 if(!dictionary.modify(newItem)) {
404 std::cout<<"ERROR!" << std::endl;
405 return false;
407 std::cout<<"SUCCESS!"<<std::endl;
408 return true;
411 void CUI::status() {
412 int i = manager.currNumWords();
413 if(i < 0) {
414 std::cerr << "Error occurs when read tasks" << std::endl;
415 return ;
418 time_t current;
419 time_t earlyTask = manager.getAllTasks().begin()->first;
420 time(&current);
421 current = (current - earlyTask) / (3600 * 24); //Days
422 if(current < 1)
423 current = 1;
424 std::cout << "Current Amount: " << i << std::endl
425 << "Reciting Rate : " << i/current << " words/day" << std::endl
426 << "The foremost one is created before " << current << " days."
427 << std::endl;
430 void CUI::showActive() {
431 if(!manager.refresh()) {
432 std::cout << "The configure file is broken!" << std::endl;
433 exit(EXIT_FAILURE);
435 if(manager.getActiveTaskNum() == 0) {
437 std::cout << "There's no new task should be review,type \"new\" to creat one."
438 << std::endl;
440 if(manager.getNextTime() != 0) {
441 time_t nextTime = manager.getNextTime();
442 struct tm * timeinfo;
443 char buffer[30];
444 timeinfo = localtime(&nextTime);
445 strftime(buffer,30,"%Y.%m.%d %H:%M:%S",timeinfo);
446 std::cout << "The nearest reviewing time is at " << buffer
447 << std::endl
448 << "Please use FreeRecite at that time!"
449 << std::endl;
452 else {
453 std::cout << std::setw(5) << std::setfill(' ') << std::left << "N"
454 << std::setw(25) << std::setfill(' ') << std::left << "Name"
455 << std::setw(5) << std::setfill(' ') << std::left << "Step"
456 << std::setw(10) << std::setfill(' ') << std::left << " ID"
457 <<std::endl;
459 for(int i = 0; i < manager.getActiveTaskNum(); ++i) {
460 std::cout << std::setw(5) << std::setfill(' ') << std::left << i+1
461 << std::setw(25) << std::setfill(' ') << std::left
462 << manager.getTaskName(manager.getActiveTasks().at(i)) << ' '
463 << std::setw(5) << std::setfill(' ') << std::left
464 << manager.getTaskStep(manager.getActiveTasks().at(i))
465 << std::setw(10) << std::setfill(' ') << std::right
466 << manager.getActiveTasks().at(i)
467 << std::endl;
472 void CUI::showAll() {
473 if(!manager.refresh()) {
474 std::cout << "The configure file is broken!" << std::endl;
475 exit(EXIT_FAILURE);
477 if(manager.getAllTasks().empty()) {
478 std::cout << "There's no new task should be review,type \"new\" to creat one."
479 << std::endl;
481 else {
482 std::cout << "There's " << manager.getAllTasks().size()
483 << " tasks should review." << std::endl;
484 std::cout << std::setw(5) << std::setfill(' ') << std::left << "N"
485 << std::setw(20) << std::setfill(' ') << std::left << "Name"
486 << std::setw(5) << std::setfill(' ') << std::left << "Step"
487 << std::setw(12) << std::setfill(' ') << std::left << " ID"
488 << std::setw(12) << std::setfill(' ') << std::left << " Review Time"
489 <<std::endl;
491 std::map<time_t,Task>::const_iterator itr = manager.getAllTasks().begin();
492 unsigned i = 0;
493 while(++i,itr != manager.getAllTasks().end()) {
494 std::cout << std::setw(5) << std::setfill(' ') << std::left << i
495 << std::setw(20) << std::setfill(' ') << std::left
496 << manager.getTaskName(itr->first) << ' '
497 << std::setw(5) << std::setfill(' ') << std::left
498 << manager.getTaskStep(itr->first)
499 << std::setw(12) << std::setfill(' ') << std::right
500 << itr->first << " ";
501 time_t nextTime = manager.getNextTime(itr->first);
502 struct tm * timeinfo;
503 char buffer[30];
504 timeinfo = localtime(&nextTime);
505 strftime(buffer,30,"%Y.%m.%d %H:%M:%S",timeinfo);
506 std::cout << std::setw(12) << std::setfill(' ') << std::left
507 << buffer << std::endl;
508 ++itr;
513 void CUI::showResult(bool result) {
514 if(result) {
515 std::cout<<" ** * * "<<std::endl;
516 std::cout<<" * * * * "<<std::endl;
517 std::cout<<" * * ** "<<std::endl;
518 std::cout<<" * * * * "<<std::endl;
519 std::cout<<" ** * * "<<std::endl;
521 else {
522 std::cout<<"##### #### #### "<<std::endl;
523 std::cout<<"# # # # # "<<std::endl;
524 std::cout<<"##### #### #### "<<std::endl;
525 std::cout<<"# # # # # "<<std::endl;
526 std::cout<<"##### # # # # "<<std::endl;
530 void CUI::r_scanProcess(Scanner &scanner) {
531 bool result = true;
532 std::string inputStr;
533 while(scanner.isValid()) {
534 clear();
535 if(dictionary.lookUp(scanner.getWord())) {
536 std::cout <<" Amount: "<< scanner.capability()
537 <<" R_Num: " << scanner.size()
538 <<" R_Times: "<< scanner.times() << std::endl;
539 std::cout <<"**********************************************" << std::endl;
540 std::cout<<"*[W]: "<< dictionary.word();
541 std::getline(std::cin,inputStr);
542 if( !dictionary.phonetics().empty() )
543 std::cout << "*[T]: /" << dictionary.phonetics() << "/" << std::endl;
544 std::cout << "*[M]: " << dictionary.translation() << std::endl;
545 std::cout << "**********************************************" << std::endl;
546 std::cout << "Type \'/help\' to show the implicit command!" << std::endl;
547 std::cout << "Do you remember it?(Y/n) ";
549 std::getline(std::cin,inputStr);
550 if(inputStr == "/help"){
551 scanProHelp();
552 continue;
553 } else if(inputStr == "/modify"){
554 modify(scanner.getWord());
555 continue;
556 } else if(inputStr == "/add"){
557 std::cout << "Input new word: ";
558 std::getline(std::cin,inputStr);
559 scanner.add(inputStr);
560 std::cout << "SUCCESS!" << std::endl;
561 continue;
562 } else if(inputStr == "/rm"){
563 inputStr = scanner.getWord();
564 scanner.remove(inputStr);
565 std::cout << "SUCCESS!" << std::endl;
566 continue;
567 } else if(inputStr == "/stop") {
568 exit(EXIT_SUCCESS);
570 if(inputStr == "Y" || inputStr == "y" || inputStr.empty())
571 result = true;
572 else
573 result = false;
575 std::cout << std::endl;
576 showResult(result);
577 scanner.test(result);
578 if(result == false)
579 scanner.test(true);
580 } else { //If the dictionary can't look up the current word
581 std::cout << '\"' << scanner.getWord() << '\"'
582 << " can't be found in your dictionary."
583 << "\n Modify Or Remove it from task(M/r) ";
584 std::string m_r;
585 std::getline(std::cin,m_r);
586 if(m_r == "R" || m_r == "r") {
587 inputStr = scanner.getWord();
588 scanner.remove(inputStr);
589 std::cout << "SUCCESS!" << std::endl;
590 } else {
591 modify(scanner.getWord());
594 } //End of while()
597 void CUI::scanProcess(Scanner &scanner) {
598 bool result;
599 std::string inputStr;
600 while(scanner.isValid()) {
601 clear();
602 if(dictionary.lookUp(scanner.getWord())){
603 std::cout <<" Type \'/help\' to show the implicit command!"
604 << std::endl;
605 std::cout <<" Amount: "<< scanner.capability()
606 <<" R_Num: " << scanner.size()
607 <<" R_Times: "<< scanner.times()<<std::endl;
608 std::cout<<"[M]: "<<dictionary.translation()<<std::endl;
609 std::cout <<"**********************************************" << std::endl;
610 std::cout<<"*Input : ";
611 std::getline(std::cin,inputStr);
613 if(inputStr == "/hint") {
614 std::cout << "*Hint : " << dictionary.word().at(0);
615 for(unsigned i = 1; i < dictionary.word().size(); ++i)
616 std::cout << '_';
617 if( !dictionary.phonetics().empty() )
618 std::cout << " /" << dictionary.phonetics() << "/";
619 std::cout << std::endl <<"*Input : ";
620 std::getline(std::cin,inputStr);
623 if(inputStr == "/help"){
624 scanProHelp();
625 continue;
626 } else if(inputStr == "/modify"){
627 modify(scanner.getWord());
628 continue;
629 } else if(inputStr == "/add"){
630 std::cout << "Input new word: ";
631 std::getline(std::cin,inputStr);
632 scanner.add(inputStr);
633 std::cout << "SUCCESS!" << std::endl;
634 continue;
635 } else if(inputStr == "/rm"){
636 inputStr = scanner.getWord();
637 scanner.remove(inputStr);
638 std::cout << "SUCCESS!" << std::endl;
639 continue;
640 } else if(inputStr == "/stop") {
641 exit(EXIT_SUCCESS);
643 result = ( inputStr == scanner.getWord() ? true : false );
644 std::cout << "*Answer: " << dictionary.word();
645 if( !dictionary.phonetics().empty() )
646 std::cout << " /" << dictionary.phonetics() << "/";
647 std::cout << std::endl;
648 std::cout <<"**********************************************" << std::endl;
649 showResult(result);
650 scanner.test(result);
651 } else { //If the dictionary can't look up the current word
652 std::cout << '\"' << scanner.getWord() << '\"'
653 << " can't be found in your dictionary."
654 << "\n Modify Or Remove it from task(M/r) ";
655 std::string m_r;
656 std::getline(std::cin,m_r);
657 if(m_r == "R" || m_r == "r") {
658 inputStr = scanner.getWord();
659 scanner.remove(inputStr);
660 std::cout << "SUCCESS!" << std::endl;
661 } else {
662 modify(scanner.getWord());
665 } //End of while()
668 void CUI::scanProHelp() {
669 std::cout << std::endl << "usage: /command " << std::endl
670 << "/help Show this help information" << std::endl
671 << "/add Add new word to this task" << std::endl
672 << "/rm Remove the current word from this task" << std::endl
673 << "/modify Modify the current word in the dictionary"
674 << std::endl
675 << "/hint Get the hint of current word, but the translation can't use"
676 << std::endl
677 << "/stop Stop Free Recite at once" << std::endl;
680 void CUI::help() {
681 std::cout << "usage: frt [--version] [--help] COMMAND [ARGS]" << std::endl
682 << "The most commonly used git commands are:" << std::endl
683 << " all Show the detail of all the tasks"
684 << std::endl
685 << " cls Clean the stress words"
686 << std::endl
687 << " done Export the remembered words"
688 <<std::endl
689 << " export <ID|file> Export words in the task(file)"
690 << std::endl
691 << " ls List the tasks that should be reviewed"
692 << std::endl
693 << " new <file> Creat new tasks with the words in the file"
694 << std::endl
695 << " merge <file> Merge the dictionary into the file"
696 << std::endl
697 << " modify [word] Modify the word in the dictionary"
698 << std::endl
699 << " recite <ID|file> Recite the words in the task(file)"
700 << std::endl
701 << " rrecite <ID|file> Recite from the translationg to word"
702 << std::endl
703 << " remove <taskID> Remove a task"
704 << std::endl
705 << " stress Show the stress words"
706 << std::endl
707 << " status Show how many words you are reciting"
708 << std::endl
709 << " test <ID|file> Test the words in the task(file)"
710 << std::endl
711 << " rtest <ID|file> Test from translation to word"
712 << std::endl
713 << " --help Show this help information"
714 << std::endl
715 << " --version Show the current version"
716 << std::endl;
719 } // namespace freeRecite End.