annotate eventLogger.mm @ 38:0dfe9e0c01aa

Evnt trails fit with uploads. Smooth button.
author Robert Tubb <rt300@eecs.qmul.ac.uk>
date Wed, 10 Apr 2013 18:57:05 +0100
parents a42903c61558
children df7c08faf541
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@35 19
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@38 69 void 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@36 232 questionnaireComments = "";
rt300@30 233 }
rt300@30 234 //-----------------------------
rt300@30 235 void EventLogger::eventlogOK(){
rt300@33 236 // COMMENT THIS IF UPLAODING FROM IPAD TO XCODE
rt300@32 237 theEvents.clear();
rt300@30 238 cout << "EVENT LOG UPLOAD SUCCESS\n";
rt300@30 239 nextUploadNumber++;
rt300@30 240 logUploadInProgress = false;
rt300@30 241 }
rt300@30 242 //-----------------------------
rt300@30 243 void EventLogger::testConnectionOK(){
rt300@30 244 cout << "^^^^^^^^ server connection OK ^^^^^^^^ \n";
rt300@30 245 serverConnectionOK = true;
rt300@30 246 }
rt300@30 247 //-----------------------------
rt300@30 248 void EventLogger::questionnaireNotOK(){
rt300@32 249 cout << "XXXXX questionnaire NOT OK XXXXXXX \n";
rt300@30 250 questionnaireUploaded = false;
rt300@30 251 }
rt300@30 252 //-----------------------------
rt300@30 253 void EventLogger::eventlogNotOK(){
rt300@30 254 // try later
rt300@32 255 cout << "XXXXX event log NOT OK XXXXXXX \n";
rt300@30 256 nextUploadQty += UPLOAD_CHUNK_SIZE;
rt300@30 257 logUploadInProgress = false;
rt300@30 258 }
rt300@30 259 //-----------------------------
rt300@30 260 void EventLogger::testConnectionNotOK(){
rt300@32 261 cout << "XXXXX server connection NOT OK XXXXXXX \n";
rt300@30 262 serverConnectionOK = false;
rt300@30 263 // alert?
rt300@30 264
rt300@30 265 }
rt300@27 266
rt300@27 267
rt300@9 268 //---------------------------------------------------------------------------
rt300@9 269
rt300@27 270 bool EventLogger::uploadEventLog(bool async){
rt300@38 271
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@38 295 bool eventWasInRegion(deque<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@38 304 void EventLogger::clearTrail(){
rt300@38 305 eventsToDraw.clear();
rt300@38 306 }
rt300@38 307 //----------------------------------------------------------------------------
rt300@33 308 void EventLogger::drawTrail(const TwoVector min, const TwoVector max){
rt300@38 309 if(eventsToDraw.size() <= 0){
rt300@38 310 return;
rt300@38 311
rt300@38 312 }
rt300@38 313 deque<lEvent>::iterator eiter;
rt300@38 314 deque<lEvent>::iterator preveiter;
rt300@33 315 int i = 0;
rt300@33 316
rt300@33 317
rt300@38 318 preveiter = --eventsToDraw.end();
rt300@38 319 TwoVector start = TwoVector(ofGetWidth()*0.5,ofGetHeight()*0.5);
rt300@38 320 TwoVector end = theGridView.coordToPixel(TwoVector((*preveiter).val1,(*preveiter).val2));
rt300@38 321 ofSetColor(255,255,255,96);
rt300@38 322 ofLine(start.x,start.y, end.x, end.y);
rt300@33 323
rt300@38 324 for(eiter = --eventsToDraw.end(); eiter >= eventsToDraw.begin(); eiter--){
rt300@27 325
rt300@33 326 //cout << i << '\n';
rt300@33 327 if( (*eiter).eventType == SCROLL || (*eiter).eventType == EVALUATION_POINT){
rt300@33 328 i++;
rt300@33 329 if(i > SCROLL_TRAIL_LENGTH){
rt300@33 330 return;
rt300@33 331 }
rt300@33 332 if(eventWasInRegion(eiter, min, max) || eventWasInRegion(preveiter, min, max)){
rt300@33 333 // draw a line between prev and this
rt300@38 334 if(eiter != eventsToDraw.begin()){
rt300@33 335 TwoVector start = theGridView.coordToPixel(TwoVector((*preveiter).val1,(*preveiter).val2));
rt300@33 336 TwoVector end = theGridView.coordToPixel(TwoVector((*eiter).val1,(*eiter).val2));
rt300@33 337 ofSetColor(255,255,255,96);
rt300@33 338 ofLine(start.x,start.y, end.x, end.y);
rt300@33 339
rt300@33 340 }
rt300@33 341
rt300@33 342 }
rt300@33 343 preveiter = eiter;
rt300@33 344 }
rt300@33 345 if( (*eiter).eventType == EVALUATION_POINT){
rt300@33 346 if( ((*eiter).val1 > min.x ) && ((*eiter).val2 > min.y ) && ((*eiter).val1 < max.x ) && ((*eiter).val2 < max.y )){
rt300@33 347 // draw it
rt300@33 348 (*eiter).draw();
rt300@33 349 }
rt300@33 350 }
rt300@33 351 }
rt300@33 352
rt300@33 353 }
rt300@8 354
rt300@28 355 //---------------------------------------------------------------------------
rt300@28 356 // only called when doing supervised tests
rt300@27 357 void EventLogger::newUser(){
rt300@32 358 // store old stuff
rt300@32 359
rt300@32 360 saveSessionToFile();
rt300@32 361 presetManager.saveSessionToFile(userName);
rt300@27 362 cout<<"setup new user\n";
rt300@29 363 deleteLogs();
rt300@27 364 nextUploadNumber = 0;
rt300@27 365 deviceID = ofGetSystemTimeMicros();
rt300@27 366 savedInteractionTime = 0;
rt300@28 367 totalInteractionTime = 0;
rt300@28 368 sessionStartTime = ofGetSystemTime();
rt300@27 369 questionnaireCompleted = false;
rt300@29 370 questionnaireUploaded = false;
rt300@29 371
rt300@29 372 ((testApp *)ofGetAppPtr())->showIntro();
rt300@27 373
rt300@27 374 }
rt300@8 375 //---------------------------------------------------------------------------
rt300@8 376 // called from alertView OK in iViewController
rt300@8 377 void EventLogger::setUsername(const char *u){
rt300@8 378 userName = u;
rt300@28 379 // start interaction clock
rt300@29 380
rt300@29 381 //timer.startInteractionClock();
rt300@29 382 [((testApp *)ofGetAppPtr())->tsc startTimer];
rt300@33 383
rt300@33 384 // press play??
rt300@33 385 }
rt300@33 386 //---------------------------------------------------------------------------
rt300@33 387 void EventLogger::thinnedScrollEvent(lEvent newEvent){
rt300@33 388 static lEvent previousEvent(EMPTY_EVENT); // initialised as whatever
rt300@33 389 static int eventCounter = 0;
rt300@33 390
rt300@33 391 // if first event then log it. it won't be, but still.
rt300@33 392 if(theEvents.size() == 0){
rt300@33 393 theEvents.push_back(newEvent);
rt300@33 394 previousEvent = newEvent;
rt300@33 395 return;
rt300@33 396 }
rt300@33 397
rt300@33 398 // 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 399 int gap = newEvent.eventTime - previousEvent.eventTime;
rt300@33 400 if(gap > 300){
rt300@33 401 // log previous event as a evaluation point MAYBE TODO if previous event was logged as scroll chuck it out?
rt300@38 402 lEvent evalEvt(EVALUATION_POINT, previousEvent.val1, previousEvent.val2, gap);
rt300@38 403 theEvents.push_back(evalEvt);
rt300@38 404 eventsToDraw.push_back(evalEvt);
rt300@38 405 if(eventsToDraw.size() > SCROLL_TRAIL_LENGTH){
rt300@38 406 eventsToDraw.pop_front();
rt300@38 407 }
rt300@33 408 // and now new event as scroll
rt300@33 409 theEvents.push_back(newEvent);
rt300@38 410 eventsToDraw.push_back(newEvent);
rt300@38 411 if(eventsToDraw.size() > SCROLL_TRAIL_LENGTH){
rt300@38 412 eventsToDraw.pop_front();
rt300@38 413 }
rt300@33 414 eventCounter = 0;
rt300@33 415
rt300@33 416 }else if(eventCounter >= EVENT_THIN_FACTOR){ // otherwise only record every Nth event
rt300@33 417 theEvents.push_back(newEvent);
rt300@38 418 eventsToDraw.push_back(newEvent);
rt300@38 419 if(eventsToDraw.size() > SCROLL_TRAIL_LENGTH){
rt300@38 420 eventsToDraw.pop_front();
rt300@38 421 }
rt300@33 422 eventCounter = 0;
rt300@33 423
rt300@33 424 }
rt300@33 425 eventCounter++;
rt300@33 426 previousEvent = newEvent;
rt300@33 427
rt300@28 428 }
rt300@28 429 //---------------------------------------------------------------------------
rt300@28 430 void EventLogger::thinnedLogEvent(lEvent newEvent){
rt300@33 431 static lEvent previousEvent(EMPTY_EVENT); // initialised as whatever. hopefully won't log
rt300@28 432 static int eventCounter = 0;
rt300@28 433
rt300@28 434 // if first event then log it. it won't be, but still.
rt300@28 435 if(theEvents.size() == 0){
rt300@28 436 theEvents.push_back(newEvent);
rt300@28 437 previousEvent = newEvent;
rt300@28 438 return;
rt300@28 439 }
rt300@28 440
rt300@31 441 // 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 442 int gap = newEvent.eventTime - previousEvent.eventTime;
rt300@28 443 if(gap > 300 || newEvent.eventType != previousEvent.eventType){
rt300@28 444 // if prev event not logged, log it
rt300@31 445 if(theEvents.back().eventTime != previousEvent.eventTime){
rt300@28 446 theEvents.push_back(previousEvent);
rt300@28 447 }
rt300@28 448 theEvents.push_back(newEvent);
rt300@7 449
rt300@28 450 }
rt300@28 451
rt300@28 452 // otherwise only record every Nth event
rt300@28 453 if(eventCounter >= EVENT_THIN_FACTOR){
rt300@28 454 theEvents.push_back(newEvent);
rt300@28 455 eventCounter = 0;
rt300@28 456
rt300@28 457 }
rt300@28 458 eventCounter++;
rt300@28 459 previousEvent = newEvent;
rt300@7 460 }
rt300@8 461 //---------------------------------------------------------------------------
rt300@5 462 void EventLogger::logEvent(const leventType& evtType,const TwoVector& centre, const double& scale, const int& sliderID, const double& sliderVal){
rt300@33 463
rt300@1 464
rt300@1 465 // scroll has 2 double coords
rt300@1 466 // zoom has 1 double scale
rt300@1 467 // save preset has 2 coords
rt300@1 468 // switch view has view type
rt300@9 469 // slider change has int slider index and 1 float value
rt300@1 470
rt300@4 471 // get time for key index
rt300@4 472
rt300@5 473 // thinFactor
rt300@5 474 if(!loggingEnabled) return;
rt300@4 475 switch ( evtType ) {
rt300@28 476 // data thinning here
rt300@28 477 case SCROLL:
rt300@33 478 thinnedScrollEvent(lEvent(evtType,centre.x,centre.y));
rt300@33 479 //theEvents.push_back(lEvent(evtType,centre.x,centre.y));
rt300@28 480 break;
rt300@28 481 case ZOOM:
rt300@28 482 thinnedLogEvent(lEvent(evtType,scale));
rt300@28 483 break;
rt300@28 484 case CHANGE_SLIDER:
rt300@28 485 thinnedLogEvent(lEvent(evtType,sliderVal , 0.0 , sliderID));
rt300@28 486 break;
rt300@29 487 // non thinned data
rt300@4 488 case SAVE_PRESET:
rt300@5 489 theEvents.push_back(lEvent(evtType,centre.x,centre.y));
rt300@4 490 // Code
rt300@4 491 break;
rt300@4 492 case SAVE_DESET:
rt300@5 493 theEvents.push_back(lEvent(evtType,centre.x,centre.y));
rt300@4 494 break;
rt300@28 495
rt300@5 496 case SCROLL_STOPPED:
rt300@5 497 theEvents.push_back(lEvent(evtType,centre.x,centre.y));
rt300@22 498 cout << "SCROLL STOPPED EVENT\n";
rt300@22 499 break;
rt300@22 500 case SNAPPED_TO_PRESET:
rt300@22 501 theEvents.push_back(lEvent(evtType,centre.x,centre.y,sliderID));
rt300@35 502 cout << "Snapped EVENT\n";
rt300@4 503 break;
rt300@25 504 case SWAP_VIEW:
rt300@25 505 theEvents.push_back(lEvent(evtType,0.0 , 0.0 , sliderID)); // slider ID is which view
rt300@25 506 break;
rt300@4 507 default:
rt300@25 508 // default is just an event type with no values
rt300@25 509 theEvents.push_back(lEvent(evtType));
rt300@4 510 break;
rt300@1 511 }
rt300@27 512 if(theEvents.size() > nextUploadQty && !logUploadInProgress){
rt300@27 513 //try to upload asynchronously
rt300@27 514 uploadEventLog(true);
rt300@7 515 }
rt300@9 516 //sessionTime = (ofGetSystemTime() - sessionStartTime);
rt300@28 517 totalInteractionTime = savedInteractionTime + (ofGetSystemTime() - sessionStartTime); // milliseconds
rt300@28 518
rt300@1 519 }
rt300@29 520 //--------------------------------------------------------------------
rt300@29 521 // called from newUser
rt300@29 522 void EventLogger::deleteLogs(){
rt300@29 523 // the
rt300@29 524 theEvents.clear();
rt300@29 525 string fname = ofxiPhoneGetDocumentsDirectory() + EVENT_LOG_FILENAME;
rt300@29 526 ofFile logFile(fname,ofFile::WriteOnly);
rt300@29 527 logFile << "";
rt300@29 528 logFile.close();
rt300@29 529 }
rt300@8 530 //---------------------------------------------------------------------------
rt300@7 531
rt300@7 532 void EventLogger::exitAndSave(){
rt300@25 533
rt300@25 534 if(!consentGiven){
rt300@25 535 logEvent(CONSENT_DENIED);
rt300@25 536 Json::Value jlogs = logsToJson();
rt300@25 537 // try to upload TODO (no - might hang and prevent exit???)
rt300@27 538 uploadEventLog(true);
rt300@25 539 return;
rt300@25 540 }
rt300@25 541 logEvent(APP_EXITED);
rt300@25 542 savedInteractionTime = savedInteractionTime + (ofGetSystemTime() - sessionStartTime);
rt300@7 543 // save user details
rt300@8 544 string fname = ofxiPhoneGetDocumentsDirectory() + EVENT_LOG_FILENAME;
rt300@8 545
rt300@31 546 // try to upload
rt300@31 547 // do it sync because event list needs to be cleared to prevent saving on device
rt300@27 548 uploadEventLog(false);
rt300@7 549
rt300@8 550 // write to file
rt300@25 551 // json without the logs that were uploaded!
rt300@25 552 Json::Value jlogs = logsToJson();
rt300@8 553 ofFile logFile(fname,ofFile::WriteOnly);
rt300@8 554 logFile << jlogs;
rt300@29 555 logFile.close();
rt300@8 556
rt300@8 557 }
rt300@8 558 //---------------------------------------------------------------------------
rt300@8 559
rt300@8 560 Json::Value EventLogger::logsToJson(){
rt300@8 561 // put all logged events into Json formatted string
rt300@8 562 Json::Value root;
rt300@8 563
rt300@8 564 vector<lEvent>::iterator eventIter;
rt300@8 565
rt300@22 566 root["programVersion"] = PROGRAM_VERSION;
rt300@8 567 root["userName"] = userName;
rt300@8 568 root["deviceID"] = deviceID;
rt300@25 569 root["uploadNumber"] = nextUploadNumber;
rt300@22 570 root["iOSdeviceType"] = iOSdeviceType;
rt300@25 571 root["savedInteractionTime"] = savedInteractionTime;
rt300@22 572 root["questionnaireCompleted"] = questionnaireCompleted;
rt300@22 573 root["questionnaireUploaded"] = questionnaireUploaded;
rt300@35 574 if(!questionnaireUploaded) root["questionnaire"] = questionnaireToJson();
rt300@35 575
rt300@8 576
rt300@8 577 int i = 0;
rt300@8 578 for(eventIter = theEvents.begin(); eventIter < theEvents.end(); eventIter++){
rt300@8 579 root["events"][i] = (*eventIter).eventToJson();
rt300@8 580 i++;
rt300@7 581 }
rt300@25 582 root["numEventsHere"] = i;
rt300@8 583 return root;
rt300@8 584 }
rt300@22 585
rt300@8 586 //---------------------------------------------------------------------------
rt300@22 587
rt300@22 588 Json::Value EventLogger::questionnaireToJson(){
rt300@22 589 // put all answers into Json formatted string
rt300@22 590 Json::Value root;
rt300@22 591
rt300@22 592 vector<int>::iterator aIter;
rt300@22 593
rt300@22 594 Json::Value questionnaire;
rt300@22 595
rt300@22 596 int i = 0;
rt300@22 597 for(aIter = questionnaireAnswers.begin(); aIter < questionnaireAnswers.end(); aIter++){
rt300@22 598 questionnaire[i] = (*aIter);
rt300@22 599 i++;
rt300@22 600 }
rt300@22 601
rt300@22 602 root["qAnswers"] = questionnaire;
rt300@28 603 root["comments"] = questionnaireComments;
rt300@22 604 root["userName"] = userName;
rt300@22 605 root["deviceID"] = deviceID;
rt300@22 606 root["iOSdeviceType"] = iOSdeviceType;
rt300@22 607 root["programVersion"] = PROGRAM_VERSION;
rt300@22 608
rt300@22 609 return root;
rt300@22 610 }
rt300@30 611
rt300@8 612 //---------------------------------------------------------------------------
rt300@30 613 void EventLogger::printAll(){
rt300@30 614 cout << "-----------------ALL LOGGED EVENTS----------------- \n";
rt300@30 615 vector<lEvent>::iterator evIter;
rt300@30 616 cout << logsToJson() << "\n";
rt300@30 617 cout << "---------------------QUESTIONNAIRE---------------- \n";
rt300@30 618 cout << questionnaireToJson() << "\n";
rt300@30 619 };
rt300@8 620 //---------------------------------------------------------------------------
rt300@32 621
rt300@32 622 void EventLogger::saveSessionToFile(){
rt300@32 623 string fname = ofxiPhoneGetDocumentsDirectory() + userName + '_' + EVENT_LOG_FILENAME;
rt300@32 624
rt300@32 625 // write to file
rt300@32 626 // json without the logs that were uploaded!
rt300@32 627 Json::Value jlogs = logsToJson();
rt300@32 628 ofFile logFile(fname,ofFile::WriteOnly);
rt300@32 629 logFile << jlogs;
rt300@32 630 logFile.close();
rt300@32 631
rt300@32 632 }
rt300@33 633 //----------------------------------------------------------------------------
rt300@33 634 // TODO this path thing
rt300@33 635 vector<TwoVector> EventLogger::getRecentPath(int numEvents){
rt300@33 636 vector<TwoVector> thePath;
rt300@33 637
rt300@33 638 TwoVector lastScrollPos;
rt300@33 639 vector<lEvent>::iterator eventIndex;
rt300@33 640 eventIndex = theEvents.end();
rt300@33 641 int numScrolls = 0;
rt300@33 642 while(numScrolls < numEvents){
rt300@33 643 // go back check for scrolls, check for end of array etc.
rt300@33 644 thePath.push_back(lastScrollPos);
rt300@33 645 numScrolls++;
rt300@33 646 }
rt300@33 647 return thePath;
rt300@33 648 }