annotate eventLogger.mm @ 42:3d627dce8bf0

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