annotate eventLogger.mm @ 41:79c129e500e1

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