annotate eventLogger.mm @ 49:178642d134a7 tip

xtra files
author Robert Tubb <rt300@eecs.qmul.ac.uk>
date Wed, 01 May 2013 17:34:33 +0100
parents a1e75b94c505
children
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@44 306 vector<lEvent *> EventLogger::getEvaluationPointsInRange(const TwoVector min, const TwoVector max){
rt300@44 307 vector<lEvent *> results;
rt300@44 308 if(eventsToDraw.size() <= 0){
rt300@44 309 return results;
rt300@44 310
rt300@44 311 }
rt300@44 312
rt300@44 313 deque<lEvent>::iterator eiter;
rt300@44 314 deque<lEvent>::iterator preveiter;
rt300@44 315 for(eiter = --eventsToDraw.end(); eiter >= eventsToDraw.begin(); eiter--){
rt300@44 316 if((*eiter).eventType == EVALUATION_POINT){
rt300@44 317 if( ((*eiter).val1 > min.x ) && ((*eiter).val2 > min.y ) && ((*eiter).val1 < max.x ) && ((*eiter).val2 < max.y )){
rt300@44 318 results.push_back(&(*eiter));
rt300@44 319 }
rt300@44 320 }
rt300@44 321 }
rt300@44 322 return results;
rt300@44 323 }
rt300@44 324 //----------------------------------------------------------------------------
rt300@33 325 void EventLogger::drawTrail(const TwoVector min, const TwoVector max){
rt300@38 326 if(eventsToDraw.size() <= 0){
rt300@38 327 return;
rt300@38 328
rt300@38 329 }
rt300@38 330 deque<lEvent>::iterator eiter;
rt300@38 331 deque<lEvent>::iterator preveiter;
rt300@33 332 int i = 0;
rt300@33 333
rt300@33 334
rt300@38 335 preveiter = --eventsToDraw.end();
rt300@38 336 TwoVector start = TwoVector(ofGetWidth()*0.5,ofGetHeight()*0.5);
rt300@38 337 TwoVector end = theGridView.coordToPixel(TwoVector((*preveiter).val1,(*preveiter).val2));
rt300@38 338 ofSetColor(255,255,255,96);
rt300@38 339 ofLine(start.x,start.y, end.x, end.y);
rt300@33 340
rt300@38 341 for(eiter = --eventsToDraw.end(); eiter >= eventsToDraw.begin(); eiter--){
rt300@27 342
rt300@33 343 //cout << i << '\n';
rt300@44 344 if( (*eiter).eventType == SCROLL
rt300@44 345 || (*eiter).eventType == EVALUATION_POINT
rt300@44 346 || (*eiter).eventType == RANDOMISE
rt300@44 347 || (*eiter).eventType == CHANGE_SLIDER)
rt300@44 348 {
rt300@33 349 i++;
rt300@33 350 if(i > SCROLL_TRAIL_LENGTH){
rt300@33 351 return;
rt300@33 352 }
rt300@33 353 if(eventWasInRegion(eiter, min, max) || eventWasInRegion(preveiter, min, max)){
rt300@33 354 // draw a line between prev and this
rt300@38 355 if(eiter != eventsToDraw.begin()){
rt300@33 356 TwoVector start = theGridView.coordToPixel(TwoVector((*preveiter).val1,(*preveiter).val2));
rt300@33 357 TwoVector end = theGridView.coordToPixel(TwoVector((*eiter).val1,(*eiter).val2));
rt300@33 358 ofSetColor(255,255,255,96);
rt300@33 359 ofLine(start.x,start.y, end.x, end.y);
rt300@33 360
rt300@33 361 }
rt300@33 362
rt300@33 363 }
rt300@33 364 preveiter = eiter;
rt300@33 365 }
rt300@33 366 if( (*eiter).eventType == EVALUATION_POINT){
rt300@33 367 if( ((*eiter).val1 > min.x ) && ((*eiter).val2 > min.y ) && ((*eiter).val1 < max.x ) && ((*eiter).val2 < max.y )){
rt300@33 368 // draw it
rt300@33 369 (*eiter).draw();
rt300@33 370 }
rt300@33 371 }
rt300@33 372 }
rt300@33 373
rt300@33 374 }
rt300@8 375
rt300@28 376 //---------------------------------------------------------------------------
rt300@28 377 // only called when doing supervised tests
rt300@27 378 void EventLogger::newUser(){
rt300@32 379 // store old stuff
rt300@32 380
rt300@32 381 saveSessionToFile();
rt300@32 382 presetManager.saveSessionToFile(userName);
rt300@27 383 cout<<"setup new user\n";
rt300@29 384 deleteLogs();
rt300@27 385 nextUploadNumber = 0;
rt300@27 386 deviceID = ofGetSystemTimeMicros();
rt300@27 387 savedInteractionTime = 0;
rt300@28 388 totalInteractionTime = 0;
rt300@28 389 sessionStartTime = ofGetSystemTime();
rt300@27 390 questionnaireCompleted = false;
rt300@29 391 questionnaireUploaded = false;
rt300@29 392
rt300@29 393 ((testApp *)ofGetAppPtr())->showIntro();
rt300@27 394
rt300@27 395 }
rt300@8 396 //---------------------------------------------------------------------------
rt300@8 397 // called from alertView OK in iViewController
rt300@8 398 void EventLogger::setUsername(const char *u){
rt300@8 399 userName = u;
rt300@29 400
rt300@33 401 }
rt300@33 402 //---------------------------------------------------------------------------
rt300@33 403 void EventLogger::thinnedScrollEvent(lEvent newEvent){
rt300@33 404 static lEvent previousEvent(EMPTY_EVENT); // initialised as whatever
rt300@33 405 static int eventCounter = 0;
rt300@33 406
rt300@33 407 // if first event then log it. it won't be, but still.
rt300@33 408 if(theEvents.size() == 0){
rt300@33 409 theEvents.push_back(newEvent);
rt300@33 410 previousEvent = newEvent;
rt300@33 411 return;
rt300@33 412 }
rt300@41 413
rt300@33 414 // 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 415 int gap = newEvent.eventTime - previousEvent.eventTime;
rt300@33 416 if(gap > 300){
rt300@39 417 // log previous event as a evaluation point
rt300@38 418 lEvent evalEvt(EVALUATION_POINT, previousEvent.val1, previousEvent.val2, gap);
rt300@38 419 theEvents.push_back(evalEvt);
rt300@38 420 eventsToDraw.push_back(evalEvt);
rt300@38 421 if(eventsToDraw.size() > SCROLL_TRAIL_LENGTH){
rt300@38 422 eventsToDraw.pop_front();
rt300@38 423 }
rt300@33 424 // and now new event as scroll
rt300@33 425 theEvents.push_back(newEvent);
rt300@38 426 eventsToDraw.push_back(newEvent);
rt300@38 427 if(eventsToDraw.size() > SCROLL_TRAIL_LENGTH){
rt300@38 428 eventsToDraw.pop_front();
rt300@38 429 }
rt300@33 430 eventCounter = 0;
rt300@33 431
rt300@33 432 }else if(eventCounter >= EVENT_THIN_FACTOR){ // otherwise only record every Nth event
rt300@33 433 theEvents.push_back(newEvent);
rt300@38 434 eventsToDraw.push_back(newEvent);
rt300@38 435 if(eventsToDraw.size() > SCROLL_TRAIL_LENGTH){
rt300@38 436 eventsToDraw.pop_front();
rt300@38 437 }
rt300@33 438 eventCounter = 0;
rt300@33 439
rt300@33 440 }
rt300@33 441 eventCounter++;
rt300@33 442 previousEvent = newEvent;
rt300@33 443
rt300@39 444 }//---------------------------------------------------------------------------
rt300@39 445 void EventLogger::thinnedSliderEvent(lEvent newEvent){
rt300@33 446 static lEvent previousEvent(EMPTY_EVENT); // initialised as whatever. hopefully won't log
rt300@28 447 static int eventCounter = 0;
rt300@28 448
rt300@41 449 // if first event then log it.
rt300@28 450 if(theEvents.size() == 0){
rt300@28 451 theEvents.push_back(newEvent);
rt300@28 452 previousEvent = newEvent;
rt300@28 453 return;
rt300@28 454 }
rt300@41 455
rt300@39 456 // if previous event is more than 300ms ago log both of them
rt300@28 457 int gap = newEvent.eventTime - previousEvent.eventTime;
rt300@39 458 if(gap > 300){
rt300@39 459 // we need the PREV grid coord though, which is lost!!
rt300@39 460 TwoVector c = theGridView.getCoord();
rt300@39 461 lEvent evalEvt(EVALUATION_POINT, c.x, c.y, gap);
rt300@39 462 theEvents.push_back(evalEvt);
rt300@39 463 eventsToDraw.push_back(evalEvt);
rt300@39 464 if(eventsToDraw.size() > SCROLL_TRAIL_LENGTH){
rt300@39 465 eventsToDraw.pop_front();
rt300@39 466 }
rt300@39 467 // if prev slider event not logged, log it
rt300@39 468 if(theEvents.back().eventTime != previousEvent.eventTime){
rt300@39 469 theEvents.push_back(previousEvent);
rt300@39 470 }
rt300@39 471
rt300@39 472 // also log new slider evt
rt300@39 473 theEvents.push_back(newEvent);
rt300@39 474 eventCounter = 0;
rt300@39 475
rt300@39 476 }else if(eventCounter >= EVENT_THIN_FACTOR){ // otherwise only record every Nth event
rt300@39 477 theEvents.push_back(newEvent);
rt300@39 478 eventCounter = 0;
rt300@39 479
rt300@39 480 }
rt300@39 481 eventCounter++;
rt300@39 482 previousEvent = newEvent;
rt300@39 483 }
rt300@39 484 //---------------------------------------------------------------------------
rt300@39 485 void EventLogger::thinnedZoomEvent(lEvent newEvent){
rt300@39 486 static lEvent previousEvent(EMPTY_EVENT); // initialised as whatever. hopefully won't log
rt300@39 487 static int eventCounter = 0;
rt300@39 488
rt300@39 489 // if first event then log it. it won't be, but still.
rt300@39 490 if(theEvents.size() == 0){
rt300@39 491 theEvents.push_back(newEvent);
rt300@39 492 previousEvent = newEvent;
rt300@39 493 return;
rt300@39 494 }
rt300@39 495
rt300@39 496 int gap = newEvent.eventTime - previousEvent.eventTime;
rt300@39 497 if(gap > 400){
rt300@28 498 // if prev event not logged, log it
rt300@31 499 if(theEvents.back().eventTime != previousEvent.eventTime){
rt300@28 500 theEvents.push_back(previousEvent);
rt300@28 501 }
rt300@28 502 theEvents.push_back(newEvent);
rt300@39 503 eventCounter = 0;
rt300@7 504
rt300@39 505 }else if(eventCounter >= EVENT_THIN_FACTOR){
rt300@28 506 theEvents.push_back(newEvent);
rt300@28 507 eventCounter = 0;
rt300@28 508
rt300@28 509 }
rt300@28 510 eventCounter++;
rt300@28 511 previousEvent = newEvent;
rt300@7 512 }
rt300@39 513 //-----------------------------------------------------------------------------
rt300@39 514 void EventLogger::thinnedSnapEvent(lEvent nextEvent){
rt300@39 515 static lEvent previousEvent(EMPTY_EVENT);
rt300@39 516 if(nextEvent.val1 != previousEvent.val1 || nextEvent.val2 != previousEvent.val2){
rt300@39 517 theEvents.push_back(nextEvent);
rt300@39 518 cout << "Snapped EVENT\n";
rt300@39 519 }
rt300@39 520 previousEvent = nextEvent;
rt300@39 521 }
rt300@8 522 //---------------------------------------------------------------------------
rt300@5 523 void EventLogger::logEvent(const leventType& evtType,const TwoVector& centre, const double& scale, const int& sliderID, const double& sliderVal){
rt300@33 524
rt300@1 525
rt300@1 526 // scroll has 2 double coords
rt300@1 527 // zoom has 1 double scale
rt300@1 528 // save preset has 2 coords
rt300@1 529 // switch view has view type
rt300@9 530 // slider change has int slider index and 1 float value
rt300@1 531
rt300@4 532 // get time for key index
rt300@4 533
rt300@5 534 // thinFactor
rt300@5 535 if(!loggingEnabled) return;
rt300@4 536 switch ( evtType ) {
rt300@28 537 // data thinning here
rt300@28 538 case SCROLL:
rt300@33 539 thinnedScrollEvent(lEvent(evtType,centre.x,centre.y));
rt300@33 540 //theEvents.push_back(lEvent(evtType,centre.x,centre.y));
rt300@28 541 break;
rt300@28 542 case ZOOM:
rt300@39 543 thinnedZoomEvent(lEvent(evtType,scale));
rt300@28 544 break;
rt300@28 545 case CHANGE_SLIDER:
rt300@39 546 thinnedSliderEvent(lEvent(evtType,sliderVal , 0.0 , sliderID));
rt300@39 547 break;
rt300@39 548 case SNAPPED_TO_PRESET:
rt300@39 549 thinnedSnapEvent(lEvent(evtType,centre.x,centre.y,sliderID));
rt300@39 550
rt300@28 551 break;
rt300@29 552 // non thinned data
rt300@4 553 case SAVE_PRESET:
rt300@5 554 theEvents.push_back(lEvent(evtType,centre.x,centre.y));
rt300@4 555 // Code
rt300@4 556 break;
rt300@4 557 case SAVE_DESET:
rt300@5 558 theEvents.push_back(lEvent(evtType,centre.x,centre.y));
rt300@4 559 break;
rt300@28 560
rt300@5 561 case SCROLL_STOPPED:
rt300@5 562 theEvents.push_back(lEvent(evtType,centre.x,centre.y));
rt300@22 563 break;
rt300@39 564
rt300@25 565 case SWAP_VIEW:
rt300@25 566 theEvents.push_back(lEvent(evtType,0.0 , 0.0 , sliderID)); // slider ID is which view
rt300@25 567 break;
rt300@44 568 // these cases are move events that need to be put in events to draw
rt300@44 569 case RANDOMISE:
rt300@44 570 theEvents.push_back(lEvent(evtType,centre.x,centre.y));
rt300@44 571 eventsToDraw.push_back(lEvent(evtType,centre.x,centre.y));
rt300@44 572 if(eventsToDraw.size() > SCROLL_TRAIL_LENGTH){
rt300@44 573 eventsToDraw.pop_front();
rt300@44 574 }
rt300@44 575 break;
rt300@4 576 default:
rt300@25 577 // default is just an event type with no values
rt300@25 578 theEvents.push_back(lEvent(evtType));
rt300@4 579 break;
rt300@1 580 }
rt300@27 581 if(theEvents.size() > nextUploadQty && !logUploadInProgress){
rt300@27 582 //try to upload asynchronously
rt300@27 583 uploadEventLog(true);
rt300@7 584 }
rt300@9 585 //sessionTime = (ofGetSystemTime() - sessionStartTime);
rt300@28 586 totalInteractionTime = savedInteractionTime + (ofGetSystemTime() - sessionStartTime); // milliseconds
rt300@28 587
rt300@1 588 }
rt300@29 589 //--------------------------------------------------------------------
rt300@29 590 // called from newUser
rt300@29 591 void EventLogger::deleteLogs(){
rt300@29 592 // the
rt300@29 593 theEvents.clear();
rt300@29 594 string fname = ofxiPhoneGetDocumentsDirectory() + EVENT_LOG_FILENAME;
rt300@29 595 ofFile logFile(fname,ofFile::WriteOnly);
rt300@29 596 logFile << "";
rt300@29 597 logFile.close();
rt300@29 598 }
rt300@8 599 //---------------------------------------------------------------------------
rt300@7 600
rt300@7 601 void EventLogger::exitAndSave(){
rt300@25 602
rt300@25 603 if(!consentGiven){
rt300@25 604 logEvent(CONSENT_DENIED);
rt300@25 605 Json::Value jlogs = logsToJson();
rt300@25 606 // try to upload TODO (no - might hang and prevent exit???)
rt300@27 607 uploadEventLog(true);
rt300@25 608 return;
rt300@25 609 }
rt300@25 610 logEvent(APP_EXITED);
rt300@25 611 savedInteractionTime = savedInteractionTime + (ofGetSystemTime() - sessionStartTime);
rt300@7 612 // save user details
rt300@8 613 string fname = ofxiPhoneGetDocumentsDirectory() + EVENT_LOG_FILENAME;
rt300@8 614
rt300@31 615 // try to upload
rt300@31 616 // do it sync because event list needs to be cleared to prevent saving on device
rt300@27 617 uploadEventLog(false);
rt300@7 618
rt300@8 619 // write to file
rt300@25 620 // json without the logs that were uploaded!
rt300@25 621 Json::Value jlogs = logsToJson();
rt300@8 622 ofFile logFile(fname,ofFile::WriteOnly);
rt300@8 623 logFile << jlogs;
rt300@29 624 logFile.close();
rt300@8 625
rt300@8 626 }
rt300@8 627 //---------------------------------------------------------------------------
rt300@8 628
rt300@8 629 Json::Value EventLogger::logsToJson(){
rt300@8 630 // put all logged events into Json formatted string
rt300@8 631 Json::Value root;
rt300@8 632
rt300@8 633 vector<lEvent>::iterator eventIter;
rt300@8 634
rt300@22 635 root["programVersion"] = PROGRAM_VERSION;
rt300@8 636 root["userName"] = userName;
rt300@8 637 root["deviceID"] = deviceID;
rt300@25 638 root["uploadNumber"] = nextUploadNumber;
rt300@22 639 root["iOSdeviceType"] = iOSdeviceType;
rt300@25 640 root["savedInteractionTime"] = savedInteractionTime;
rt300@22 641 root["questionnaireCompleted"] = questionnaireCompleted;
rt300@22 642 root["questionnaireUploaded"] = questionnaireUploaded;
rt300@35 643 if(!questionnaireUploaded) root["questionnaire"] = questionnaireToJson();
rt300@35 644
rt300@8 645
rt300@8 646 int i = 0;
rt300@8 647 for(eventIter = theEvents.begin(); eventIter < theEvents.end(); eventIter++){
rt300@8 648 root["events"][i] = (*eventIter).eventToJson();
rt300@8 649 i++;
rt300@7 650 }
rt300@25 651 root["numEventsHere"] = i;
rt300@8 652 return root;
rt300@8 653 }
rt300@22 654
rt300@8 655 //---------------------------------------------------------------------------
rt300@22 656
rt300@22 657 Json::Value EventLogger::questionnaireToJson(){
rt300@22 658 // put all answers into Json formatted string
rt300@22 659 Json::Value root;
rt300@22 660
rt300@22 661 vector<int>::iterator aIter;
rt300@22 662
rt300@22 663 Json::Value questionnaire;
rt300@22 664
rt300@22 665 int i = 0;
rt300@22 666 for(aIter = questionnaireAnswers.begin(); aIter < questionnaireAnswers.end(); aIter++){
rt300@22 667 questionnaire[i] = (*aIter);
rt300@22 668 i++;
rt300@22 669 }
rt300@22 670
rt300@22 671 root["qAnswers"] = questionnaire;
rt300@28 672 root["comments"] = questionnaireComments;
rt300@22 673 root["userName"] = userName;
rt300@22 674 root["deviceID"] = deviceID;
rt300@22 675 root["iOSdeviceType"] = iOSdeviceType;
rt300@22 676 root["programVersion"] = PROGRAM_VERSION;
rt300@22 677
rt300@22 678 return root;
rt300@22 679 }
rt300@30 680
rt300@8 681 //---------------------------------------------------------------------------
rt300@30 682 void EventLogger::printAll(){
rt300@30 683 cout << "-----------------ALL LOGGED EVENTS----------------- \n";
rt300@30 684 vector<lEvent>::iterator evIter;
rt300@30 685 cout << logsToJson() << "\n";
rt300@30 686 cout << "---------------------QUESTIONNAIRE---------------- \n";
rt300@30 687 cout << questionnaireToJson() << "\n";
rt300@30 688 };
rt300@8 689 //---------------------------------------------------------------------------
rt300@32 690
rt300@32 691 void EventLogger::saveSessionToFile(){
rt300@32 692 string fname = ofxiPhoneGetDocumentsDirectory() + userName + '_' + EVENT_LOG_FILENAME;
rt300@32 693
rt300@32 694 // write to file
rt300@32 695 // json without the logs that were uploaded!
rt300@32 696 Json::Value jlogs = logsToJson();
rt300@32 697 ofFile logFile(fname,ofFile::WriteOnly);
rt300@32 698 logFile << jlogs;
rt300@32 699 logFile.close();
rt300@32 700
rt300@32 701 }
rt300@33 702 //----------------------------------------------------------------------------
rt300@33 703 // TODO this path thing
rt300@33 704 vector<TwoVector> EventLogger::getRecentPath(int numEvents){
rt300@33 705 vector<TwoVector> thePath;
rt300@33 706
rt300@33 707 TwoVector lastScrollPos;
rt300@33 708 vector<lEvent>::iterator eventIndex;
rt300@33 709 eventIndex = theEvents.end();
rt300@33 710 int numScrolls = 0;
rt300@33 711 while(numScrolls < numEvents){
rt300@33 712 // go back check for scrolls, check for end of array etc.
rt300@33 713 thePath.push_back(lastScrollPos);
rt300@33 714 numScrolls++;
rt300@33 715 }
rt300@33 716 return thePath;
rt300@33 717 }