annotate eventLogger.mm @ 33:92dba082d957

Added trail and EVALUATION_POINT event type.
author Robert Tubb <rt300@eecs.qmul.ac.uk>
date Tue, 26 Mar 2013 18:41:42 +0000
parents ab7c86d0f3d8
children 790939017078
rev   line source
rt300@0 1 //
rt300@0 2 // eventLogger.mm
rt300@0 3 // oscSenderExample
rt300@0 4 //
rt300@0 5 // Created by Robert Tubb on 05/11/2012.
rt300@0 6 //
rt300@0 7 //
rt300@4 8
rt300@8 9 //---------------------------------------------------------------------------
rt300@0 10 #include "eventLogger.h"
rt300@33 11 #include "grid.h"
rt300@33 12
rt300@33 13 extern Grid theGridView;
rt300@1 14
rt300@1 15 EventLogger eventLogger;
rt300@32 16 extern PresetManager presetManager;
rt300@33 17 //---------------------------------------------------------------------------
rt300@33 18 void lEvent::draw(){
rt300@33 19 // can't draw lines you fool
rt300@33 20 double size = 2.0;
rt300@33 21 TwoVector pos = theGridView.coordToPixel(TwoVector(val1,val2)); // euch -rely on grid view?
rt300@33 22
rt300@33 23 if(eventType == SCROLL){
rt300@33 24 ofSetColor(255,123,56);
rt300@33 25 ofRect(pos.x, pos.y,size,size);
rt300@33 26 }else if(eventType == EVALUATION_POINT){
rt300@33 27 size = sliderID/150.0; // slider id is the hover time. sorry sorry.
rt300@33 28 if(size > 40) size = 40;
rt300@33 29 ofSetColor(25,123,216);
rt300@33 30 ofNoFill();
rt300@33 31 ofEllipse(pos.x, pos.y, size, size);
rt300@33 32
rt300@33 33 }
rt300@33 34 }
rt300@29 35
rt300@8 36 //---------------------------------------------------------------------------
rt300@1 37 EventLogger::EventLogger(){
rt300@8 38
rt300@31 39 consentGiven = true; // unless told otherwise firstAppOpen
rt300@8 40 loggingEnabled = true;
rt300@22 41 serverConnectionOK = false;
rt300@22 42 questionnaireCompleted = false;
rt300@22 43 questionnaireUploaded = false;
rt300@27 44 logUploadInProgress = false;
rt300@22 45 ofxiPhoneDeviceType iOSdeviceType = ofxiPhoneGetDeviceType();
rt300@22 46 cout << "Device: " << iOSdeviceType << '\n';
rt300@22 47
rt300@25 48 nextUploadQty = UPLOAD_CHUNK_SIZE; // amount of data uploaded is always more than UPLOAD_CHUNK_SIZE events
rt300@27 49
rt300@8 50 }
rt300@8 51 //---------------------------------------------------------------------------
rt300@24 52 // draw() - show path of last N scroll events - can be scrubbed along?
rt300@24 53 //
rt300@24 54 //---------------------------------------------------------------------------
rt300@29 55
rt300@8 56 void EventLogger::init(){
rt300@4 57
rt300@30 58 checkExistingLogFile(ofxiPhoneGetDocumentsDirectory() + EVENT_LOG_FILENAME);
rt300@8 59 sessionStartTime = ofGetSystemTime();
rt300@31 60
rt300@31 61 logEvent(APP_STARTED);
rt300@31 62
rt300@31 63 serverComms = [[ServerComms alloc] init];
rt300@9 64
rt300@9 65 testConnection();
rt300@7 66
rt300@31 67 }
rt300@31 68 //---------------------------------------------------------------------------
rt300@31 69 bool EventLogger::testConnection(){
rt300@31 70 Json::Value root;
rt300@31 71 root["x"] = "y";
rt300@31 72 cout << "testConnection\n";
rt300@31 73 sendToServer("testConnection", root, true);
rt300@31 74
rt300@30 75 }
rt300@30 76 //---------------------------------------------------------------------------
rt300@30 77 // this reads the persistent log file , checks if we've used the app before and
rt300@30 78 // if we've answered questionnaire or not
rt300@30 79 void EventLogger::checkExistingLogFile(const string &jsonFile){
rt300@30 80 Json::Value root;
rt300@30 81 Json::Reader reader;
rt300@30 82
rt300@30 83 /////////////
rt300@30 84 // read file
rt300@30 85
rt300@30 86 ifstream theFile(jsonFile.c_str());
rt300@30 87 stringstream fileText;
rt300@30 88 string line;
rt300@30 89 if(!theFile){
rt300@30 90
rt300@30 91 firstEverAppOpen();
rt300@30 92 return;
rt300@30 93 }else{
rt300@30 94 while(theFile){
rt300@30 95 theFile >> line;
rt300@30 96 // cout << line; // lots!!!!
rt300@30 97 fileText << line;
rt300@30 98 }
rt300@30 99 theFile.close();
rt300@30 100 }
rt300@30 101
rt300@30 102 // otherwise, we've been in here before
rt300@30 103
rt300@30 104 /////////////
rt300@30 105 // Parse json
rt300@30 106 cout << "size of log JSON string:" << fileText.str().length() << "BYTES \n";
rt300@30 107
rt300@30 108 bool parsingSuccessful = reader.parse( fileText.str(), root );
rt300@30 109
rt300@30 110 if ( !parsingSuccessful )
rt300@30 111 {
rt300@30 112 // report to the user the failure and their locations in the document.
rt300@30 113 std::cout << "Failed to parse event log JSON: \n"
rt300@30 114 << reader.getFormattedErrorMessages();
rt300@30 115 return;
rt300@30 116 }
rt300@30 117
rt300@30 118 /////////////////
rt300@30 119 // now put user deets into variables
rt300@30 120
rt300@30 121 userName = root["userName"].asString();
rt300@30 122 deviceID = root["deviceID"].asLargestInt();
rt300@30 123 nextUploadNumber = root["uploadNumber"].asInt();
rt300@30 124 savedInteractionTime = root["savedInteractionTime"].asLargestInt();
rt300@30 125 questionnaireCompleted = root["questionnaireCompleted"].asBool();
rt300@30 126 questionnaireUploaded = root["questionnaireUploaded"].asBool();
rt300@30 127 interfaceOrder = root["interfaceOrder"].asInt();
rt300@30 128
rt300@29 129
rt300@30 130 // check for unuploaded evts
rt300@30 131 const Json::Value jlogs = root["events"];
rt300@29 132
rt300@30 133 for ( int index = 0; index < jlogs.size(); ++index ) theEvents.push_back(lEvent(jlogs[index]));
rt300@30 134 if(theEvents.size() > nextUploadQty && ! logUploadInProgress){
rt300@30 135 //try to upload
rt300@30 136 uploadEventLog(true);
rt300@30 137 }
rt300@30 138
rt300@30 139 //////////////
rt300@30 140 // what stage is the experiment at??
rt300@30 141
rt300@30 142 if(questionnaireCompleted && !questionnaireUploaded){
rt300@30 143 // then read it in and upload it
rt300@30 144 Json::Value JQ = root["questionnaire"];
rt300@30 145 Json::Value JArray = JQ["qAnswers"];
rt300@30 146 if(JArray.size() < 2){
rt300@30 147 cout << "Error - status of questionnaire is wierd\n";
rt300@30 148 }
rt300@30 149 for ( unsigned int i = 0; i < JArray.size(); i++ )
rt300@30 150 {
rt300@30 151 questionnaireAnswers.push_back(JArray[i].asInt());
rt300@30 152 }
rt300@30 153 questionnaireComments = JQ["comments"].toStyledString();
rt300@30 154 uploadQuestionnaire();
rt300@30 155 }
rt300@30 156 //TODO if questionnaire wasn't reached but still opened then set the timer to something sensible
rt300@30 157
rt300@30 158 if(!questionnaireCompleted){
rt300@30 159 // for now sod it, start from scratch
rt300@30 160 firstEverAppOpen();
rt300@30 161 return;
rt300@30 162 }
rt300@30 163 cout << "Total interaction time: " << savedInteractionTime << '\n';
rt300@30 164
rt300@30 165 //timer.setInteractionTime(savedInteractionTime);
rt300@30 166 //timer.setOrderFromPrevious(interfaceOrder);
rt300@30 167
rt300@8 168 }
rt300@29 169
rt300@8 170 //---------------------------------------------------------------------------
rt300@30 171
rt300@30 172 void EventLogger::firstEverAppOpen(){
rt300@30 173 cout<<"no event log file - first APP open\n";
rt300@30 174 nextUploadNumber = 0;
rt300@30 175 deviceID = ofGetSystemTimeMicros();
rt300@30 176 savedInteractionTime = 0;
rt300@30 177 questionnaireCompleted = false;
rt300@30 178 questionnaireUploaded = false;
rt300@30 179
rt300@33 180 //((testApp *)ofGetAppPtr())->showIntro();
rt300@33 181 //consentGiven = false;
rt300@33 182 ((testApp *)ofGetAppPtr())->justStart();
rt300@33 183
rt300@30 184
rt300@30 185 }
rt300@30 186
rt300@30 187
rt300@30 188 //---------------------------------------------------------------------------
rt300@28 189 void EventLogger::questionnaireAnswersObtained(vector<int> answers, const char* userComments){
rt300@22 190
rt300@22 191 questionnaireCompleted = true;
rt300@22 192 questionnaireAnswers = answers;
rt300@28 193 questionnaireComments = userComments;
rt300@22 194 uploadQuestionnaire();
rt300@31 195 logEvent(QUESTIONNAIRE_COMPLETED);
rt300@22 196
rt300@22 197 }
rt300@22 198 //---------------------------------------------------------------------------
rt300@27 199 void EventLogger::uploadQuestionnaire(){
rt300@22 200 // show indicator
rt300@22 201 cout << "^^^^^^^^ UPLOADING QUESTIONNAIRE ^^^^^^^^ \n";
rt300@31 202 cout << questionnaireToJson() << "\n";
rt300@27 203 sendToServer("questionnaire", questionnaireToJson(), true);
rt300@27 204
rt300@22 205 }
rt300@22 206 //---------------------------------------------------------------------------
rt300@27 207 bool EventLogger::sendToServer(string functionName, Json::Value jsonData, bool async = false){
rt300@22 208
rt300@22 209 Json::FastWriter writer;
rt300@22 210 string jsontext = writer.write( jsonData );
rt300@22 211
rt300@27 212 // remove newline
rt300@22 213 if (!jsontext.empty() && jsontext[jsontext.length()-1] == '\n') {
rt300@22 214 jsontext.erase(jsontext.length()-1);
rt300@22 215 }
rt300@30 216 ostringstream jd;
rt300@30 217 jd << jsontext;
rt300@30 218 NSString *theData = [NSString stringWithUTF8String:jd.str().c_str()];
rt300@30 219 NSString *theType = [NSString stringWithUTF8String:functionName.c_str()];
rt300@22 220
rt300@30 221 if(async){
rt300@30 222 [serverComms doPostRequest:theType withData:theData];
rt300@30 223 }else{
rt300@30 224 bool success = [serverComms doSyncPostRequest:theType withData:theData];
rt300@30 225 return success;
rt300@30 226 }
rt300@29 227
rt300@27 228 }
rt300@27 229 //-----------------------------
rt300@30 230 void EventLogger::questionnaireOK(){
rt300@30 231 questionnaireUploaded = true;
rt300@30 232 }
rt300@30 233 //-----------------------------
rt300@30 234 void EventLogger::eventlogOK(){
rt300@33 235 // COMMENT THIS IF UPLAODING FROM IPAD TO XCODE
rt300@32 236 theEvents.clear();
rt300@30 237 cout << "EVENT LOG UPLOAD SUCCESS\n";
rt300@30 238 nextUploadNumber++;
rt300@30 239 logUploadInProgress = false;
rt300@30 240 }
rt300@30 241 //-----------------------------
rt300@30 242 void EventLogger::testConnectionOK(){
rt300@30 243 cout << "^^^^^^^^ server connection OK ^^^^^^^^ \n";
rt300@30 244 serverConnectionOK = true;
rt300@30 245 }
rt300@30 246 //-----------------------------
rt300@30 247 void EventLogger::questionnaireNotOK(){
rt300@32 248 cout << "XXXXX questionnaire NOT OK XXXXXXX \n";
rt300@30 249 questionnaireUploaded = false;
rt300@30 250 }
rt300@30 251 //-----------------------------
rt300@30 252 void EventLogger::eventlogNotOK(){
rt300@30 253 // try later
rt300@32 254 cout << "XXXXX event log NOT OK XXXXXXX \n";
rt300@30 255 nextUploadQty += UPLOAD_CHUNK_SIZE;
rt300@30 256 logUploadInProgress = false;
rt300@30 257 }
rt300@30 258 //-----------------------------
rt300@30 259 void EventLogger::testConnectionNotOK(){
rt300@32 260 cout << "XXXXX server connection NOT OK XXXXXXX \n";
rt300@30 261 serverConnectionOK = false;
rt300@30 262 // alert?
rt300@30 263
rt300@30 264 }
rt300@27 265
rt300@27 266
rt300@9 267 //---------------------------------------------------------------------------
rt300@9 268
rt300@27 269 bool EventLogger::uploadEventLog(bool async){
rt300@33 270 // COMMENT THIS OUTRT !!!!!!!!
rt300@33 271 return false;
rt300@22 272 // show indicator
rt300@27 273 logUploadInProgress = true;
rt300@25 274 cout << "^^^^^^^^ ATTEMPTING TO UPLOAD " << theEvents.size() << " EVENTS ^^^^^^^^ .\n";
rt300@27 275 if(!async){
rt300@27 276 bool success = sendToServer("eventlog", logsToJson(), async);
rt300@27 277 if(!success){
rt300@29 278 // try later : NOPE has maximum size
rt300@27 279 nextUploadQty += UPLOAD_CHUNK_SIZE;
rt300@27 280 }else{
rt300@27 281
rt300@27 282 // if success - clear memory
rt300@31 283 // IF UPLAODING FROM IPAD TO XCODE COMMENT OUT
rt300@32 284 theEvents.clear();
rt300@27 285 cout << "UPLOAD SUCCESS\n";
rt300@27 286 nextUploadNumber++;
rt300@27 287 }
rt300@27 288 logUploadInProgress = false;
rt300@27 289 return success;
rt300@9 290 }else{
rt300@27 291 sendToServer("eventlog", logsToJson(), async);
rt300@9 292 }
rt300@1 293 }
rt300@8 294 //----------------------------------------------------------------------------
rt300@33 295 bool eventWasInRegion(vector<lEvent>::iterator eiter, TwoVector regionTopLeft, TwoVector regionBottomRight){
rt300@33 296 if( ((*eiter).val1 > regionTopLeft.x ) && ((*eiter).val2 > regionTopLeft.y ) && ((*eiter).val1 < regionBottomRight.x ) && ((*eiter).val2 < regionBottomRight.y )){
rt300@33 297 return true;
rt300@33 298 }else{
rt300@33 299 return false;
rt300@33 300 }
rt300@33 301
rt300@33 302 }
rt300@33 303 //----------------------------------------------------------------------------
rt300@33 304 void EventLogger::drawTrail(const TwoVector min, const TwoVector max){
rt300@33 305 // horribly inefficient
rt300@33 306 vector<lEvent>::iterator eiter;
rt300@33 307 vector<lEvent>::iterator preveiter;
rt300@33 308 int i = 0;
rt300@33 309
rt300@33 310
rt300@33 311
rt300@33 312 preveiter = theEvents.begin();
rt300@33 313 for(eiter = --theEvents.end(); eiter > theEvents.begin(); eiter--){
rt300@27 314
rt300@33 315 //cout << i << '\n';
rt300@33 316 if( (*eiter).eventType == SCROLL || (*eiter).eventType == EVALUATION_POINT){
rt300@33 317 i++;
rt300@33 318 if(i > SCROLL_TRAIL_LENGTH){
rt300@33 319 return;
rt300@33 320 }
rt300@33 321 if(eventWasInRegion(eiter, min, max) || eventWasInRegion(preveiter, min, max)){
rt300@33 322 // draw a line between prev and this
rt300@33 323 if(preveiter != theEvents.begin()){
rt300@33 324 TwoVector start = theGridView.coordToPixel(TwoVector((*preveiter).val1,(*preveiter).val2));
rt300@33 325 TwoVector end = theGridView.coordToPixel(TwoVector((*eiter).val1,(*eiter).val2));
rt300@33 326 ofSetColor(255,255,255,96);
rt300@33 327 ofLine(start.x,start.y, end.x, end.y);
rt300@33 328
rt300@33 329 }else{
rt300@33 330 // draw line from listen point to last evt
rt300@33 331 TwoVector start = TwoVector(ofGetWidth()*0.5,ofGetHeight()*0.5);
rt300@33 332 TwoVector end = theGridView.coordToPixel(TwoVector((*eiter).val1,(*eiter).val2));
rt300@33 333 ofSetColor(255,255,255,96);
rt300@33 334 ofLine(start.x,start.y, end.x, end.y);
rt300@33 335 // draw ever growing listen point
rt300@33 336
rt300@33 337 }
rt300@33 338
rt300@33 339 }
rt300@33 340 preveiter = eiter;
rt300@33 341 }
rt300@33 342 if( (*eiter).eventType == EVALUATION_POINT){
rt300@33 343 if( ((*eiter).val1 > min.x ) && ((*eiter).val2 > min.y ) && ((*eiter).val1 < max.x ) && ((*eiter).val2 < max.y )){
rt300@33 344 // draw it
rt300@33 345 (*eiter).draw();
rt300@33 346 }
rt300@33 347 }
rt300@33 348 }
rt300@33 349
rt300@33 350 }
rt300@8 351
rt300@28 352 //---------------------------------------------------------------------------
rt300@28 353 // only called when doing supervised tests
rt300@27 354 void EventLogger::newUser(){
rt300@32 355 // store old stuff
rt300@32 356
rt300@32 357 saveSessionToFile();
rt300@32 358 presetManager.saveSessionToFile(userName);
rt300@27 359 cout<<"setup new user\n";
rt300@29 360 deleteLogs();
rt300@27 361 nextUploadNumber = 0;
rt300@27 362 deviceID = ofGetSystemTimeMicros();
rt300@27 363 savedInteractionTime = 0;
rt300@28 364 totalInteractionTime = 0;
rt300@28 365 sessionStartTime = ofGetSystemTime();
rt300@27 366 questionnaireCompleted = false;
rt300@29 367 questionnaireUploaded = false;
rt300@29 368
rt300@29 369 ((testApp *)ofGetAppPtr())->showIntro();
rt300@27 370
rt300@27 371 }
rt300@8 372 //---------------------------------------------------------------------------
rt300@8 373 // called from alertView OK in iViewController
rt300@8 374 void EventLogger::setUsername(const char *u){
rt300@8 375 userName = u;
rt300@28 376 // start interaction clock
rt300@29 377
rt300@29 378 //timer.startInteractionClock();
rt300@29 379 [((testApp *)ofGetAppPtr())->tsc startTimer];
rt300@33 380
rt300@33 381 // press play??
rt300@33 382 }
rt300@33 383 //---------------------------------------------------------------------------
rt300@33 384 void EventLogger::thinnedScrollEvent(lEvent newEvent){
rt300@33 385 static lEvent previousEvent(EMPTY_EVENT); // initialised as whatever
rt300@33 386 static int eventCounter = 0;
rt300@33 387
rt300@33 388 // if first event then log it. it won't be, but still.
rt300@33 389 if(theEvents.size() == 0){
rt300@33 390 theEvents.push_back(newEvent);
rt300@33 391 previousEvent = newEvent;
rt300@33 392 return;
rt300@33 393 }
rt300@33 394
rt300@33 395 // if previous event is more than 300ms ago, or event type has changed, log both of them (lots of events on move+zoom combinations!!)
rt300@33 396 int gap = newEvent.eventTime - previousEvent.eventTime;
rt300@33 397 if(gap > 300){
rt300@33 398 // log previous event as a evaluation point MAYBE TODO if previous event was logged as scroll chuck it out?
rt300@33 399 theEvents.push_back(lEvent(EVALUATION_POINT, previousEvent.val1, previousEvent.val2, gap));
rt300@33 400 // and now new event as scroll
rt300@33 401 theEvents.push_back(newEvent);
rt300@33 402 eventCounter = 0;
rt300@33 403
rt300@33 404 }else if(eventCounter >= EVENT_THIN_FACTOR){ // otherwise only record every Nth event
rt300@33 405 theEvents.push_back(newEvent);
rt300@33 406 eventCounter = 0;
rt300@33 407
rt300@33 408 }
rt300@33 409 eventCounter++;
rt300@33 410 previousEvent = newEvent;
rt300@33 411
rt300@28 412 }
rt300@28 413 //---------------------------------------------------------------------------
rt300@28 414 void EventLogger::thinnedLogEvent(lEvent newEvent){
rt300@33 415 static lEvent previousEvent(EMPTY_EVENT); // initialised as whatever. hopefully won't log
rt300@28 416 static int eventCounter = 0;
rt300@28 417
rt300@28 418 // if first event then log it. it won't be, but still.
rt300@28 419 if(theEvents.size() == 0){
rt300@28 420 theEvents.push_back(newEvent);
rt300@28 421 previousEvent = newEvent;
rt300@28 422 return;
rt300@28 423 }
rt300@28 424
rt300@31 425 // if previous event is more than 300ms ago, or event type has changed, log both of them (lots of events on move+zoom combinations!!)
rt300@28 426 int gap = newEvent.eventTime - previousEvent.eventTime;
rt300@28 427 if(gap > 300 || newEvent.eventType != previousEvent.eventType){
rt300@28 428 // if prev event not logged, log it
rt300@31 429 if(theEvents.back().eventTime != previousEvent.eventTime){
rt300@28 430 theEvents.push_back(previousEvent);
rt300@28 431 }
rt300@28 432 theEvents.push_back(newEvent);
rt300@7 433
rt300@28 434 }
rt300@28 435
rt300@28 436 // otherwise only record every Nth event
rt300@28 437 if(eventCounter >= EVENT_THIN_FACTOR){
rt300@28 438 theEvents.push_back(newEvent);
rt300@28 439 eventCounter = 0;
rt300@28 440
rt300@28 441 }
rt300@28 442 eventCounter++;
rt300@28 443 previousEvent = newEvent;
rt300@7 444 }
rt300@8 445 //---------------------------------------------------------------------------
rt300@5 446 void EventLogger::logEvent(const leventType& evtType,const TwoVector& centre, const double& scale, const int& sliderID, const double& sliderVal){
rt300@33 447
rt300@1 448
rt300@1 449 // scroll has 2 double coords
rt300@1 450 // zoom has 1 double scale
rt300@1 451 // save preset has 2 coords
rt300@1 452 // switch view has view type
rt300@9 453 // slider change has int slider index and 1 float value
rt300@1 454
rt300@4 455 // get time for key index
rt300@4 456
rt300@5 457 // thinFactor
rt300@5 458 if(!loggingEnabled) return;
rt300@4 459 switch ( evtType ) {
rt300@28 460 // data thinning here
rt300@28 461 case SCROLL:
rt300@33 462 thinnedScrollEvent(lEvent(evtType,centre.x,centre.y));
rt300@33 463 //theEvents.push_back(lEvent(evtType,centre.x,centre.y));
rt300@28 464 break;
rt300@28 465 case ZOOM:
rt300@28 466 thinnedLogEvent(lEvent(evtType,scale));
rt300@28 467 break;
rt300@28 468 case CHANGE_SLIDER:
rt300@28 469 thinnedLogEvent(lEvent(evtType,sliderVal , 0.0 , sliderID));
rt300@28 470 break;
rt300@29 471 // non thinned data
rt300@4 472 case SAVE_PRESET:
rt300@5 473 theEvents.push_back(lEvent(evtType,centre.x,centre.y));
rt300@4 474 // Code
rt300@4 475 break;
rt300@4 476 case SAVE_DESET:
rt300@5 477 theEvents.push_back(lEvent(evtType,centre.x,centre.y));
rt300@4 478 break;
rt300@28 479
rt300@5 480 case SCROLL_STOPPED:
rt300@5 481 theEvents.push_back(lEvent(evtType,centre.x,centre.y));
rt300@22 482 cout << "SCROLL STOPPED EVENT\n";
rt300@22 483 break;
rt300@22 484 case SNAPPED_TO_PRESET:
rt300@22 485 theEvents.push_back(lEvent(evtType,centre.x,centre.y,sliderID));
rt300@22 486 cout << "SCROLL STOPPED EVENT\n";
rt300@4 487 break;
rt300@25 488 case SWAP_VIEW:
rt300@25 489 theEvents.push_back(lEvent(evtType,0.0 , 0.0 , sliderID)); // slider ID is which view
rt300@25 490 break;
rt300@4 491 default:
rt300@25 492 // default is just an event type with no values
rt300@25 493 theEvents.push_back(lEvent(evtType));
rt300@4 494 break;
rt300@1 495 }
rt300@27 496 if(theEvents.size() > nextUploadQty && !logUploadInProgress){
rt300@27 497 //try to upload asynchronously
rt300@27 498 uploadEventLog(true);
rt300@7 499 }
rt300@9 500 //sessionTime = (ofGetSystemTime() - sessionStartTime);
rt300@28 501 totalInteractionTime = savedInteractionTime + (ofGetSystemTime() - sessionStartTime); // milliseconds
rt300@28 502
rt300@1 503 }
rt300@29 504 //--------------------------------------------------------------------
rt300@29 505 // called from newUser
rt300@29 506 void EventLogger::deleteLogs(){
rt300@29 507 // the
rt300@29 508 theEvents.clear();
rt300@29 509 string fname = ofxiPhoneGetDocumentsDirectory() + EVENT_LOG_FILENAME;
rt300@29 510 ofFile logFile(fname,ofFile::WriteOnly);
rt300@29 511 logFile << "";
rt300@29 512 logFile.close();
rt300@29 513 }
rt300@8 514 //---------------------------------------------------------------------------
rt300@7 515
rt300@7 516 void EventLogger::exitAndSave(){
rt300@25 517
rt300@25 518 if(!consentGiven){
rt300@25 519 logEvent(CONSENT_DENIED);
rt300@25 520 Json::Value jlogs = logsToJson();
rt300@25 521 // try to upload TODO (no - might hang and prevent exit???)
rt300@27 522 uploadEventLog(true);
rt300@25 523 return;
rt300@25 524 }
rt300@25 525 logEvent(APP_EXITED);
rt300@25 526 savedInteractionTime = savedInteractionTime + (ofGetSystemTime() - sessionStartTime);
rt300@7 527 // save user details
rt300@8 528 string fname = ofxiPhoneGetDocumentsDirectory() + EVENT_LOG_FILENAME;
rt300@8 529
rt300@31 530 // try to upload
rt300@31 531 // do it sync because event list needs to be cleared to prevent saving on device
rt300@27 532 uploadEventLog(false);
rt300@7 533
rt300@8 534 // write to file
rt300@25 535 // json without the logs that were uploaded!
rt300@25 536 Json::Value jlogs = logsToJson();
rt300@8 537 ofFile logFile(fname,ofFile::WriteOnly);
rt300@8 538 logFile << jlogs;
rt300@29 539 logFile.close();
rt300@8 540
rt300@8 541 }
rt300@8 542 //---------------------------------------------------------------------------
rt300@8 543
rt300@8 544 Json::Value EventLogger::logsToJson(){
rt300@8 545 // put all logged events into Json formatted string
rt300@8 546 Json::Value root;
rt300@8 547
rt300@8 548 vector<lEvent>::iterator eventIter;
rt300@8 549
rt300@22 550 root["programVersion"] = PROGRAM_VERSION;
rt300@8 551 root["userName"] = userName;
rt300@8 552 root["deviceID"] = deviceID;
rt300@25 553 root["uploadNumber"] = nextUploadNumber;
rt300@22 554 root["iOSdeviceType"] = iOSdeviceType;
rt300@25 555 root["savedInteractionTime"] = savedInteractionTime;
rt300@22 556 root["questionnaireCompleted"] = questionnaireCompleted;
rt300@22 557 root["questionnaireUploaded"] = questionnaireUploaded;
rt300@30 558 root["questionnaire"] = questionnaireToJson();
rt300@30 559
rt300@8 560
rt300@8 561 int i = 0;
rt300@8 562 for(eventIter = theEvents.begin(); eventIter < theEvents.end(); eventIter++){
rt300@8 563 root["events"][i] = (*eventIter).eventToJson();
rt300@8 564 i++;
rt300@7 565 }
rt300@25 566 root["numEventsHere"] = i;
rt300@8 567 return root;
rt300@8 568 }
rt300@22 569
rt300@8 570 //---------------------------------------------------------------------------
rt300@22 571
rt300@22 572 Json::Value EventLogger::questionnaireToJson(){
rt300@22 573 // put all answers into Json formatted string
rt300@22 574 Json::Value root;
rt300@22 575
rt300@22 576 vector<int>::iterator aIter;
rt300@22 577
rt300@22 578 Json::Value questionnaire;
rt300@22 579
rt300@22 580 int i = 0;
rt300@22 581 for(aIter = questionnaireAnswers.begin(); aIter < questionnaireAnswers.end(); aIter++){
rt300@22 582 questionnaire[i] = (*aIter);
rt300@22 583 i++;
rt300@22 584 }
rt300@22 585
rt300@22 586 root["qAnswers"] = questionnaire;
rt300@28 587 root["comments"] = questionnaireComments;
rt300@22 588 root["userName"] = userName;
rt300@22 589 root["deviceID"] = deviceID;
rt300@22 590 root["iOSdeviceType"] = iOSdeviceType;
rt300@22 591 root["programVersion"] = PROGRAM_VERSION;
rt300@22 592
rt300@22 593 return root;
rt300@22 594 }
rt300@30 595
rt300@8 596 //---------------------------------------------------------------------------
rt300@30 597 void EventLogger::printAll(){
rt300@30 598 cout << "-----------------ALL LOGGED EVENTS----------------- \n";
rt300@30 599 vector<lEvent>::iterator evIter;
rt300@30 600 cout << logsToJson() << "\n";
rt300@30 601 cout << "---------------------QUESTIONNAIRE---------------- \n";
rt300@30 602 cout << questionnaireToJson() << "\n";
rt300@30 603 };
rt300@8 604 //---------------------------------------------------------------------------
rt300@32 605
rt300@32 606 void EventLogger::saveSessionToFile(){
rt300@32 607 string fname = ofxiPhoneGetDocumentsDirectory() + userName + '_' + EVENT_LOG_FILENAME;
rt300@32 608
rt300@32 609 // write to file
rt300@32 610 // json without the logs that were uploaded!
rt300@32 611 Json::Value jlogs = logsToJson();
rt300@32 612 ofFile logFile(fname,ofFile::WriteOnly);
rt300@32 613 logFile << jlogs;
rt300@32 614 logFile.close();
rt300@32 615
rt300@32 616 }
rt300@33 617 //----------------------------------------------------------------------------
rt300@33 618 // TODO this path thing
rt300@33 619 vector<TwoVector> EventLogger::getRecentPath(int numEvents){
rt300@33 620 vector<TwoVector> thePath;
rt300@33 621
rt300@33 622 TwoVector lastScrollPos;
rt300@33 623 vector<lEvent>::iterator eventIndex;
rt300@33 624 eventIndex = theEvents.end();
rt300@33 625 int numScrolls = 0;
rt300@33 626 while(numScrolls < numEvents){
rt300@33 627 // go back check for scrolls, check for end of array etc.
rt300@33 628 thePath.push_back(lastScrollPos);
rt300@33 629 numScrolls++;
rt300@33 630 }
rt300@33 631 return thePath;
rt300@33 632 }