Source: plugins/wtapi.telephony.js

import WTAPI from "../wtapi";
import {JSJaCIQ} from '../jsjac';

/**
 * A plugin that provides Telephony functionality
 *
 * @version 1.1.0
 */
const NS_AMI = "urn:wildix:ami";
const 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) {
        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) {
        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;
}

export default TelephonyPlugin;