﻿// Live Chat Scripts.  Image and URL swapping based on availability image provided by InstantService.

// Redo of smartbuttons and caching.
// P. Rutins 2011

// Container object has a list of unique departments.
// Department object holds data for checking and saving availability, and caching.
// SmartButton object is used on the page to hook together with HTML elements.

var LiveChatDepartments = new Array(); // Container object
LiveChatDepartments.findDepartment = function (ai, di) {
    var lcd;
    if (ai > 0 && di > 0) {
        lcd = this.find(function (department) {
            return (department.ai == this.find_ai && department.di == this.find_di);
            }, { find_ai: ai, find_di: di });
        if (lcd) { return lcd; }
    }
    return null;
}
LiveChatDepartments.available = function (ai, di) {
    var lcd = this.findDepartment(ai, di);
    if (lcd) { return lcd.available; }
}
LiveChatDepartments.check = function (ai, di, callback) {
    var lcd = this.findDepartment(ai, di);
    if (lcd) { return lcd.detectAvailability(callback); }
}
LiveChatDepartments.updateCache = function (ai, di, callback) {
    var lcd = this.findDepartment(ai, di);
    if (lcd) { return lcd.updateCache(callback); }
}
// use: LiveChatDepartments.createDepartment([AI], [DI], '[path]', [default availability], [polling interval, in seconds]);
// AI: Instant Service Account ID 
// DI: Instant Service Department ID 
// path: hostname and path to smartbutton image (uses a standard default if null - ordinarily you will not need anything else.)
// default availability: should the department show as open or closed before it has checked?
// polling interval: how often the department should check the path to the smartbutton image to see if the department is available - in seconds.
LiveChatDepartments.createDepartment = function (ai, di, path, available, updateInterval, updateServer) {
    var lcd = this.findDepartment(ai, di);
    if (!lcd) {
        lcd = new LiveChatDepartment(ai, di, path, available, updateInterval, updateServer);
        this.push(lcd);
    }
    return lcd;
}
LiveChatDepartments.activateDepartment = function (ai, di, lc_department, updateInterval, callback, initial_callback) {
    var lcd = (lc_department ? lc_department : this.findDepartment(ai, di));
    if (!lcd) { return 'please create a department first.'; }
    return lcd.activateDepartment(initial_callback, callback);
}
LiveChatDepartments.deactivateDepartment = function (ai, di, department) {
    var lcd = (lc_department ? lc_department : this.findDepartment(ai, di));
    if (lcd) { lcd.deactivateDepartment(); }
    return lcd;
}
LiveChatDepartments.activateAll = function (global_callback) {
    LiveChatDepartments.each(function (lcd) {
        // use service callbacks
        var initial_callback = null;
        if (lcd.callbackServer) {
            initial_callback = lcd.callbackService.bindAsEventListener(lcd);
        }
        return lcd.activateDepartment(initial_callback, global_callback);
    });
}
// Activate all departments on page load.
Event.observe(window, "load", LiveChatDepartments.activateAll);

/*** LiveChatDepartment object - contains all the info necessary to send availability back to the server, if necessary. ***

use: var d = LiveChatDepartments.createDepartment([department AI], [department DI], [path to available.gif], [current status], [milliseconds], [update server cache, true|false]);
var d = LiveChatDepartments.createDepartment(5657, 10642, 'admin.instantservice.com/resources/smartbutton/5657/10642', true, 15000, true);
// create a department to update every 15 seconds.
*******************************************/
var LiveChatDepartment = function (AI, DI, Path, available, updateInterval, updateServer) {
    this.ai = (AI || '5657');
    this.di = (DI || '10642');
    this.path = (Path || 'admin.instantservice.com/resources/smartbutton');
    this.available = (available && true);
    this.updateInterval = updateInterval;
    this.updating = null;
    this.callbackServer = updateServer; // boolean - should we call the server?
    var hasCalledServer = false; // has this been saved back to the server?

    /* department detects its availability by looking for available.gif */
    /* https://admin.instantservice.com/help/setup/advancedsmartbutton_help.html */
    this.detectAvailability = function (callback) {
        var onload = function (type, target, width, height) {
            if (!this.chatDept.available) {
                this.chatDept.available = true;
                $(document).fire("chat:" + this.chatDept.di.toString());
            };
            if (typeof (callback) == 'function') { callback(this.chatDept); }
        };
        var onerror = function (type, target, width, height) {
            if (this.chatDept.available) {
                this.chatDept.available = false;
                $(document).fire("chat:" + this.chatDept.di.toString());
            }
            if (typeof (callback) == 'function') { callback(this.chatDept); }
        };
        var i = new Image();
        i.chatDept = this;
        i.onload = onload;
        i.onerror = onerror;
        i.onabort = onerror;
        i.src = 'https://' + this.path + '/' + this.ai + '/' + this.di + '/available.gif?' + Math.floor(Math.random() * 10001);
    };

    this.createSmartbutton = function (controlID, queue_di) {
        if (!controlID) { return 'please specify a controlID.'; }
        if (!queue_di) { queue_di = this.di; }
        var sb = new LiveChatSmartbutton(this.ai, this.di, queue_di, controlID);
        sb.initialize();
        return sb;
    };

    /**** server callbacks ****/

    this.callbackPage = function (controlID) {
        if (hasCalledServer) { return false; }
        // this callback uses the prototype library's Ajax.Request instead of all the MS bloat libraries.    
        // it does require a runat="server" form on the page.  This function is not typically used, use the callbackService instead.
        callMeBack((this.available ? 'available' : 'unavailable'), controlID, ReceiveServiceData, ProcessError);
        hasCalledServer = true; // only call once per page per department.  We don't care if there's an error.
        return true;
    };

    /* use a callback to the LiveChatService.  Once required a scriptmanager on the page, no longer.
    <asp:ScriptManager runat="server"><Services><asp:ServiceReference path="../services/LiveChatService.asmx"></asp:ServiceReference></Services></asp:ScriptManager> 
    We can get away without using a ScriptManager, but if we want to use this we still need the basic callback library from MS. (http://www.orvis.com/LiveChatService/js).  This is only required if we need to get object definitions from the web service.  In this case, the call is simple enough that we can build the JSON object by hand to pass it to the service.
    */
    this.callbackService = function () {
        if (hasCalledServer) { return false; }
        hasCalledServer = true; // only call once per page per department.  We don't care if there's an error.
        // this callback calls the LiveChatService to notify the application of the availability status of the chat department.
        // with the addition of the LiveChatDepartments object, we no longer need to direct a callback to a particular control.  It should come to the department,
        // which fires the event to update all controls on the page.  Since that's already been done, though, there's no need for the returned data.
        var svcArgs = { 'AI': this.ai, 'DI': this.di, 'Available': this.available };
        callSOAPService('/services/LiveChatService.asmx', 'http://www.orvis.com/LiveChatService', 'SetAvailability', '', svcArgs, ReceiveServiceData, ProcessError);
        // We don't really care about the returned value, since we've already done the display changes needed.
        // If we do, we can pass in an onSuccess function and an onError function.
        return true;
    };

    /**** get this department started and stopped ****/
    this.activateDepartment = function (initial_callback, callback) {
        if (!this.updating) {
            this.detectAvailability(initial_callback);

            if (this.updateInterval > 0) {
                this.updating = new PeriodicalExecuter(function () { this.detectAvailability(callback); } .bindAsEventListener(this), this.updateInterval);
                //window.setInterval(d.detectAvailability, d.updateInterval);
            }
        }
        return this;
    }

    this.deactivateDepartment = function () {
        if (this.updating) { this.updating.stop(); }
        return this;
    }

};

/*** Smartbutton Object ***

use: var x = new LiveChatSmartbutton([department AI], [department DI], [element ID prefix]); 
var x = new LiveChatSmartbutton(5657, 10642, 'LeftNavLiveChatButton'); // create a new button;
***************************/

var LiveChatSmartbutton = function (ai, di, queue_di, controlID) {
    this.ai = ai;
    this.di = di;
    this.queue_di = queue_di;
    this.controlID = controlID;
    this.chatDepartment = LiveChatDepartments.findDepartment(ai, di);
    this.queueDepartment = LiveChatDepartments.findDepartment(ai, queue_di);

    this.initialize = function () {
        // update display on change of status
        Event.observe(document, "chat:" + this.di.toString(), this.showAvailability.bindAsEventListener(this));
        Event.observe(document, "chat:" + this.queue_di.toString(), this.showAvailability.bindAsEventListener(this));
        // display initial status -- if we get out of sync, we might not get back in for a while.
        this.showAvailability();
    };

    this.showAvailability = function () {
        //alert('button: ' + this.chatDepartment.available + ' queue: ' + this.queueDepartment.available);
        if (!this.chatDepartment) { this.close(); }
        if (this.chatDepartment.available) {
            this.open();
        } else {
            // busy status = if availability department is closed but queue is open.
            if (!this.queueDepartment) { this.close(); }
            else {
                if (this.queueDepartment.available) { this.setBusy(); }
                else { this.close(); }
            }
        }
    };

    var openID = '_InstantServiceOpen';
    var busyID = '_InstantServiceBusy';
    var closedID = '_InstantServiceClosed';
    var inputID = '_chat_available';

    this.open = function () {
        var a = $(this.controlID + openID); if (a) { a.style.display = 'inline'; }
        var u = $(this.controlID + busyID); if (u) { u.style.display = 'none'; }
        var c = $(this.controlID + closedID); if (c) { c.style.display = 'none'; }
        var i = $(this.controlID + inputID); if (i) { i.value = 'open'; }
    };

    this.setBusy = function () {
        var a = $(this.controlID + openID); if (a) { a.style.display = 'none'; }
        var u = $(this.controlID + busyID); if (u) { u.style.display = 'inline'; }
        var c = $(this.controlID + closedID); if (c) { c.style.display = 'none'; }
        var i = $(this.controlID + inputID); if (i) { i.value = 'busy'; }
    };

    this.close = function () {
        var a = $(this.controlID + openID); if (a) { a.style.display = 'none'; }
        var u = $(this.controlID + busyID); if (u) { u.style.display = 'none'; }
        var c = $(this.controlID + closedID); if (c) { c.style.display = 'inline'; }
        var i = $(this.controlID + inputID); if (i) { i.value = 'closed'; }
    };
}

// Update cache and database with callback to WebService.
// P. Rutins 2007

/* use an in-page callback. Not currently used, but works. */
function ReceivePartialPageData(rValue) {
    var ret = rValue.split('|');
    if (ret.length > 1) {
        var c = $(ret[1]);
        if (c) { c.innerHTML = ret[2]; }
    } else { ProcessError(ret[0]); }
};
/* used to receive data back from the live chat service. */
function ReceiveServiceData(rValue) {
    //alert(rValue);
};
function ProcessError(errText) {   //alert(errText);
    // do nothing with it. 
};

function loadLiveChatService(obj) {
    if (typeof (LiveChatService) == 'undefined') {
        var s = document.createElement('script');
        var h = document.getElementsByTagName('head').item(0);
        s.type = 'text/javascript';
        //if (document.implementation.hasFeature("HTMLEvents", "2.0")) { // Mozilla
        //    s.addEventListener("load", function(){ alert('Event Listener Fired'); alert(typeof(LiveChatService)); }, false);
        //} else {
        s.onreadystatechange = function () { // IE/Safari
            //alert(this.readyState);
            if (this.readyState === 'loaded') {
                obj.callbackService(); //alert(typeof(LiveChatService));
            } 
        };
        s.onload = function () {
            obj.callbackService(); // alert(typeof(LiveChatService)); 
        };
        s.src = '/services/LiveChatService.asmx/js';
        h.appendChild(s);
    } else {
        obj.callbackService();
    }
}

/*******************************************/

/* LEGACY -- Search and replace all instances that use this code!
//
// For smartbuttons that cannot use the .NET control. Load in content to the smartbutton div
function showSmartButton(useContent) {
if (useContent) {
useContent.style.display = 'inline';
return true;
} 
}

// For smartbuttons that cannot use the .NET control. Detect using the smartbutton image -- based on code provided by InstantService 5/2/07
// https://admin.instantservice.com/help/setup/advancedsmartbutton_help.html
function InstantServiceSmartButton1(ai, di, department) {
// requires divs named '_InstantServiceAvailable' instead of 'InstantServiceAvailable'.
new LiveChatDepartment('', ai, di, department, 'admin.instantservice.com/resources/smartbutton', '', '', false);
};

function InstantServiceSmartButton(ai, di) {
var a = document.getElementById('InstantServiceAvailable');
a.style.display = 'none';
var u = document.getElementById('InstantServiceUnavailable');
u.style.display = 'none';
var i = new Image();
i.onload = function () { showSmartButton(a); };
i.onerror = function () { showSmartButton(u); };
//alert('http://' + path + '/available.gif');
i.src = 'http://admin.instantservice.com/resources/smartbutton/' + ai + '/' + di + '/available.gif?' + Math.floor(Math.random() * 10001);
}

*/
// LEGACY CODE FOR BACKWARD COMPATIBILITY ONLY! REMOVE ASAP! MAY 2011
function InstantServiceSmartButton(ai, di) {
    var a = document.getElementById('InstantServiceAvailable');
    a.id = 'old_InstantServiceOpen';
    var u = document.getElementById('InstantServiceUnavailable');
    u.id = 'old_InstantServiceClosed';

    var d = LiveChatDepartments.createDepartment(ai, di, null, 1, 25, null);
    d.createSmartbutton('old');
}

// KEEP THIS FOR USE IN Smartbutton DIVs.
var ChatWindow = null;
function ShowChatWindow(height, width, url) {
    if (url.charAt(url.length - 1) == "=") { }
    else if ((url.charAt(url.length - 1) == "&") || (url.lastIndexOf("&amp;") == url.length - 5)) { url += "qs="; }
    else { url += "&qs="; }
    ChatWindow = window.open(url + escape(document.location), 'custclient', 'scrollbars=0,left=1, top=1,width=' + width + ',height=' + height);
    FocusChat();
}

function FocusChat() {
    if (ChatWindow != null) {
        ChatWindow.focus();
    }
}

function ShowWindow(height, width, url) {
    var nw = window.open(url, 'OrvisHelpWindow_', 'toolbar=no,location=0,directories=no,status=no,menubar=0,scrollbars=yes,resizable=1,copyhistory=0,left=1,top=1,width=' + width + ',height=' + height); if (nw) { nw.focus(); }
};

/* -- use the following HTML code in a subject page for a smartbutton that doesn't use the control.
<!-- <dd>For even faster response, try our Live Chat.</dd> -->
<script language="JAVASCRIPT" type="text/javascript" src="/ClientSideScripts/Prototype.js"></script>
<script language="JAVASCRIPT" type="text/javascript" src="/ClientSideScripts/LiveChat.js"></script>
<div id="cschat_InstantServiceAvailable" style="display:none;">
<b>For even faster response, try our Live Chat!</b>
<div class="dd">Our Orvis Customer Service Team can provide immediate online assistance for questions relating to placing orders, Orvis products, and website navigation, just to name a few.  <b><a onclick="ShowChatWindow(320, 500, '/store/instant_service_chat.aspx?ai=5657&amp;di=10642'); return false;" href="">Orvis Live Chat</a></b> is available everyday, 8 a.m. through 11 p.m. ET.
</div>
</div>
<div id="cschat_InstantServiceUnavailable" style="display:none;">
<b>For even faster response, try our Live Chat!</b>
<div class="dd">Our Orvis Customer Service Team can provide immediate online assistance for questions relating to placing orders, Orvis products, and website navigation, just to name a few.  <b><a onclick="ShowWindow(550, 750, '/intro_newwindow.asp?subject=1308'); return false;" href="">Orvis Live Chat</a></b> is available everyday, 8 a.m. through 11 p.m. ET.</div>				
</div>
<script language="javascript" type="text/javascript">
    // this sets up a department that can update itself every 30 seconds on the page.
    var cs_dept = LiveChatDepartments.createDepartment(5657, 10642, 'default', null, 0, 30);
    // this creates a smartbutton that looks at the above department.
    var cs_smartbutton = cs_dept.createSmartbutton("cschat");
    // you could create a second smartbutton on the page like so, which would also show the availability of the same department:
    // var cs_smartbutton_2 = cs_dept.createSmartbutton("cschat_button2")
    // and you would need to have DIV elements named "cschat_button2_InstantServiceAvailable" and "cschat_button2_InstantServiceUnavailable".

    // this detects the department's availability once.
    cs_dept.detectAvailability();
    // this tells the department to check its availability, according to the interval you set above (30 seconds).
    LiveChatDepartments.activateDepartment(5657, 10642, cs_dept);
    // When the department updates, all smartbuttons created for it will update their displays.
</script>
*/

if (typeof (Sys) !== 'undefined') Sys.Application.notifyScriptLoaded();
