
/**
 Tracker

 Tracks the time the player is in a particular state.
**/

function Tracker() {
    this.startTime = 0;
    this.currentTotal = 0;
}
/* reset to zero and start again */
Tracker.prototype.reset = function () {
    this.startTime = 0;
    this.currentTotal = 0;
};
/* returns current time */
Tracker.prototype.getTime = function () {
    return (new Date()).getTime();
};
/* returns current total */
Tracker.prototype.getCurrentTotal = function () {
    return Math.floor(this.currentTotal / 1000);
};
/* start the timer */
Tracker.prototype.start = function () {
    var rightNow = this.getTime();
    this.startTime = rightNow;
};
/* stop the timer - must track the total time accumulated */
Tracker.prototype.stop = function () {
    var rightNow = this.getTime();
    if (this.startTime > 0) {
        try {
            this.currentTotal += (rightNow - this.startTime);
        }
        catch (e) { }
    }
    this.startTime = 0;
};
/* update the current time and return the up to date total */
Tracker.prototype.update = function () {
    var rightNow = this.getTime();
    if (this.startTime > 0) {
        this.currentTotal += (rightNow - this.startTime);
    }
    this.startTime = rightNow;
    return Math.floor(this.currentTotal / 1000);
};

/**  
VPTracker 
  
Tracks events for a video page and isssues the events to Google
Analytics.
  
Manage Google Analytics for video pages
Assumes ga.js and jquery are loaded.
  
Singleton class - only one per page.
  
Must register accounts (up to 10) to use.
Should also  specify the action and label
to use.
  
To register accounts:
  
VPTracker.addAccount("AccountId");

Event Code:     
0 - Start
1 - Update
2 - Completed
3 - User Abort (unload event caught)
4 - Page Loaded.

6/23/2011 - Kent Johnson (Fluid Consulting)
            
            Add function validdata to ensure duration and playlength
            are reasonable.  Client side hangings are causing large durations
            to be reported.

9/23/2011 - Kent Johnson (Fluid Consulting)

            Add user agent classification.
            Fix setViewKey.

12/29/2011 - Kent Johnson (Fluid Consulting)

            Remove fix for replay.  JWPlayer fixed bugs with rtmp.

**/

// Globals
// Major version of Flash required
var requiredMajorVersion = 10;
// Minor version of Flash required
var requiredMinorVersion = 0;
// Minor version of Flash required
var requiredRevision = 0;
// 

/* Events */
var VPSTART = 0;
var VPUPDATE = 1;
var VPCOMPLETED = 2;
var VPABORT = 3;
var VPPAGELOAD = 4;
var VPERROR = 5;

/* Servers */

var VPWEBSERVER = 0;
var VPFLASHSERVER = 1;
var VPINTERNAPSERVER = 2;



var VPTracker = new function () {

    this.getUID = function () {
        /* return (new Date()).getTime(); */
        return (Math.random() * Math.pow(10, 17) +
               Math.random() * Math.pow(10, 17) +
               Math.random() * Math.pow(10, 17) +
               Math.random() * Math.pow(10, 17));
    };

    this.vpid = 0;
    this.referrer = escape(document.referrer);
    this.userid = "";
    this.url = escape(document.URL);
    this.useragent = "";
    this.tabid = 0;
    this.server = -1;
    this.posturl = "http://www.videoapt.com/Video/StatLogger/tabid/176/Default.aspx";
    //this.posturl = "http://ctmdev.fluid-consulting.com/Video/StatLogger/tabid/176/Default.aspx";
    this.trackers = new Array(10);
    this.nexttracker = 0;
    this.category = "Videos";
    this.action = "";
    this.label = "";
    this.apple = 0;
    this.filenumber = 1;          // Assume first video on page is being played.
    this.flash = 1;               // 1 if flash is being used
    this.mediastart = 0;          // media start recorded indicator
    this.totalstarts = 0;         // number of times a video is watched.
    this.currentevent = -1;       // event to log
    this.intervalcount = 0;       // count onMediaTime Events 
    this.videokey = -1;           // key to identify a single video play
    this.viewkey = this.getUID(); // Key to identify a single page visit 
    this.playlength = 0;          // play time of video INTERNAP AND FLASHSERVER ONLY
    this.errormessage = "";       // error message from player
    this.pageload = 0;            // indictate if the page load has been sent.
    this.playlist = "";           // player player list used to fix replay bug.
    this.replayPauseCount = 0;    // Count plays in REPLAYPAUSE State
    this.forcecrossdomain = 0;    // Use cross domain
    this.INTERVALINITIALMAX = 50; // 5 seconds for first update CONSTANT
    this.INTERVALNORMALMAX = 100; // 10 seconds for normal updates
    this.MAXVIDEOLENGTH = 5400;   // 1.5 hours is the MAXVIDEOLENGTH;
    this.intervalmax = this.INTERVALINITALMAX;
    this.classifiedagent = 0;     // UserAgent classification. Mobile classification only now
    this.setclassifiedagent = 0;  // Non-zero if user agent is classified.

    this.AgentNOTCLASSIFIED = 0;
    this.AgentAPPLE = 100;
    this.AgentANDROID = 200;
    this.AgentWEBOS = 300;
    this.AgentBLACKBERRY = 400;
    this.AgentSYMBIAN = 500;
    this.AgentWINDOWS = 600;

    /* Classify Mobile User Agents */
    this.userAgentType = function () {

        if (this.setclassifiedagent > 0) {
            return this.classifiedagent;
        }

        var agent = navigator.userAgent;
        var result = this.AgentNOTCLASSIFIED;
        this.setclassifiedagent = 1;
        /* Apple */
        if (agent.indexOf("iPhone") != -1 || agent.indexOf("iPad") != -1 || agent.indexOf("iPod") != -1) {
            result = this.AgentAPPLE;
        }
        else if (agent.indexOf("Android") != -1) {
            result = this.AgentANDROID;
        }
        else if (agent.indexOf("webOS") != -1) {
            result = this.AgentWEBOS;
        }
        else if (agent.indexOf("BlackBerry") != -1) {
            result = this.AgentBLACKBERRY;
        }
        else if (agent.indexOf("SymbianOS") != -1) {
            result = this.AgentSYMBIAN;
        }
        else if (agent.indexOf("Windows Phone") != -1) {
            result = this.AgentWINDOWS;
        }

        return result;
    };

    /* time in milliseconds */
    this.getTime = function () {
        return (new Date()).getTime();
    };

    /* ensure the data to be sent is valid; true if ok */
    this.validdata = function (duration) {
        if (duration >= this.MAXVIDEOLENGTH) {
            return false;
        }
        if (this.playlength >= this.MAXVIDEOLENGTH) {
            this.playlength = 0;
        }
        return true;
    };

    this.postUrl = function (event, duration) {

        if (this.validdata(duration)) {
            this.classifiedagent = this.userAgentType();

            qstring = "?VPID=" + this.vpid;
            qstring += "&VideoKey=" + this.videokey;
            qstring += "&ViewKey=" + this.viewkey;
            qstring += "&Event=" + event;
            qstring += "&Buffer=" + this.buffertime.getCurrentTotal();
            qstring += "&Idle=" + this.idletime.getCurrentTotal();
            qstring += "&Pause=" + this.pausetime.getCurrentTotal();
            /*qstring += "&Userid="+ this.userid;*/
            /*qstring += "&Useragent=" + this.useragent;*/
            qstring += "&Apple=" + this.apple;
            qstring += "&QTabid=" + this.tabid;
            qstring += "&Duration=" + duration;
            qstring += "&Server=" + this.server;
            qstring += "&Filenumber=" + this.filenumber;
            qstring += "&Playlength=" + this.playlength;
            qstring += "&UAType=" + this.classifiedagent;
            qstring += "&Url=" + this.url;
            qstring += "&Referrer=" + this.referrer;


            if (this.errormessage.length > 0) {
                qstring += "&Error=" + escape(this.errormessage);
            }

            var urlstring = this.posturl + qstring;
            var asyncindicator = true;
            if (event === VPABORT) {
                asyncindicator = false;
            }
            var cd = false;
            if (this.forcecrossdomain === 1) {
                cd = true;
            }

            try {
                if (cd) {
                   jQuery.ajax({ url: urlstring, dataType: 'jsonp', async: asyncindicator, success: this.doNothing });
                }
                else {
                   jQuery.ajax({ url: urlstring, async: asyncindicator, success: this.doNothing });
                }
            }
            catch (e) {
            }
        }

    };

    this.doNothing = function () {
    };

    /* social media click handling */
    this.postClick = function (socialtypeid, socialtypename) {
        for (i = 0; i < this.nexttracker; i++) {
            this.trackers[i]._trackEvent(
                                        this.category,
                                        this.action,
                                        this.label + ":" + socialtypename, 0);
        }

        qstring = "?VPID=" + this.vpid;
        qstring += "&ViewKey=" + this.viewkey;
        qstring += "&VideoKey=" + this.videokey;
        qstring += "&SocialType=" + socialtypeid;
        qstring += "&SocialName=" + socialtypename;

        var urlstring = this.posturl + qstring;
        var asyncindicator = true;
        jQuery.ajax({ url: urlstring, async: asyncindicator, success: function () { } });

    };



    /* Set functions */
    this.setVpid = function (vpid) {
        this.vpid = vpid;
    };
    this.setReferrer = function (referrer) {
        this.referrer = escape(referrer);
    };
    this.setUserid = function (userid) {
        this.userid = userid;
    };
    this.setUrl = function (url) {
        this.url = escape(url);
    };
    this.setUseragent = function (useragent) {
        this.useragent = escape(useragent);
    };
    this.setApple = function (apple) {
        this.apple = apple;
    };
    this.Tabid = function (tabid) {
        this.tabid = tabid;
    };
    this.setServer = function (server) {
        this.server = server;
    };
    this.setFileNumber = function (filenumber) {
        this.filenumber = filenumber;
    };
    this.setEvent = function (event) {
        this.currentevent = event;
    };
    this.setViewKey = function (key) {
        this.viewkey = key;
    };
    this.getViewKey = function () {
        return this.viewkey;
    };
    this.setForceCrossDomain = function (force) {
        this.forcecrossdomain = force;
    };


    this.addAccount = function (account) {
        try {
            if (account.length > 1) {
                this.trackers[this.nexttracker] = _gat._getTracker(account);
                this.trackers[this.nexttracker]._setDomainName("none");
                this.trackers[this.nexttracker]._trackPageview();
                this.nexttracker++;
            }
        }
        catch (error) { }

    };

    /* Add Multiple accounts variable arguments */
    /* For instance: VP.AddAcounts('1', '2', '3'); */
    this.AddAccounts = function () {
        try {
            for (i = 0; i <= arguments.length; i++) {
                if (arguments[i].length > 1) {
                    this.trackers[this.nexttracker] = _gat._getTracker(arguments[i]);
                    this.trackers[this.nexttracker]._setDomainName("none");
                    this.trackers[this.nexttracker]._trackPageview();
                    this.nexttracker++;
                }
            }
        }
        catch (error) { }
    };

    this.catchExit = function () {
        VPTracker.setEvent(VPABORT);
        VPTracker.onMediaEvent(VPTracker.EventABORT, "");
    };

    /* Initial Log */
    this.pageLoad = function (account) {
        this.setStateMachine();
        try {
            /* allow templates to set variables before player loads */
            VPTrackerPlugin();
        }
        catch (e) {
        }
        this.currentevent = VPPAGELOAD;
        this.classifiedagent = this.userAgentType();
        this.postUrl(this.currentevent, 0);
        this.pageload = 1;
        /* 
        Catch a window close event, runs inside the window object.
        Start time must be recorded.
        */
        window.onbeforeunload = this.catchExit;
    };

    this.setCategory = function (newcategory) {
        this.category = newcategory;
    };

    this.setAction = function (newaction) {
        this.action = newaction;
    };

    this.setLabel = function (newlabel) {
        this.label = newlabel;
    };

    this.setFlash = function (newflash) {
        this.flash = newflash;
    };

    /* send an event to google */
    this.sendToGa = function (cat, action, label, duration) {
        if (this.server > VPWEBSERVER && this.validdata(duration)) {
            for (i = 0; i < this.nexttracker; i++) {
                this.trackers[i]._trackEvent(cat, action, label, duration);
            }
        }
    };



    this.StateREADY = 0;
    this.StateIDLE = 1;
    this.StateBUFFERING = 2;
    this.StatePLAYING = 3;
    this.StatePAUSED = 4;
    this.StateREPLAYPAUSE = 5;

    this.EventIDLE = 1;
    this.EventBUFFER = 2;
    this.EventPLAY = 3;
    this.EventPAUSE = 4;
    this.EventCOMPLETE = 5;
    this.EventTIMER = 6;
    this.EventERROR = 7;
    this.EventABORT = 8;

    this.currentState = this.StateREADY;

    this.playtime = new Tracker();
    this.buffertime = new Tracker();
    this.idletime = new Tracker();
    this.pausetime = new Tracker();

    /* Handle a new event */
    this.onMediaEvent = function (event, lastparameter) {
        /* handle error right away */
        switch (event) {
            case this.EventERROR:
                this.handleError(lastparameter.message);
                break;
            default:
                break;
        }
        /* go to the state handler */
        switch (this.currentState) {
            case this.StateREADY:
                this.processReady(event);
                break;
            case this.StateIDLE:
                this.processIdle(event);
                break;
            case this.StateBUFFERING:
                this.processBuffering(event);
                break;
            case this.StatePLAYING:
                this.processPlaying(event);
                break;
            case this.StatePAUSED:
                this.processPaused(event);
                break;
            case this.StateREPLAYPAUSE:
                this.processReplayPause(event);
                break;
        }
    };

    /* Wrap player functions */
    this.setFullscreen = function () {
        jwplayer().setFullscreen(true);
    };
    this.setPlayList = function () {
        jwplayer().load(this.playlist);
    };
    this.getPlayList = function () {
        return jwplayer().getPlaylist();
    };
    this.getDuration = function () {
        var result;
        try {
            result = jwplayer().getDuration();
            if (result == undefined) {
                result = 0;
            }
            else if (result == null) {
                result = 0;
            }
            else if (result < 0) {
                result = 0;
            }
        }
        catch (e) {
            result = 0;
        }
        return result;
    };
    this.pausePlayer = function () {
        jwplayer().pause();
    };
    this.getAutoStart = function () {
        var result = jwplayer().config.autostart;
        if (result === "true") {
            return true;
        }
        else if (result === "false") {
            return false;
        }
        else {
            return result;
        }
    };

    // Check for initial start
    this.checkStart = function () {
        // Open to fullscreen on mobile devices.        
        this.classifiedagent = this.userAgentType();
        if (this.classifiedagent >= this.AgentAPPLE) {
            this.setFullscreen();
        }

        if (this.mediastart === 0) {
            try {
                this.playlength = Math.floor(this.getDuration());
                if (this.playlength > this.MAXVIDEOLENGTH || this.playlength < 0) {
                    this.playlength = 0;
                }
            } catch (e) { }
            this.totalstarts++;
            this.mediastart = 1;
            this.currentevent = VPSTART;
            this.playlist = this.getPlayList();

            this.postUrl(this.currentevent, VPSTART);
        }
    };

    /* Initialize the machine */
    this.setStateMachine = function () {
        this.playtime.reset();
        this.idletime.reset();
        this.pausetime.reset();
        this.buffertime.reset();
        this.intervalcount = 0;
        this.videokey = this.getUID();
        this.mediastart = 0;
        this.errormessage = "";
        this.currentState = this.StateREADY;
        this.replayPauseCount = 0;
        this.intervalmax = this.INTERVALINITIALMAX;
    };

    /* abort processing is same for all states */
    this.handleAbort = function () {
        if (this.pageload === 1) {
            this.idletime.stop();
            this.buffertime.stop();
            this.pausetime.stop();
            var totalwatchtime = this.playtime.update();
            this.postUrl(VPABORT, totalwatchtime);
            this.sendToGa(this.category, this.action, this.label, totalwatchtime);
            this.setStateMachine();
        }
    };

    /* error processing is same for all states */
    this.handleError = function (error) {
        if (this.pageload === 1) {
            this.errormessage = error;
            this.idletime.stop();
            this.buffertime.stop();
            this.pausetime.stop();
            var totalwatchtime = this.playtime.update();
            this.postUrl(VPERROR, totalwatchtime);
            this.sendToGa(this.category, this.action, this.label, totalwatchtime);
            this.setStateMachine();
            /* Attempt to recover */
            try {
                if (error.indexOf("Could not seek") != -1) {
                    this.playlist = this.getPlayList();
                    this.setPlayList();
                }
            }
            catch (e) {
            }
        }
    };

    /* currentState is READY */
    this.processReady = function (event) {
        switch (event) {
            case this.EventIDLE:
                this.playtime.start();
                this.currentState = this.StateIDLE;
                break;
            case this.EventBUFFER:
                this.buffertime.start();
                this.currentState = this.StateBUFFERING;
                break;
            case this.EventPLAY:
                this.checkStart();
                this.playtime.start();
                this.currentState = this.StatePLAYING;
                break;
            case this.EventPAUSE:
                this.pausetime.start();
                this.currentState = this.StatePAUSED;
                break;
            case this.EventCOMPLETE:
                break;
            case this.EventTIMER:

                break;
        }
    };

    /* currentState is Idle */
    this.processIdle = function (event) {
        switch (event) {
            case this.EventIDLE:
                break;
            case this.EventBUFFER:
                this.idletime.stop();
                this.buffertime.start();
                this.currentState = this.StateBUFFERING;
                break;
            case this.EventPLAY:
                this.checkStart();
                this.idletime.stop();
                this.playtime.start();
                this.currentState = this.StatePLAYING;
                break;
            case this.EventPAUSE:
                this.idletime.stop();
                this.pausetime.start();
                this.currentState = this.StatePAUSED;
                break;
            case this.EventCOMPLETE:
                /* race condition may cause the macine to go idle before complete */
                var totalwatchtime = this.playtime.update();

                this.postUrl(VPCOMPLETED, totalwatchtime);
                this.sendToGa(this.category, this.action, this.label, totalwatchtime);
                this.setStateMachine();
                /* load playlist - fix replay issue 
                   No longer needed RTMP replay issue is fixed. 
                this.setPlayList();
                */
                this.currentState = this.StateREPLAYPAUSE;
                break;
            case this.EventTIMER:
                break;
        }
    };

    this.processBuffering = function (event) {
        switch (event) {
            case this.EventIDLE:
                this.buffertime.stop();
                this.idletime.start();
                this.currentState = this.StateIDLE;
                break;
            case this.EventBUFFER:
                break;
            case this.EventPLAY:
                this.checkStart();
                this.buffertime.stop();
                this.playtime.start();
                this.currentState = this.StatePLAYING;
                break;
            case this.EventPAUSE:
                this.buffertime.stop();
                this.pausetime.start();
                this.currentState = this.StatePAUSED;
                break;
            case this.EventCOMPLETE:
                break;
            case this.EventTIMER:
                break;
            case this.EventABORT:
                this.handleAbort();
                break;
        }
    };

    this.processPlaying = function (event) {
        var totalwatchtime = 0;
        switch (event) {
            case this.EventIDLE:
                this.playtime.stop();
                this.idletime.start();
                this.currentState = this.StateIDLE;
                break;
            case this.EventBUFFER:
                this.playtime.stop();
                this.buffertime.start();
                this.currentState = this.StateBUFFERING;
                break;
            case this.EventPLAY:
                break;
            case this.EventPAUSE:
                this.playtime.stop();
                /* Pause may take some time so update stat log */
                totalwatchtime = this.playtime.getCurrentTotal();
                this.postUrl(VPUPDATE, totalwatchtime);
                this.pausetime.start();
                this.currentState = this.StatePAUSED;
                break;
            case this.EventCOMPLETE:
                this.currentState = this.StateREADY;
                totalwatchtime = this.playtime.update();

                this.postUrl(VPCOMPLETED, totalwatchtime);
                this.sendToGa(this.category, this.action, this.label, totalwatchtime);
                this.setStateMachine();
                /* load playlist - fix replay issue
                   No longer needed since RTMPT replay bug is fixed.
                this.setPlayList();
                */
                this.currentState = this.StateREPLAYPAUSE;

                break;
            case this.EventTIMER:
                this.intervalcount++;
                if (this.intervalcount > this.intervalmax) {
                    if (this.playlength > this.MAXVIDEOLENGTH || this.playlength <= 0) {
                        this.playlength = Math.floor(this.getDuration());
                    }
                    this.intervalmax = this.INTERVALNORMALMAX;
                    this.intervalcount = 0;
                    this.postUrl(VPUPDATE, this.playtime.update());
                }
                break;
            case this.EventABORT:
                this.handleAbort();
                break;
        }
    };


    this.processPaused = function (event) {
        switch (event) {
            case this.EventIDLE:
                this.pausetime.stop();
                this.idletime.start();
                this.currentState = this.StateIDLE;
                break;
            case this.EventBUFFER:
                this.pausetime.stop();
                this.buffertime.start();
                this.currentState = this.StateBUFFERING;
                break;
            case this.EventPLAY:
                this.checkStart();
                this.pausetime.stop();
                this.playtime.start();
                this.currentState = this.StatePLAYING;
                break;
            case this.EventPAUSE:
                break;
            case this.EventCOMPLETE:
                break;
            case this.EventTIMER:
                break;
            case this.EventABORT:
                this.handleAbort();
                break;
        }
    };

    this.processReplayPause = function (event) {
        switch (event) {
            case this.EventIDLE:
                break;
            case this.EventBUFFER:
                break;
            case this.EventPLAY:
                this.replayPauseCount++;
                this.checkStart();
                this.playtime.start();
                this.currentState = this.StatePLAYING;
                /* if autostart false playlist will not autostart so do not pause */
                /* only the flash player has the problem */
                /* No Longer needed  since RTMP now replays
                if (this.replayPauseCount > 1 || this.getAutoStart() === false || this.flash === 0) {
                    this.checkStart();
                    this.playtime.start();
                    this.currentState = this.StatePLAYING;
                }
                else {
                    this.pausePlayer();
                }
                */
                break;
            case this.EventPAUSE:
                break;
            case this.EventCOMPLETE:
                break;
            case this.EventTIMER:
                break;
            case this.EventABORT:
                break;
        }
    };
};

/* Playing*/
function onMediaPlay(event) {
    VPTracker.onMediaEvent(VPTracker.EventPLAY, event);
}
/* Paused */
function onMediaPause(event) {
    VPTracker.onMediaEvent(VPTracker.EventPAUSE, event);
}
/* Buffering */
function onMediaBuffer(event) {
    VPTracker.onMediaEvent(VPTracker.EventBUFFER, event);
}
/* Idle */
function onMediaIdle(event) {
    VPTracker.onMediaEvent(VPTracker.EventIDLE, event);
}
/* Interval while playing */
function onMediaTime(event) {
    VPTracker.onMediaEvent(VPTracker.EventTIMER, event);
}
/* Complete */
function onMediaComplete(event) {
    VPTracker.onMediaEvent(VPTracker.EventCOMPLETE, "");
}
/* Error */
function onMediaError(event) {
    VPTracker.onMediaEvent(VPTracker.EventERROR, event);
}


function socialmediaClick(socialtypeid, socialtypename) {
    VPTracker.postClick(socialtypeid, socialtypename);
}

// Return true if the browser supports the video tag
function supports_video() {
  try {
     return !!document.createElement('video').canPlayType('video/mp4');
  } 
  catch(e) {
     return false;
  }
}


