improme calling mode the implicit command
[FreeRecite.git] / src / ui / Cui.cpp
blob8185427fcbfd207465b3d75ad57acc9f458d97b5
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;
114 }else if(!strcmp(argv[1],"rtest")) {
115 if( ( taskID = atoid(argv[2]) ) != 0 ) {
116 test(taskID,true);
117 return;
120 } //else if(argc == 3)
122 std::cout << "frt: \'" << argv[argc-1] << "\' is not a frt-command. "
123 << "See \'frt --help\'." << std::endl;
124 } //End of run().
126 time_t CUI::atoid(const char *argv) {
127 std::istringstream ssm(argv);
128 unsigned tid;
129 if((ssm >> tid))
130 return static_cast<time_t>(tid);
131 else
132 return static_cast<time_t>(0);
135 void CUI::cleanStress() {
136 ::remove(configHolder.keyFile().c_str());
139 void CUI::clear() {
140 for(int i = 0; i < 10; ++i)
141 std::cerr << std::endl;
144 void CUI::createNew(const char *fileName) {
145 std::string taskName;
146 std::ifstream ifs(fileName);
147 if(!ifs.is_open()) {
148 std::cout << "Can't find the file." << std::endl;
149 return;
151 std::set<std::string> wordSet;
152 std::string word, name, cmd;
153 std::cout << "Give a task name for it?" << std::endl;
154 std::cout << "(Press Enter will give a default name): ";
155 std::getline(std::cin,name);
156 while(ifs.good()) {
157 std::getline(ifs,word);
158 while(word[word.size()-1] == ' ')
159 word.erase(word.size()-1);
160 while(!dictionary.lookUp(word) && !word.empty()) {
161 std::cout << '\"' << word << '\"'
162 << " can't be fond in your dictionary"<<std::endl
163 << "Remove(R),Modify(M) or Add to dictionary(A)? (R/m/a)"
164 << std::endl;
165 std::getline(std::cin,cmd);
167 if(cmd == "A" || cmd == "a")
168 while(!modify(word)) /* An empty sentance. */;
169 else if(cmd == "M" || cmd == "m") {
170 std::cout << "Input the new word: ";
171 std::getline(std::cin,word); //Get a new word from the user.
172 continue;
173 } else
174 std::getline(ifs,word); //Read a new word from file.
177 wordSet.insert(word);
179 unsigned taskMaxWords = 0;
180 if(wordSet.size() > 30)
181 taskMaxWords = 20;
182 else
183 taskMaxWords = 30;
184 if(manager.createTask(wordSet,name.c_str(),taskMaxWords)) {
185 std::cout << "Creat a task SUCCESS!" << std::endl;
186 manager.refresh();
187 }else
188 std::cerr << "Can't creat a task :}" << std::endl;
192 void CUI::exportFromFile(const char *fileName) {
193 std::ifstream ifs(fileName);
194 std::string tmpWord;
195 std::set<std::string> wdSet;
196 if(!ifs.is_open()) {
197 return;
199 while(ifs.good()) {
200 std::getline(ifs, tmpWord);
201 while(tmpWord[tmpWord.size()-1] == ' ')
202 tmpWord.erase(tmpWord.size()-1);
203 if(!tmpWord.empty())
204 wdSet.insert(tmpWord);
206 ifs.close();
207 std::set<std::string>::const_iterator itr = wdSet.begin();
208 while(itr != wdSet.end()) {
209 if(dictionary.lookUp(*itr)) {
210 std::cout << std::setw(12) << std::setfill(' ') << std::left
211 << dictionary.word() << ' ';
212 std::cout << '[' << dictionary.phonetics() << ']';
213 std::cout << ' ' << dictionary.translation() << std::endl;
214 }else {
215 std::cout << *itr << " *** " << std::endl;
217 ++itr;
221 void CUI::exportDone() {
222 exportFromFile(configHolder.doneFile().c_str());
225 void CUI::exportTask(time_t taskID) {
226 if(!manager.hasTask(taskID)) {
227 std::cout << "There's no this task!" << std::endl;
228 return;
230 std::string fileName = Scanner::getTaskFileName(taskID);
231 exportFromFile(fileName.c_str());
234 void CUI::exportStress(){
235 exportFromFile(configHolder.keyFile().c_str());
238 void CUI:: merge(const char *fileName) {
239 if(!dictionary.merge(fileName))
240 std::cerr << "FAIL" << std::endl;
241 else
242 std::cerr << "SUCCESS" << std::endl;
246 void CUI::test(time_t taskID, bool reverse) {
247 Tester tester;
248 if(!manager.hasTask(taskID)) {
249 std::cout << "There's no this task!" << std::endl;
250 return;
252 if(!tester.load(taskID)) {
253 std::cerr << "error when load words!" << std::endl;
254 return;
256 time_t startTime = 0;
257 time_t endTime = 0;
258 time(&startTime);
260 if(reverse == true)
261 r_scanProcess(tester);
262 else
263 scanProcess(tester);
265 time(&endTime);
266 startTime = endTime - startTime;
267 std::cout << std::endl << "Used Time: "
268 << startTime/60 << "minutes" << std::endl;
269 int testResult = manager.test(taskID,tester.getScore());
270 if(testResult == 0) {
271 std::cout<<"Your score is " << tester.getScore() << std::endl;
272 std::cout<<"You passed it!"<<std::endl;
273 time_t nextTime = manager.getNextTime(taskID);
274 struct tm * timeinfo;
275 char buffer[30];
276 timeinfo = localtime(&nextTime);
277 strftime(buffer,30,"%Y.%m.%d %H:%M:%S",timeinfo);
278 std::cout << "Then next reviewing time is: " << buffer
279 << std::endl;
280 }else if(testResult == -1){
281 std::cout<<"Your score is " << tester.getScore() << std::endl
282 <<"You haven't passed it :} "<<std::endl;
283 }else { // testResult == 1
284 std::cout << "Congratulations! You have complish this task!"
285 << std::endl;
289 void CUI::recite(const char *fileName, bool reverse) {
290 Reciter reciter;
291 if(!reciter.load(fileName)) {
292 std::cerr << "Can't open this file!" << std::endl;
293 return;
295 time_t startTime = 0;
296 time_t endTime = 0;
297 time(&startTime);
298 if(reverse == true)
299 r_scanProcess(reciter);
300 else
301 scanProcess(reciter);
302 time(&endTime);
303 startTime = (endTime - startTime)/60;
304 time_t usedTime = startTime > 0 ? startTime : 1;
305 std::cout << std::endl << "Used Time: "
306 << usedTime << " minutes" << std::endl;
307 float r_num = reciter.capability() - reciter.getScore();
308 std::cout << "There're " << reciter.capability() << " words in this task. "
309 << reciter.getScore() << " of them you have known before."
310 << std::endl << "Your Reciting Rate is: "
311 << r_num / usedTime
312 << " word(s)/min" << std::endl;
315 void CUI::recite(time_t taskID, bool reverse) {
316 if(!manager.hasTask(taskID)) {
317 std::cerr<< "There's no this task!" << std::endl;
318 return;
321 Reciter reciter;
322 if(!reciter.load(taskID)) {
323 std::cerr << "error when load words!" << 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::remove(time_t taskID) {
347 if(!manager.hasTask(taskID)) {
348 std::cerr<< "There's no this task!" << std::endl;
349 return;
351 manager.removeTask(taskID);
354 bool CUI::modify(const std::string &word) {
355 std::string newItem,inputStr;
356 if(word.empty()) {
357 std::cout<<"[W]: ";
358 std::getline(std::cin,inputStr);
359 newItem.append("[W]"+inputStr);
360 }else
361 newItem.append("[W]"+word);
363 std::cout<<"θ_ɑ_ʌ_ә_є_æ_ɔ_ʃ_ð_ŋ_ʒ"<<std::endl;
364 std::cout<<"0_1_2_3_4_5_6_7_8_9_="<<std::endl;
365 std::cout<<"[T]: ";
366 std::getline(std::cin,inputStr);
367 newItem.append("[T]"+inputStr);
368 std::cout<<"[M]: ";
369 std::getline(std::cin,inputStr);
370 newItem.append("[M]"+inputStr);
372 if(!dictionary.modify(newItem)) {
373 std::cout<<"ERROR!" << std::endl;
374 return false;
376 std::cout<<"SUCCESS!"<<std::endl;
377 return true;
380 void CUI::status() {
381 int i = manager.currNumWords();
382 if(i < 0) {
383 std::cerr << "Error occurs when read tasks" << std::endl;
384 return ;
387 time_t current;
388 time_t earlyTask = manager.getAllTasks().begin()->first;
389 time(&current);
390 current = (current - earlyTask) / (3600 * 24); //Days
391 if(current < 1)
392 current = 1;
393 std::cout << "Current Amount: " << i << std::endl
394 << "Reciting Rate : " << i/current << " words/day" << std::endl
395 << "The foremost one is created before " << current << " days."
396 << std::endl;
399 void CUI::showActive() {
400 if(!manager.refresh()) {
401 std::cout << "The configure file is broken!" << std::endl;
402 exit(EXIT_FAILURE);
404 if(manager.getActiveTaskNum() == 0) {
406 std::cout << "There's no new task should be review,type \"new\" to creat one."
407 << std::endl;
409 if(manager.getNextTime() != 0) {
410 time_t nextTime = manager.getNextTime();
411 struct tm * timeinfo;
412 char buffer[30];
413 timeinfo = localtime(&nextTime);
414 strftime(buffer,30,"%Y.%m.%d %H:%M:%S",timeinfo);
415 std::cout << "The nearest reviewing time is at " << buffer
416 << std::endl
417 << "Please use FreeRecite at that time!"
418 << std::endl;
421 else {
422 std::cout << std::setw(5) << std::setfill(' ') << std::left << "N"
423 << std::setw(25) << std::setfill(' ') << std::left << "Name"
424 << std::setw(5) << std::setfill(' ') << std::left << "Step"
425 << std::setw(10) << std::setfill(' ') << std::left << " ID"
426 <<std::endl;
428 for(int i = 0; i < manager.getActiveTaskNum(); ++i) {
429 std::cout << std::setw(5) << std::setfill(' ') << std::left << i+1
430 << std::setw(25) << std::setfill(' ') << std::left
431 << manager.getTaskName(manager.getActiveTasks().at(i)) << ' '
432 << std::setw(5) << std::setfill(' ') << std::left
433 << manager.getTaskStep(manager.getActiveTasks().at(i))
434 << std::setw(10) << std::setfill(' ') << std::right
435 << manager.getActiveTasks().at(i)
436 << std::endl;
441 void CUI::showAll() {
442 if(!manager.refresh()) {
443 std::cout << "The configure file is broken!" << std::endl;
444 exit(EXIT_FAILURE);
446 if(manager.getAllTasks().empty()) {
447 std::cout << "There's no new task should be review,type \"new\" to creat one."
448 << std::endl;
450 else {
451 std::cout << "There's " << manager.getAllTasks().size()
452 << " tasks should review." << std::endl;
453 std::cout << std::setw(5) << std::setfill(' ') << std::left << "N"
454 << std::setw(20) << std::setfill(' ') << std::left << "Name"
455 << std::setw(5) << std::setfill(' ') << std::left << "Step"
456 << std::setw(12) << std::setfill(' ') << std::left << " ID"
457 << std::setw(12) << std::setfill(' ') << std::left << " Review Time"
458 <<std::endl;
460 std::map<time_t,Task>::const_iterator itr = manager.getAllTasks().begin();
461 unsigned i = 0;
462 while(++i,itr != manager.getAllTasks().end()) {
463 std::cout << std::setw(5) << std::setfill(' ') << std::left << i
464 << std::setw(20) << std::setfill(' ') << std::left
465 << manager.getTaskName(itr->first) << ' '
466 << std::setw(5) << std::setfill(' ') << std::left
467 << manager.getTaskStep(itr->first)
468 << std::setw(12) << std::setfill(' ') << std::right
469 << itr->first << " ";
470 time_t nextTime = manager.getNextTime(itr->first);
471 struct tm * timeinfo;
472 char buffer[30];
473 timeinfo = localtime(&nextTime);
474 strftime(buffer,30,"%Y.%m.%d %H:%M:%S",timeinfo);
475 std::cout << std::setw(12) << std::setfill(' ') << std::left
476 << buffer << std::endl;
477 ++itr;
482 void CUI::showResult(bool result) {
483 if(result) {
484 std::cout<<" ** * * "<<std::endl;
485 std::cout<<" * * * * "<<std::endl;
486 std::cout<<" * * ** "<<std::endl;
487 std::cout<<" * * * * "<<std::endl;
488 std::cout<<" ** * * "<<std::endl;
490 else {
491 std::cout<<"##### #### #### "<<std::endl;
492 std::cout<<"# # # # # "<<std::endl;
493 std::cout<<"##### #### #### "<<std::endl;
494 std::cout<<"# # # # # "<<std::endl;
495 std::cout<<"##### # # # # "<<std::endl;
499 void CUI::r_scanProcess(Scanner &scanner) {
500 bool result = true;
501 std::string inputStr;
502 while(scanner.isValid()) {
503 clear();
504 if(dictionary.lookUp(scanner.getWord())) {
505 std::cout <<" Amount: "<< scanner.capability()
506 <<" R_Num: " << scanner.size()
507 <<" R_Times: "<< scanner.times() << std::endl;
508 std::cout <<"**********************************************" << std::endl;
509 std::cout<<"*[W]: "<< dictionary.word();
510 std::getline(std::cin,inputStr);
511 if( !dictionary.phonetics().empty() )
512 std::cout << "*[T]: /" << dictionary.phonetics() << "/" << std::endl;
513 std::cout << "*[M]: " << dictionary.translation() << std::endl;
514 std::cout << "**********************************************" << std::endl;
515 std::cout << "Type \'/help\' to show the implicit command!" << std::endl;
516 std::cout << "Do you remember it?(Y/n) ";
518 std::getline(std::cin,inputStr);
519 if(inputStr == "/help"){
520 scanProHelp();
521 continue;
522 } else if(inputStr == "/modify"){
523 modify(scanner.getWord());
524 continue;
525 } else if(inputStr == "/add"){
526 std::cout << "Input new word: ";
527 std::getline(std::cin,inputStr);
528 scanner.add(inputStr);
529 std::cout << "SUCCESS!" << std::endl;
530 continue;
531 } else if(inputStr == "/rm"){
532 inputStr = scanner.getWord();
533 scanner.remove(inputStr);
534 std::cout << "SUCCESS!" << std::endl;
535 continue;
536 } else if(inputStr == "/stop") {
537 exit(EXIT_SUCCESS);
539 if(inputStr == "Y" || inputStr == "y" || inputStr.empty())
540 result = true;
541 else
542 result = false;
544 std::cout << std::endl;
545 showResult(result);
546 scanner.test(result);
547 if(result == false)
548 scanner.test(true);
549 } else { //If the dictionary can't look up the current word
550 std::cout << '\"' << scanner.getWord() << '\"'
551 << " can't be found in your dictionary."
552 << "\n Modify Or Remove it from task(M/r) ";
553 std::string m_r;
554 std::getline(std::cin,m_r);
555 if(m_r == "R" || m_r == "r") {
556 inputStr = scanner.getWord();
557 scanner.remove(inputStr);
558 std::cout << "SUCCESS!" << std::endl;
559 } else {
560 modify(scanner.getWord());
563 } //End of while()
566 void CUI::scanProcess(Scanner &scanner) {
567 bool result;
568 std::string inputStr;
569 while(scanner.isValid()) {
570 clear();
571 if(dictionary.lookUp(scanner.getWord())){
572 std::cout <<" Type \'/help\' to show the implicit command!"
573 << std::endl;
574 std::cout <<" Amount: "<< scanner.capability()
575 <<" R_Num: " << scanner.size()
576 <<" R_Times: "<< scanner.times()<<std::endl;
577 std::cout<<"[M]: "<<dictionary.translation()<<std::endl;
578 std::cout <<"**********************************************" << std::endl;
579 std::cout<<"*Input : ";
580 std::getline(std::cin,inputStr);
582 if(inputStr == "/hint") {
583 std::cout << "*Hint : " << dictionary.word().at(0);
584 for(unsigned i = 1; i < dictionary.word().size(); ++i)
585 std::cout << '_';
586 if( !dictionary.phonetics().empty() )
587 std::cout << " /" << dictionary.phonetics() << "/";
588 std::cout << std::endl <<"*Input : ";
589 std::getline(std::cin,inputStr);
592 if(inputStr == "/help"){
593 scanProHelp();
594 continue;
595 } else if(inputStr == "/modify"){
596 modify(scanner.getWord());
597 continue;
598 } else if(inputStr == "/add"){
599 std::cout << "Input new word: ";
600 std::getline(std::cin,inputStr);
601 scanner.add(inputStr);
602 std::cout << "SUCCESS!" << std::endl;
603 continue;
604 } else if(inputStr == "/rm"){
605 inputStr = scanner.getWord();
606 scanner.remove(inputStr);
607 std::cout << "SUCCESS!" << std::endl;
608 continue;
609 } else if(inputStr == "//stop") {
610 exit(EXIT_SUCCESS);
612 result = ( inputStr == scanner.getWord() ? true : false );
613 std::cout << "*Answer: " << dictionary.word();
614 if( !dictionary.phonetics().empty() )
615 std::cout << " /" << dictionary.phonetics() << "/";
616 std::cout << std::endl;
617 std::cout <<"**********************************************" << std::endl;
618 showResult(result);
619 scanner.test(result);
620 } else { //If the dictionary can't look up the current word
621 std::cout << '\"' << scanner.getWord() << '\"'
622 << " can't be found in your dictionary."
623 << "\n Modify Or Remove it from task(M/r) ";
624 std::string m_r;
625 std::getline(std::cin,m_r);
626 if(m_r == "R" || m_r == "r") {
627 inputStr = scanner.getWord();
628 scanner.remove(inputStr);
629 std::cout << "SUCCESS!" << std::endl;
630 } else {
631 modify(scanner.getWord());
634 } //End of while()
637 void CUI::scanProHelp() {
638 std::cout << std::endl << "usage: /command " << std::endl
639 << "/help Show this help information" << std::endl
640 << "/add Add new word to this task" << std::endl
641 << "/rm Remove the current word from this task" << std::endl
642 << "/modify Modify the current word in the dictionary"
643 << std::endl
644 << "/hint Get the hint of current word, but the translation can't use"
645 << std::endl
646 << "/stop Stop Free Recite at once" << std::endl;
649 void CUI::help() {
650 std::cout << "usage: frt [--version] [--help] COMMAND [ARGS]" << std::endl
651 << "The most commonly used git commands are:" << std::endl
652 << " all Show the detail of all the tasks"
653 << std::endl
654 << " cls Clean the strees' words in the system"
655 << std::endl
656 << " done Export the words which you have remembered"
657 <<std::endl
658 << " export <taskID> Export a tasks' words to the screen"
659 << std::endl
660 << " export <filename> Export the words in the file as it is a task"
661 << std::endl
662 << " ls List the tasks that should be reviewed"
663 << std::endl
664 << " new <filename> Creat new tasks with the words in the file"
665 << std::endl
666 << " merge <filename> Merge the dictionary into file"
667 << std::endl
668 << " modify [word] Modify the word in the dictionary"
669 << std::endl
670 << " recite <taskID> Recite the task whose ID is taskID"
671 << std::endl
672 << " recite <filename> Recite the words in the specified file"
673 << std::endl
674 << " rrecite <taskID> Recite from the translationg to word"
675 << std::endl
676 << " rrecite <filename> Recite from the translationg to word"
677 << std::endl
678 << " remove <taskID> Remove a task which you don't want to recite"
679 << std::endl
680 << " stress Show some words which may be difficult for you"
681 << std::endl
682 << " status Show how many words you are reciting"
683 << std::endl
684 << " test <taskID> Test the task whose ID is taskID"
685 << std::endl
686 << " rtest <taskID> Test from translation to word"
687 << std::endl
688 << " --help Show this help information"
689 << std::endl
690 << " --version Show the current version"
691 << std::endl;
694 } // namespace freeRecite End.