/**
 * Common utility functions.
 */
(function(context,$) {

    "use strict";

    context.JK = context.JK || {};
    var rest   = context.JK.Rest();
    var logger = context.JK.logger;

    // types
    var registrationTypes = {
        native : "Native",
        facebook : "Facebook"
    };

    var sessionCreationTypes = {
        create : "Create",
        join : "Join"
    };

    var sessionQualityTypes = {
        good : "Good",
        poor : "Poor"
    };

    var invitationTypes = {
        email : "Email",
        facebook : "Facebook",
        google : "Google"
    };

    var friendConnectTypes = {
        request : "Request",
        accept : "Accept"
    };

    var recordingActions = {
        make : "Make",
        share : "Share"
    };

    var recordingShareTypes = {
        facebook : "Facebook",
        syndicationWidget : "SyndWidget",
        syndicationUrl: "SyndURL"
    };

    var recordingPlayActions = {
        website : "Website",
        client : "Client",
        facebook : "Facebook",
        syndicationWidget : "SyndWidget",
        syndicationUrl: "SyndURL"
    };
    
    var sessionPlayActions = {
        website : "Website",
        client : "Client",
        facebook : "Facebook",
        syndicationWidget : "SyndWidget",
        syndicationUrl: "SyndURL"
    };

    var userLabels = {
        registeredUser : "RegisteredUser",
        visitor: "Visitor"
    };

    var bandActions = {
        create : "Create",
        join : "Join",
        session : "Session",
        recording : "Recording"
    };

    var jkSocialTargets = {
        musician : 'Musician',
        band : 'Band',
        fan : 'Fan',
        recording : 'Recording',
        session : 'Session',
        facebook: 'facebook',
        twitter: 'twitter',
        google: 'google',
    };

    var audioTestFailReasons = {
        latency : 'Latency',
        ioVariance : 'ioVariance',
        ioTarget : 'ioTarget'
    }

    var audioTestDataReasons = {
      pass : 'Pass',
      latencyFail : 'LatencyFail',
      ioVarianceFail : 'ioVarianceFail',
      ioTargetFail : 'ioTargetFail'
    }

    var jamClassReasons = {
        testDrive: 'TestDrive'
    }

    var networkTestFailReasons = {
      stun : 'STUN',
      bandwidth : 'Bandwidth',
      packetRate : 'PacketRate',
      jitter : 'Jitter',
      jamerror : 'ServiceError',
      noNetwork : 'NoNetwork'
    }

    var categories = {
        register : "Register",
        download : "DownloadClient",
        audioTest : "AudioTest",
        audioTestData : 'AudioTestData',
        trackConfig : "AudioTrackConfig",
        networkTest : "NetworkTest",
        sessionCount : "SessionCount",
        sessionMusicians : "SessionMusicians",
        sessionQuality : "SessionQuality",
        invite : "Invite",
        findSession : "FindSession",
        friendConnect : "Connect",
        recording : "Recording",
        recordingPlay : "RecordingPlay",
        sessionPlay : "SessionPlay",
        band : "Band",
        jkLike : 'jkLike',
        jkFollow : 'jkFollow',
        jkFavorite : 'jkFavorite',
        jkComment : 'jkComment',
        fileDownload: "DownloadFile",
        jamclass: 'JamClass'
    };

    // JamTrack categories and actions:
    var jamTrackAvailabilityTypes = {
        worldwide: 'JamTrackGlobal',
        usa: 'JamTrackUSA'        
    }
    var jamTrackActions = {
        isPublic: 'PublicPerformance',
        isPrivate: 'PrivateUse'        
    }
    var jamTrackSessionLabels = {
        nonSession: 'NonSession',
        inSession: 'InSession'    
    }

    var fileDownloads = {
        jamtrack_csv: 'JamTrackCSV',
        jamtrack_pdf: 'JamTrackPDF'
    }

    function translatePlatformForGA(platform) {
        assertOneOf(platform, context.JK.OS);

        if(platform == context.JK.OS.WIN32) {
            return "Windows";
        }
        if(platform == context.JK.OS.OSX) {
            return "Mac";
        }
        if(platform == context.JK.OS.UNIX) {
            return "Unix";
        }
    }

    function assertBoolean(value) {
        if(typeof value != 'boolean') {
            throw "value is not a boolean: " + JSON.stringify(value);
        }
    }

    function assertNumber(value) {
        if(typeof value != 'number') {
            throw "value is not a number: " + JSON.stringify(value);
        }
    }

    function assertOneOf(enumValue, enums){
        var found = false;
        for (var key in enums) {
            if (enumValue == enums[key]) {
                found = true;
                break;
            }
        }
        if(!found) {
            throw "unable to find enum: " + enumValue + " in: " + JSON.stringify(enums);
        }
    }

    function trackFileDownload(type) {
        assertOneOf(type, fileDownloads)
        context.ga('send', 'event', categories.fileDownload, type)
    }

    function trackRegister(asMusician, registrationType) {
        assertBoolean(asMusician);
        assertOneOf(registrationType, registrationTypes);

        var action = asMusician ? "Musician" : "Fan";

        context.ga('send', 'event', categories.register, action, registrationType);
    }

    function trackTestDrivePurchase(count) {

        context.ga('send', 'event', categories.jamclass, jamClassReasons.testDrive, count);

    }
    function trackDownload(platform) {
       var normalizedPlatform = translatePlatformForGA(platform);

       context.ga('send', 'event', categories.download, normalizedPlatform);
    }

    function trackFTUECompletion(state, platform) {
        var normalizedPlatform = translatePlatformForGA(platform);

        context.ga('send', 'event', categories.audioTest, state, normalizedPlatform);
    }

    function trackSessionCount(musicianAccess, fanAccess, invitationCount) {
        assertBoolean(musicianAccess);
        assertBoolean(fanAccess);
        assertNumber(invitationCount);

        var gaMusicianAccess = musicianAccess ? "MusicianPublic" : "MusicianPrivate";
        var gaFanAccess = fanAccess ? "FanPublic" : "FanPrivate";

        context.ga('send', 'event', categories.sessionCount, gaMusicianAccess, gaFanAccess, invitationCount);
    }

    function trackSessionMusicians(joinOrCreate) {
        assertOneOf(joinOrCreate, sessionCreationTypes);

        context.ga('send', 'event', categories.sessionMusicians, joinOrCreate);
    }

    function trackSessionQuality(goodOrPoor) {
        assertOneOf(goodOrPoor, sessionQualityTypes);
        context.ga('send', 'event', categories.sessionQuality, goodOrPoor);
    }

    function trackServiceInvitations(invitationType, numInvited) {
        assertOneOf(invitationType, invitationTypes);
        assertNumber(numInvited);

        context.ga('send', 'event', categories.invite, invitationType, numInvited);
    }

    function trackFindSessions(numSessionsFound) {
        assertNumber(numSessionsFound);

        var sessionCountRollup = "n/a";
        if(numSessionsFound === 0) {
            sessionCountRollup = "0";
        }
        else if(numSessionsFound >= 1 && numSessionsFound <= 5) {
            sessionCountRollup = "1-5";
        }
        else if(numSessionsFound >= 6 && numSessionsFound <= 10) {
            sessionCountRollup = "6-10";
        }
        else {
            sessionCountRollup = "10+";
        }

        context.ga('send', 'event', categories.findSession, sessionCountRollup, numSessionsFound);
    }

    function trackJamTrackPlaySession(sessionId, inSession) {
      rest.getSession(sessionId).done(function(session) {             
        if (session && session.jam_track ) {                
          rest.getJamTracks({id:session.jam_track.id}).done(function(response) {                
            if (response.jamtracks && response.jamtracks.length!=0) {
              var jamtrack = response.jamtracks[0]
              trackJamTrackPlay(
                jamtrack.sales_region!=context.JK.AVAILABILITY_US, 
                session.participants.length > 1, 
                inSession);
            }// if
          })// rest.getJamTracks                 
        }// if
      })// rest.getSession
    }

    function trackJamTrackPlay(isGlobal, isPublic, inSession) {
        assertBoolean(isGlobal)
        assertBoolean(isPublic)
        assertBoolean(inSession)
        context.ga(
            'send', 
            'event',
            (isGlobal)  ? jamTrackAvailabilityTypes.worldwide : jamTrackAvailabilityTypes.usa,
            (isPublic)  ? jamTrackActions.isPublic : jamTrackActions.isPrivate,
            (inSession) ? jamTrackSessionLabels.inSession : jamTrackSessionLabels.nonSession
        )
        logger.debug("Tracked Jam Track Play")
    }

    function trackTiming(timing) {

      if(!timing) {return}

      try {
        var computed = {
          dns: timing.domainLookupEnd - timing.domainLookupStart,
          connect: timing.connectEnd - timing.connectStart,
          ttfb: timing.responseStart - timing.connectEnd,
          basePage: timing.responseEnd - timing.responseStart,
          frontEnd: timing.loadEventStart - timing.responseEnd,
          domContentLoadedEvent: timing.domContentLoadedEventEnd - timing.domContentLoadedEventStart,
          windowLoadEvent: timing.loadEventEnd - timing.loadEventStart,
          domInteractive: timing.domInteractive - timing.domLoading,
          domComplete: timing.domComplete - timing.domLoading,
          domCompleteToOnload: timing.loadEventStart - timing.domComplete
        };

        logger.debug("page load time: " + computed.frontEnd)
        context._.each(computed, function (value, key) {
          if (value > 0 && value < 60000) {
            context.ga("send", "timing", "NavigationTiming", key, value, null, {'page' : '/' + window.location.pathname});
          }
        })
        //context.stats.write('web.timing.navigation', computed)
      }
      catch(e) {
        logger.error("loading times failed in ga.js", e)
      }
    }

    // if you want to pass in no title, either omit it from the arg list when u invoke virtualPageView, or pass in undefined, NOT null
    function virtualPageView(page, title) {

        context.ga('send', 'pageview', {
            'page': page,
            'title': title
        });
    }

    function trackFriendConnect(friendConnectType) {
        assertOneOf(friendConnectType, friendConnectTypes);

        context.ga('send', 'event', categories.friendConnect, friendConnectType);
    }

    // when someone keeps a recording
    function trackMakeRecording() {
        context.ga('send', 'event', categories.recording, recordingActions.make);
    }

    // when someone shares a recording
    function trackShareRecording(shareType) {
        assertOneOf(shareType, recordingShareTypes);

        context.ga('send', 'event', categories.recording, recordingActions.share, shareType);
    }

    function _defaultPlayAction() {
        return !window.jamClient || ((typeof(FakeJamClient)!='undefined') && window.jamClient === FakeJamClient) ? 'Website' : 'Client';
    }

    // when someone plays a recording
    function trackRecordingPlay(recording, recordingAction) {
        
        if (!recordingAction) {
            recordingAction = _defaultPlayAction();
        }
        assertOneOf(recordingAction, recordingPlayActions);
        var label = JK.currentUserId ? userLabels.registeredUser :  userLabels.visitor;

        context.ga('send', 'event', categories.recordingPlay, recordingAction, label);

        if (recording.jam_track) {
            rest.getJamTracks({id:recording.jam_track_id}).done(function(response) {
                if (response.jamtracks && response.jamtracks.length==1) {
                    var jamtrack = response.jamtracks[0]
                    trackJamTrackPlay(jamtrack.sales_region!=context.JK.AVAILABILITY_US, recording.fan_access, false);
                }
            })            
        }
    }

    // when someone plays a live session broadcast
    function trackSessionPlay(session, recordingAction) {
        logger.debug("Tracking session play: ", session)
        if (!recordingAction) {
            recordingAction = _defaultPlayAction();
        }
        assertOneOf(recordingAction, sessionPlayActions);
        var label = JK.currentUserId ? userLabels.registeredUser :  userLabels.visitor;

        context.ga('send', 'event', categories.sessionPlay, recordingAction, label);
    }

    function trackBand(bandAction) {
        assertOneOf(bandAction, bandActions);

        context.ga('send', 'event', categories.band, bandAction);
    }

    function trackJKSocial(category, target, data) {
        assertOneOf(category, categories);
        assertOneOf(target, jkSocialTargets);

        context.ga('send', 'event', category, target, data);
    }

    function trackNetworkTest(platform, numUsers) {
      var normalizedPlatform = translatePlatformForGA(platform);

      context.ga('send', 'event', categories.networkTest, 'Passed', normalizedPlatform, numUsers);
    }

    function trackNetworkTestFailure(reason, data) {
      assertOneOf(reason, networkTestFailReasons);

      context.ga('send', 'event', categories.networkTest, 'Failed', reason, data);
    }

    function trackAudioTestCompletion(platform) {
      var normalizedPlatform = translatePlatformForGA(platform);

      context.ga('send', 'event', categories.audioTest, 'Passed', normalizedPlatform);
    }

    function trackAudioTestFailure(platform, reason, data) {
      assertOneOf(reason, audioTestFailReasons);

      var normalizedPlatform = translatePlatformForGA(platform);

      if(normalizedPlatform == "Windows") {
        var action = "FailedWin";
      }
      else if(normalizedPlatform == "Mac") {
        var action = "FailedMac";
      }
      else {
        var action = "FailedLinux";
      }

      context.ga('send', 'event', categories.audioTest, action, reason, data);
    }

    function trackConfigureTracksCompletion(platform) {
      var normalizedPlatform = translatePlatformForGA(platform);

      context.ga('send', 'event', categories.trackConfig, 'Passed', normalizedPlatform);
    }

    function trackAudioTestData(uniqueDeviceName, reason, data) {
      assertOneOf(reason, audioTestDataReasons);

      context.ga('send', 'event', categories.audioTestData, uniqueDeviceName, reason, data);
    }

    var GA = {};
    GA.Categories = categories;
    GA.SessionCreationTypes = sessionCreationTypes;
    GA.SessionQualityTypes = sessionQualityTypes;
    GA.InvitationTypes = invitationTypes;
    GA.FriendConnectTypes = friendConnectTypes;
    GA.RecordingActions = recordingActions;
    GA.BandActions = bandActions;
    GA.JKSocialTargets = jkSocialTargets;
    GA.AudioTestFailReasons = audioTestFailReasons;
    GA.AudioTestDataReasons = audioTestDataReasons;
    GA.NetworkTestFailReasons = networkTestFailReasons;
    GA.FileDownloadTypes = fileDownloads;
    GA.trackRegister = trackRegister;
    GA.trackDownload = trackDownload;
    GA.trackFTUECompletion = trackFTUECompletion;
    GA.trackNetworkTest = trackNetworkTest;
    GA.trackNetworkTestFailure = trackNetworkTestFailure;
    GA.trackAudioTestCompletion = trackAudioTestCompletion;
    GA.trackAudioTestFailure = trackAudioTestFailure;
    GA.trackAudioTestData = trackAudioTestData;
    GA.trackConfigureTracksCompletion = trackConfigureTracksCompletion;
    GA.trackSessionCount = trackSessionCount;
    GA.trackSessionMusicians = trackSessionMusicians;
    GA.trackSessionQuality = trackSessionQuality;
    GA.trackServiceInvitations = trackServiceInvitations;
    GA.trackFindSessions = trackFindSessions;
    GA.trackJamTrackPlay = trackJamTrackPlay;    
    GA.trackJamTrackPlaySession = trackJamTrackPlaySession;    
    GA.trackFriendConnect = trackFriendConnect;
    GA.trackMakeRecording = trackMakeRecording;
    GA.trackShareRecording = trackShareRecording;
    GA.trackRecordingPlay = trackRecordingPlay;
    GA.trackSessionPlay = trackSessionPlay;
    GA.trackBand = trackBand;
    GA.trackJKSocial = trackJKSocial;
    GA.virtualPageView = virtualPageView;
    GA.trackTiming = trackTiming;
    GA.trackFileDownload = trackFileDownload;
    GA.trackTestDrivePurchase = trackTestDrivePurchase;
    
    context.JK.GA = GA;

})(window,jQuery);