Source: wtapi.ami.js

/**
 * A plugin that provides Telephony functionality
 *
 * @version 1.1.0
 */
(function(WTAPI) {
    var NS_AMI = "urn:wildix:ami";
    var NS_AMI_DEVICES = "urn:wildix:devices";

    /**
     * Constructor for Telephony plugin.
     * Instance will be created each time when new WTAPI instance is created. <br />
     * Plugin could be accessible thought WTAPI with <b>telephony</b> property.
     *
     * @tutorial telephony-plugin
     * @memberof WTAPI
     * @alias WTAPI.TelephonyPlugin
     * @augments WTAPI.Observer
     * @public
     * @constructor
     */
    function TelephonyPlugin(wtapi) {
        this._calls = [];
        //this._anyDevice = new AnyDevice();*/
        // this._mobilityDevice = new MobilityDevice(); // POSTPONED
        this._devices = [];
        //this._devices.push(this._anyDevice);*/
        // this._devices.push(this._mobilityDevice);  // POSTPONED
        this._wtapi = wtapi;
        this._wtapi.registerHandler("message", this._handleMessage, this, 10);
        this._wtapi.addListener("connected", this._onConnected, this);
        this._wtapi.addListener("disconnected", this._onDisconnected, this);

        // Initialize supper
        WTAPI.Observable.call(this);
    }

    TelephonyPlugin.prototype = Object.create(WTAPI.Observable.prototype);

    // ============================================================
    // Public events
    // ============================================================

    /**
     * Indicates that active devices are changed
     *
     * @event WTAPI.TelephonyPlugin#devices_changed
     * @type {object}
     * @property {Array} devices List of supported devices that are available for current user
     */

    /**
     * Indicates that new call is added
     *
     * @event WTAPI.TelephonyPlugin#call_added
     * @property {WTAPI.TelephonyPlugin.Call} call A call that was added
     */

    /**
     * Indicates that call was updated
     *
     * @event WTAPI.TelephonyPlugin#call_updated
     * @property {WTAPI.TelephonyPlugin.Call} call A call that was updated
     */

    /**
     * Indicates that call was terminated
     *
     * @event WTAPI.TelephonyPlugin#call_terminated
     * @property {WTAPI.TelephonyPlugin.Call} call A call that was terminated
     */

    // ============================================================
    // Public functions
    // ============================================================


    /**
     * @callback TelephonyActionCallback
     * @param {string} error An error message, null when operation is successful
     */

    /**
     * Initiates a call to a specified number using specified device (phone).
     *
     * @param {WTAPI.TelephonyPlugin.Device} device A device from which initiate a call.
     * @param {string} to A number to call to.
     * @param {TelephonyActionCallback} callback
     */
    TelephonyPlugin.prototype.call = function(device, to, callback) {
        var scope = arguments[3] || this;

        /*if (device instanceof AnyDevice) {
            return this.callToAllDevices(to, callback, scope);
        }  else if (device instanceof  MobilityDevice) {
            return this.callToMobility(to, callback, scope);
        } */

        var packet = this._createOriginateUsingReferPacket(device, to);
        var handler = this._proxyIqCallback(callback, scope);
        this._wtapi.getConnection().sendIQ(packet, handler);
    }

    /**
     * Initiates a call to specified number using mobile device.
     * User who initiated a call, should respond to the call, and only then PBX will start call to destination.
     *
     * @param {string} mobile A mobile number.
     * @param {string} to A number to call to.
     * @param {string} lang A user lang default en.
     * @param {TelephonyActionCallback} callback
     */
    TelephonyPlugin.prototype.callToMobility = function(mobile, to, lang, callback) {
        var scope = arguments[4] || this;
        var packet = this._createOriginateUsingMobilityPacket(mobile, to, lang);
        var handler = this._proxyIqCallback(callback, scope);
        this._wtapi.getConnection().sendIQ(packet, handler);
    }

    /**
     * Initiates a call to specified number using all available devices.
     * User who initiated a call, should respond to the call, and only then PBX will start call to destination.
     *
     * @param {string} to A number to call to.
     * @param {TelephonyActionCallback} callback
     */
    TelephonyPlugin.prototype.callToAllDevices = function(to, callback) {
        var scope = arguments[2] || this;
        var packet = this._createOriginateUsingInvitePacket(to);
        var handler = this._proxyIqCallback(callback, scope);
        this._wtapi.getConnection().sendIQ(packet, handler);
    }

    /**
     * Answer a specified incoming call at a specified device.
     * Can be used only when call state in "ring".
     *
     * @param {WTAPI.TelephonyPlugin.Device} device
     * @param {WTAPI.TelephonyPlugin.Call} call
     * @param {TelephonyActionCallback} callback
     */
    TelephonyPlugin.prototype.answer = function(device, call, callback) {
        var scope = arguments[2] || this;
        var packet = this._createAnswerCallPacket(call, device);
        var handler = this._proxyIqCallback(callback, scope);
        this._wtapi.getConnection().sendIQ(packet, handler);
    }

    /**
     * Ends a specified call.
     *
     * @param {WTAPI.TelephonyPlugin.Call} call
     * @param {TelephonyActionCallback} callback
     */
    TelephonyPlugin.prototype.hangup = function(call, callback) {
        var scope = arguments[2] || this;
        var packet = this._createHangUpCallPacket(call);
        var handler = this._proxyIqCallback(callback, scope);
        this._wtapi.getConnection().sendIQ(packet, handler);
    }

    /**
     * Put a specified call on HOLD.
     *
     * @param {WTAPI.TelephonyPlugin.Call} call
     * @param {TelephonyActionCallback} callback
     */
    TelephonyPlugin.prototype.hold = function(call, callback) {
        var scope = arguments[2] || this;
        var packet = this._createHoldPacket(call);
        var handler = this._proxyIqCallback(callback, scope);
        this._wtapi.getConnection().sendIQ(packet, handler);
    }

    /**
     * Resumes a specified call from HOLD.
     *
     * @param {WTAPI.TelephonyPlugin.Call} call
     * @param {TelephonyActionCallback} callback
     */
    TelephonyPlugin.prototype.resume = function(call, callback) {
        var scope = arguments[2] || this;
        var packet = this._createResumePacket(call);
        var handler = this._proxyIqCallback(callback, scope);
        this._wtapi.getConnection().sendIQ(packet, handler);
    }

    /**
     * Performs a blind transfer or call forwarding to a specified number.
     *
     * @param {WTAPI.TelephonyPlugin.Call} call
     * @param {string} to
     * @param {TelephonyActionCallback} callback
     */
    TelephonyPlugin.prototype.forward = function(call, to, callback) {
        var scope = arguments[3] || this;
        var packet = this._createForwardPacket(call, to);
        var handler = this._proxyIqCallback(callback, scope);
        this._wtapi.getConnection().sendIQ(packet, handler);
    }


    /**
     * Performs an attendant transfer with a specified calls.
     *
     * @param {WTAPI.TelephonyPlugin.Call} call1
     * @param {WTAPI.TelephonyPlugin.Call} call2
     * @param {TelephonyActionCallback} callback
     */
    TelephonyPlugin.prototype.bridge = function(call1, call2, callback) {
        var scope = arguments[3] || this;
        var packet = this._createBridgePacket(call1, call2);
        var handler = this._proxyIqCallback(callback, scope);
        this._wtapi.getConnection().sendIQ(packet, handler);
    }

    /**
     * Start recording for a specified call.
     *
     * @param {WTAPI.TelephonyPlugin.Call} call
     * @param {TelephonyActionCallback} callback
     */
    TelephonyPlugin.prototype.startRecord = function(call, callback) {
        var scope = arguments[2] || this;
        var packet = this._createStartRecordPacket(call);
        var handler = this._proxyIqCallback(callback, scope);
        this._wtapi.getConnection().sendIQ(packet, handler);
    }

    /**
     * End record of a specified call.
     *
     * @param {WTAPI.TelephonyPlugin.Call} call
     * @param {TelephonyActionCallback} callback
     */
    TelephonyPlugin.prototype.stopRecord = function(call, callback) {
        var scope = arguments[2] || this;
        var packet = this._createStopRecordPacket(call);
        var handler = this._proxyIqCallback(callback, scope);
        this._wtapi.getConnection().sendIQ(packet, handler);
    }

    /**
     * Returns a list of available calls.
     *
     * @access public
     * @returns {Array}
     */
    TelephonyPlugin.prototype.getActiveCalls = function() {
        return this._calls.slice(0);
    }

    /**
     * Returns a list of available devices (phones).
     *
     * @access public
     * @returns {Array}
     */
    TelephonyPlugin.prototype.getRegisteredDevices = function() {
        return this._devices.slice(0);
    }

    // ============================================================
    // Plugin callbacks
    // ============================================================

    /**
     * @private
     */
    TelephonyPlugin.prototype._onConnected = function() {

    }

    /**
     * @private
     * @fires WTAPI.TelephonyPlugin#devices_changed
     * @fires WTAPI.TelephonyPlugin#call_terminated
     */
    TelephonyPlugin.prototype._onDisconnected = function() {
        // Clean devices
        this._devices = [];
        this._fire("devices_changed", this._devices);

        // Clean calls
        for (var c=0; c < this._calls.length; c++) {
            this._fire("call_terminated", this._calls[c]);
        }
        this._calls = [];
    }

    /**
     * @private
     */
    TelephonyPlugin.prototype._handleMessage = function(message) {
        if (this._handleCallsStateMessage(message)) {
            return true;
        } else if (this._handleDevicesStateMessage(message)) {
            return true;
        }
    }

    /**
     *
     * @private
     * @param message
     */
    TelephonyPlugin.prototype._handleCallsStateMessage = function(message) {
        var event = message.getChild("event", NS_AMI);
        if (event !== null) {
            var type = event.getAttribute("type");
            switch (type) {
                case "new":
                    this._handleCallsAdded(this._parseCallItems(event));
                    break;
                case "update":
                    this._handleCallsUpdated(this._parseCallItems(event));
                    break;
                case "remove":
                    this._handleCallsRemoved(this._parseCallItems(event));
                    break
                case "state":
                    this._handleCallsState(this._parseCallItems(event));
                    break;
            }

            return true;
        }
    }

    /**
     *
     * @param items
     * @private
     * @fires WTAPI.TelephonyPlugin#call_added
     */
    TelephonyPlugin.prototype._handleCallsAdded = function(items) {
        for (var i=0; i < items.length; i++) {
            var call = Call.fromObject(items[i]);
            var duplicate = false;

            for (var c=0; c < this._calls.length; c++) {
                if (this._calls[c].getChannel() == call.getChannel()) {
                    duplicate = true;
                    break;
                }
            }

            if (!duplicate) {
                this._calls.push(call);
                this._fire("call_added", call);
            }
        }
    }

    /**
     *
     * @param items
     * @private
     * @fires WTAPI.TelephonyPlugin#call_updated
     */
    TelephonyPlugin.prototype._handleCallsUpdated = function(items) {
        for (var i=0; i < items.length; i++) {
            var channel = items[i].channel;

            for (var c=0; c < this._calls.length; c++) {
                var call = this._calls[c];

                if (call.getChannel() === channel) {
                    call.updateFromObject(items[i]);
                    this._fire("call_updated", call);
                }
            }
        }
    }

    /**
     *
     * @param items
     * @private
     * @fires WTAPI.TelephonyPlugin#call_terminated
     */
    TelephonyPlugin.prototype._handleCallsRemoved = function(items) {
        for (var i=0; i < items.length; i++) {
            var channel = items[i].channel;
            var filtered = [];

            for (var c=0; c < this._calls.length; c++) {
                var call = this._calls[c];
                if (call.getChannel() !== channel) {
                    filtered.push(call);
                } else {
                	call._hangupCause = items[i].hangupCause;
                    call._hangupCauseText = items[i].hangupCauseText;
                    this._fire("call_terminated", call);
                }
            }

            this._calls = filtered;
        }
    }

    /**
     *
     * @param items
     * @returns {*}
     * @private
     */
    TelephonyPlugin.prototype._handleCallsState = function(items) {
        return this._handleCallsAdded(items);
    }

    /**
     *
     * @param message
     * @returns {boolean}
     * @private
     */
    TelephonyPlugin.prototype._handleDevicesStateMessage = function(message) {
        var event = message.getChild("event", NS_AMI_DEVICES);
        if (event !== null) {
            this._devices = [];
    		var items = event.getElementsByTagName('item');
    		for (var i=0; i<items.length; i++) {
                var device = Device.fromObject(this._parseDeviceItem(items.item(i)));
    			this._devices.push(device);
	        }
            //this._devices.push(this._anyDevice);
            // this._devices.push(this._mobilityDevice); // POSTPONED

            this._fire("devices_changed", this._devices);

    		return true;
		}
    }

    // ============================================================
    // Private functions
    // ============================================================

    /**
     * Generates a call originate command packet
     * @private
     */
    TelephonyPlugin.prototype._createOriginateUsingReferPacket = function(device, to){
        var packet = new JSJaCIQ();
        packet.setType('set');
        var query = packet.setQuery('urn:wildix:ami');
        var originate = packet.getDoc().createElement('originate');
        originate.setAttribute('to', to);
        originate.setAttribute('device', device.getId());
        originate.setAttribute('type', 'refer');
        query.appendChild(originate);

        return packet;
    }

    /**
     * Generates a call originate command packet
     * @private
     */
    TelephonyPlugin.prototype._createOriginateUsingInvitePacket = function(to) {
    	var packet = new JSJaCIQ();
        packet.setType('set');
        var query = packet.setQuery('urn:wildix:ami');
        var originate = packet.getDoc().createElement('originate');
        originate.setAttribute('to', to);
        query.appendChild(originate);

        return packet;
	}

    /**
     * Generates a call originate command packet
     * @private
     */
    TelephonyPlugin.prototype._createOriginateUsingMobilityPacket = function(mobile, to, lang) {
    	if (!lang){
    		lang = 'en';
    	}
    	var packet = new JSJaCIQ();
        packet.setType('set');
        var query = packet.setQuery('urn:wildix:ami');
        var originate  = packet.getDoc().createElement('originate');
        originate.setAttribute('to', to);
        originate.setAttribute('type', 'mobility');
        originate.setAttribute('mobility', mobile);
        originate.setAttribute('lang', lang);
        query.appendChild(originate);

        return packet;
	}

    /**
     * Generates a call answer command packet
     * @private
     */
    TelephonyPlugin.prototype._createAnswerCallPacket = function(call, device) {
    	var packet = new JSJaCIQ().setType('set');
    	var query = packet.setQuery(NS_AMI);
    	var answer  = packet.getDoc().createElement('answer');
    	answer.setAttribute('channel', call.getChannel());
    	answer.setAttribute('device', device.getId());
    	query.appendChild(answer);

    	return packet;
    };

    /**
     * Generates a call hangup command packet
     * @private
     */
    TelephonyPlugin.prototype._createHangUpCallPacket = function(call) {
    	var packet = new JSJaCIQ().setType('set');
    	var query = packet.setQuery(NS_AMI);
    	var hangup  = packet.getDoc().createElement('hangup');
    	hangup.setAttribute('channel', call.getChannel());
    	query.appendChild(hangup);

    	return packet;
    };

    /**
     * Generates a decline call command packet
     * @private
     */
    TelephonyPlugin.prototype._createDeclineCallPacket = function(call) {
	 	var packet = new JSJaCIQ().setType('set');
	 	var query = packet.setQuery(NS_AMI);
	 	var hangup  = packet.getDoc().createElement('hangup');
	 	hangup.setAttribute('channel', call.getChannel());
	 	query.appendChild(hangup);

	 	return packet;
    };

    /**
     * Generates a hold command packet
     * @private
     */
    TelephonyPlugin.prototype._createHoldPacket = function(call) {
	 	var packet = new JSJaCIQ().setType('set');
	 	var query = packet.setQuery(NS_AMI);
	 	var hold  = packet.getDoc().createElement('hold');
	 	hold.setAttribute('channel', call.getChannel());
	 	query.appendChild(hold);

	 	return packet;
    };


    /**
     * Generates a resume command packet
     * @private
     */
    TelephonyPlugin.prototype._createResumePacket = function(call){
	 	var packet = new JSJaCIQ().setType('set');
	 	var query = packet.setQuery(NS_AMI);
	 	var unhold = packet.getDoc().createElement('unhold');
	 	unhold.setAttribute('channel', call.getChannel());
	 	query.appendChild(unhold);

        return packet;
    };

    /**
     * Generates a record start command packet
     * @private
     */
    TelephonyPlugin.prototype._createStartRecordPacket = function(call) {
	 	var packet = new JSJaCIQ().setType('set');
	 	var query = packet.setQuery(NS_AMI);
	 	var record_start  = packet.getDoc().createElement('record-start');
	 	record_start.setAttribute('channel', call.getChannel());
	 	query.appendChild(record_start);

	 	return packet;
    };

    /**
     * Generates a record stop command packet
     * @private
     */
    TelephonyPlugin.prototype._createStopRecordPacket = function(call){
	 	var packet = new JSJaCIQ().setType('set');
	 	var query = packet.setQuery(NS_AMI);
	 	var record_stop  = packet.getDoc().createElement('record-stop');
	 	record_stop.setAttribute('channel', call.getChannel());
	 	query.appendChild(record_stop);

	 	return packet;
    };

    /**
     * Generates a forward command packet
     * @private
     */
    TelephonyPlugin.prototype._createForwardPacket = function(call, to) {
	 	var packet = new JSJaCIQ().setType('set');
	 	var query = packet.setQuery(NS_AMI);
	 	var forward  = packet.getDoc().createElement('forward');
	 	forward.setAttribute('channel', call.getChannel());
	 	forward.setAttribute('to', to);
	 	query.appendChild(forward);

	 	return packet;
    };

    /**
     * Generates a bridge command packet
     * @private
     */
    TelephonyPlugin.prototype._createBridgePacket = function(callFrom, callTo) {
	 	var packet = new JSJaCIQ().setType('set');
	 	var query = packet.setQuery(NS_AMI);

        var bridge = query.appendChild(packet.buildNode('bridge', {xmlns: NS_AMI}));

        bridge.appendChild(packet.buildNode('call', {xmlns: NS_AMI, channel: callFrom.getChannel()}));
        bridge.appendChild(packet.buildNode('call', {xmlns: NS_AMI, channel: callTo.getChannel()}));

	 	return packet;
    };

    /**
     *
     * @param event
     * @returns {Array}
     * @private
     */
    TelephonyPlugin.prototype._parseCallItems = function(event) {
        var items = event.getElementsByTagName("call");
        var calls = [];

        for (var i=0; i < items.length; i++) {
            calls.push(this._parseCallItem(items.item(i)));
        }

        return calls;
    }

    /**
     *
     * @param element
     * @returns {object}
     * @private
     */
    TelephonyPlugin.prototype._parseCallItem = function(element) {
    	var elHangupCause = element.querySelector('hangup-cause');

    	var hangupCause = null;
    	var hangupCauseText = null;

    	if(elHangupCause){
    		hangupCause = elHangupCause.getAttribute('cause'),
    		hangupCauseText = elHangupCause.getAttribute('cause-txt')
    	}
        return {
            channel: element.getAttribute('channel'),
            calleeNumber: element.getAttribute('connected_line_num'),
            calleeName: element.getAttribute('connected_line_name'),
            duration: element.getAttribute('duration'),
            record: element.getAttribute('record'),
            state: element.getAttribute('state'),
            direction: element.getAttribute('direction'),
            destination: element.getAttribute('destination'),
            type: element.getAttribute('type'),
            hangupCause: hangupCause,
            hangupCauseText: hangupCauseText
        }
    }

    /**
     *
     * @param element
     * @returns {object}
     * @private
     */
    TelephonyPlugin.prototype._parseDeviceItem = function(element) {
        return {
            id: element.getAttribute('id'),
            name: element.getAttribute('name')
        }
    }

    /**
     *
     * @param callback
     * @param scope
     * @returns {{error_handler: Function, result_handler: Function}}
     * @private
     */
    TelephonyPlugin.prototype._proxyIqCallback = function(callback, scope) {
        return {
            error_handler: function(iq) {
                var node = iq.getNode();
                var errors = node.getElementsByTagName("error");
                var reason = "unknown";

                if (errors.length > 0) {
                    var error = errors[0];
                    var type = error.firstChild;
                    if (type) {
                        reason = type.tagName;
                    }
                }

                callback.call(scope, reason);
            },
            result_handler: function() {
                callback.call(scope, null);
            }
        }
    }

    // ============================================================
    // Extra classes
    // ============================================================

    /**
     *
     *
     * @memberof WTAPI.TelephonyPlugin
     * @alias WTAPI.TelephonyPlugin.Device
     * @public
     * @constructor
     */
    function Device(id, name) {
        var formattedName = name;
        var match;
        if (match = name.match(/^Wildix (WP\d+) ((\d+\.)+\d+).*?$/i)) {
            formattedName = match[1]; // WP490, WP500, WP600, ...
        } else if (match = name.match(/^Wildix (W-AIR) ((\d+\.)+\d+).*?$/i)) {
            formattedName = match[1]; // W-AIR
        }else if(match = name.match(/^Wildix (Zero Distance) ((\d+\.)+\d+).*?$/i)){
            formattedName = match[1]; // Zero Distance
        }

        /**
         * Returns unique id of current device
         *
         * @public
         * @returns {string}
         */
        this.getId = function() {
            return id;
        }

        /**
         * Returns a well formatted device name
         *
         * @public
         * @returns {string}
         */
        this.getName = function() {
            return formattedName;
        }

        /**
         * Gets a User Agent that device is send
         *
         * @public
         * @returns {string}
         */
        this.getUserAgent = function() {
            return name;
        }
    }


    /**
     * Creates a new Device using json object
     *
     * @param {object} params
     * @private
     * @returns {Device}
     */
    Device.fromObject = function(params) {
        return new Device(params.id, params.name);
    }

    /*
    function AnyDevice() {

        /**
         *
         * @public
         * @returns {string}

        this.getId = function() {
            return "any"
        }

        /**
         *
         * @public
         * @returns {string}

        this.getName = function() {
            return "Any device";
        }
    }

    function MobilityDevice() {
        this.getId = function() {
            return "mobility"
        }
        this.getName = function() {
            return "Mobility";
        }
    }
    */

    /**
     *
     * @memberof WTAPI.TelephonyPlugin
     * @alias WTAPI.TelephonyPlugin.Call
     * @public
     * @constructor
     */
    function Call(channel, calleeNumber, calleeName, duration, record, state, direction, destination, type) {
        this._calleeNumber = calleeNumber;
        this._calleeName = calleeName;
        this._duration = parseInt(duration);
        this._durationTime = Math.round(new Date().getTime() / 1000);
        this._record = record;
        this._state = state;
        this._channel = channel;
        this._destination = destination;
        this._type = type;
        this._hangupCause = null;
        this._hangupCauseText = null;
        // Hide direction properties

        this.getDirection = function() {
            return direction;
        }
    }



    Call.fromObject = function(o) {
        return new Call(o.channel, o.calleeNumber, o.calleeName, o.duration, o.record, o.state, o.direction, o.destination, o.type);
    }

    /**
     * @private
     */
    Call.prototype.updateFromObject = function(o) {
        this._calleeNumber = o.calleeNumber;
        this._calleeName = o.calleeName;
        this._duration = parseInt(o.duration);
        this._durationTime = Math.round(new Date().getTime() / 1000);
        this._record = o.record;
        this._state = o.state;
        this._destination = o.destination;
        this._type = o.type;
        this._hangupCause = o.hangupCause;
        this._hangupCauseText = o.hangupCauseText;
    }

    /**
     * Returns a channel of call
     *
     * @public
     * @returns {string}
     */
    Call.prototype.getChannel = function() {
        return this._channel;
    }

    /**
     * Returns a destination channel of call
     *
     * @public
     * @returns {string}
     */
    Call.prototype.getDestinationChannel = function() {
        return this._destination;
    }

    /**
     * Returns a type of call
     *
     * @public
     * @returns {string}
     */
    Call.prototype.getType = function() {
        return this._type;
    }

    /**
     * Returns a duration of call in seconds.
     *
     * @public
     * @returns {int}
     */
    Call.prototype.getDuration = function() {
        var time = Math.round(new Date().getTime() / 1000);
        var offset = time - this._durationTime;
        return this._duration + offset;
    };

    /**
     * Returns a duration in "MM:SS" format.
     *
     * @public
     * @returns {string}
     */
    Call.prototype.getFormattedDuration = function() {
        var seconds = this.getDuration();
        if (isNaN(seconds)) {
            return "00:00";
        }
        var hours = parseInt( seconds / 3600 ) % 24;
        var minutes = parseInt( seconds / 60 ) % 60;
        var result = "";
        seconds = seconds % 60;

        if (hours > 0) {
            result += (hours < 10 ? "0" + hours : hours) + ":";
        }

        result += (minutes < 10 ? "0" + minutes : minutes) + ":" + (seconds  < 10 ? "0" + seconds : seconds);
        return result;
    };

    /**
     * Returns the full name of the other participant.
     * Can be empty string when name is not available.
     *
     * @public
     * @returns {string}
     */
    Call.prototype.getCalleeName = function() {
        return this._calleeName;
    }

    /**
     * Returns the phone number of the other participant.
     *
     * @public
     * @returns {string}
     */
    Call.prototype.getCalleeNumber = function() {
        return this._calleeNumber;
    }

    /**
     * Returns a participant name in format "NAME (NUMBER)" or "NUMBER" when name is not available.
     *
     * @public
     * @returns {string}
     */
    Call.prototype.getFormattedCalleeName = function() {
        if (this._calleeName.length > 0) {
            return this._calleeName + "("+ this._calleeNumber +")";
        }

        return this._calleeNumber;
    }

    /**
     * Returns a state of a call.
     * Possible states are: ring, hold, up.
     * ring - when call is not answered.
     * hold - when call is on hold.
     * up - when call is answered and not on a hold.
     *
     * @public
     * @returns {string}
     */
    Call.prototype.getState = function() {
        return this._state;
    }

    /**
     * Returns the human-readable state of a call.
     * Possible returns values are: Ringing, Paused, Connected.
     *
     * @public
     * @returns {string}
     */
    Call.prototype.getFormattedState = function() {
        switch (this._state) {
            case "ring":
                return "Ringing";
            case "hold":
                return "Paused";
            case "up":
                return "Connected";
        }
    }

    /**
     * Returns true if this call is incoming.
     *
     * @public
     * @returns {boolean}
     */
    Call.prototype.isIncoming = function() {
        return this.getDirection() == "incoming";
    }

    /**
     * Returns true if this call is outgoing.
     *
     * @public
     * @returns {boolean}
     */
    Call.prototype.isOutgoing = function() {
        return this.getDirection() == "outgoing";
    }

    /**
     * Returns true if this call are recorded.
     *
     * @public
     * @returns {boolean}
     */
    Call.prototype.isRecorded = function() {
        return this._record == "on";
    }

    /**
     *  Get a list of records files
     *
     * @public
     * @param {function} successCallback
     * @param {function} errorCallback
     */
    Call.prototype.getRecordedFiles = function(successCallback, errorCallback) {
    	successCallback = successCallback || function(){};
    	errorCallback = errorCallback || function(){};

    	var channel = this.getChannel();
		if(this.isIncoming()){
			channel = this.getDestinationChannel();
    	}
		if(channel && channel != ''){
			WTAPI.ajax({
	    		url: '/api/v1/Calls/'+encodeURIComponent(channel)+'/Recordings/',
	    		type: 'GET',
	    		success: function(data, textStatus, jqXHR){
	    			if(data.type == 'result' && data.result && data.result.records){
	    				successCallback(this, data.result.records);
	    			}
	    		}.bind(this),
	    		error: function(jqXHR, textStatus, data){
	    			if(jqXHR.status != 404){
	    				var error = jqXHR.statusText;
	    				if(jqXHR && jqXHR.responseText){
	    		        	try {
	    		        		var response = JSON.parse(jqXHR.responseText);
	    		        		if(response['type'] && response['type'] == 'error'){
	    		        			errorCallback(this, response['reason'])
	    		                }
	    					} catch (e) {
	    						errorCallback(this, e.message);
	    					}
	    		        }
	    			}else{
	    				errorCallback(this, jqXHR.statusText);
	    			}
	    		}.bind(this)
	    	});
		}
    }

    /**
     * Returns true if this call are in "ring" state (not answered yet).
     *
     * @public
     * @returns {boolean}
     */
    Call.prototype.isRinging = function() {
        return this._state == "ring";
    }

    /**
     * Returns true if this call are on hold.
     *
     * @public
     * @returns {boolean}
     */
    Call.prototype.isOnHold = function() {
        return this._state == "hold";
    }

    /**
     * Returns a hangup cause of a call.
     *
     * @public
     * @returns {string}
     */
    Call.prototype.getHangupCause = function() {
        return this._hangupCause;
    }

    /**
     * Returns a hangup cause text of a call.
     *
     * @public
     * @returns {string}
     */
    Call.prototype.getHangupCauseText = function() {
        return this._hangupCauseText;
    }

    WTAPI.addPlugin("telephony", TelephonyPlugin);
}(WTAPI));