Source: managers/channel.js

define('application/managers/channel', [
    'antie/class',
    'rofl/lib/utils',
    'application/managers/epg',
    'antie/runtimecontext',
    'antie/storageprovider',
    'application/managers/api',
    'application/models/configuration'
], function (
    Class,
    Utils,
    EPGManager,
    RuntimeContext,
    StorageProvider,
    ApiManager,
    ApiConfig
) {
    'use strict';

    var CHANNEL_STORAGE = 'kpn-channel',
        instance,
        device,
        epgManager,
        storage,
        api,
        ChannelManager;

    ChannelManager = Class.extend({

        /**
         * Initialises the channel manager.
         */
        init: function () {
            this._channels = [];
            device = RuntimeContext.getDevice();
            epgManager = EPGManager.getInstance();
            storage = device.getStorage(StorageProvider.STORAGE_TYPE_PERSISTENT, CHANNEL_STORAGE);
            api = ApiManager.getKPNAPI();
        },

        /**
         * Loads the channels from API and sets them in the manager.
         *
         * @returns {Promise} - Promise resolving with the channels.
         */
        load: function () {
            return api.read('channels', {
                params: {
                    channels: ApiConfig.getChannels()
                },
                withCredentials: true
            }).then(Utils.bind(function (channels) {
                this.setChannels(channels);

                return channels;
            }, this));
        },

        /**
         * Returns the channels.
         *
         * @returns {Array} - The channels.
         */
        getChannels: function () {
            return this._channels;
        },

        /**
         * Sets the channels.
         *
         * @param {Array} channels - The channels.
         */
        setChannels: function (channels) {
            var channelMap = [];

            this._channels = channels;

            channels.sort(function (a, b) {
                return a.getNumber() > b.getNumber() ? 1 : -1;
            });

            Utils.each(channels, function (channel) {
                channelMap.push(channel.getId());
            });

            this._channelMap = channelMap;
        },

        /**
         * Returns the last watched channel id.
         *
         * @returns {number} - The last watched channel id.
         */
        getLastWatchedChannel: function () {
            return storage.getItem('last-watched-channelid');
        },

        /**
         * Sets the last watched channel.
         *
         * @param {number} channelId - The last watched channel id.
         */
        setLastWatchedChannel: function (channelId) {
            storage.setItem('last-watched-channelid', channelId);
        },

        /**
         * Gets a channel by ID.
         *
         * @param {string} id - The channel ID you want.
         * @returns {Object|null} - The channel or null if not found.
         */
        getChannelById: function (id) {
            var channel = Utils.filter(this._channels, function (channelModel) {
                return channelModel.getId().toString() === id.toString();
            });

            if (channel.length > 0) {
                return channel[0];
            }

            return null;
        },

        /**
         * Returns the next channel.
         *
         * @param {Object} channel - The channel to locate the next for.
         * @returns {Object|null} - The next channel or null if not found.
         */
        getNextChannel: function (channel) {
            var channels = this.getChannels(),
                channelIndex;

            if (!channels || !channel) {
                return null;
            }

            channelIndex = Utils.map(channels, function (current) {
                return current.getNumber();
            }).indexOf(channel.getNumber());

            if (channelIndex === -1) {
                return null;
            }

            /*
             * The current channel is the last channel.
             * Return the first channel.
             */
            if (channelIndex === channels.length - 1) {
                return channels[0];
            }

            return channels[channelIndex + 1];
        },

        /**
         * Returns the previous channel.
         *
         * @param {Object} channel - The channel to locate the previous for.
         * @returns {Object|null} - The previous channel or null if not found.
         */
        getPreviousChannel: function (channel) {
            var channels = this.getChannels(),
                channelIndex;

            if (!channels || !channel) {
                return null;
            }

            channelIndex = Utils.map(channels, function (current) {
                return current.getNumber();
            }).indexOf(channel.getNumber());

            if (channelIndex === -1) {
                return null;
            }

            /*
             * The current channel is the first channel.
             * Return the last channel.
             */
            if (channelIndex === 0) {
                return channels[channels.length - 1];
            }

            return channels[channelIndex + -1];
        },

        /**
         * Returns the channel by number, or the closest channel.
         *
         * @param {number} number - The number.
         * @returns {Object|null} - The channel or the closest channel or null if not found.
         */
        getChannelByNumber: function (number) {
            var channels = this.getChannels().slice(0);

            if (!channels) {
                return null;
            }

            return channels.sort(function (a, b) {
                return Math.abs(a.getNumber() - number) - Math.abs(b.getNumber() - number);
            }).shift();
        },

        /**
         * Returns the current broadcast for the given channel.
         *
         * @param {number|string} channelId - The channel id.
         * @returns {Promise} - Promise resolving with the current item.
         */
        getCurrentBroadcastForChannel: function (channelId) {
            var currentItem;

            return epgManager.getCurrentItem([channelId])
                .then(Utils.bind(function (item) {
                    currentItem = item[channelId];

                    return currentItem;
                }, this));
        },

        /**
         * Returns the broadcast at the given time.
         *
         * @param {string} channelId - The channel id.
         * @param {number} time - The time of the broadcast.
         * @returns {Promise} - Promise resolving with the broadcast item.
         */
        getBroadcastAtTime: function (channelId, time) {

            return epgManager.getItem(channelId, time / 1000)
                .then(function (items) {
                    return items[channelId].item;
                });
        },

        /**
         * Returns the next item of broadcast at the given time.
         *
         * @param {number} channelId - The channel id.
         * @param {number} time - The time of the broadcast.
         * @returns {Promise} - Promise resolving with the next item of broadcast item.
         */
        getNextBroadcastAtTime: function (channelId, time) {
            return epgManager.getItem(channelId, time)
                .then(function (items) {
                    return items[channelId].next;
                });
        },

        /**
         * Returns the channel map.
         *
         * @param {number} [start] - Optional start index.
         * @param {number} [end] - Optional end index.
         * @returns {Array} - The channel map.
         */
        getChannelMap: function (start, end) {
            if (start && start < 0) {
                start = 0;
            }

            if (end) {
                start = start ? start : 0;

                return this._channelMap.slice(start, end);
            }

            return this._channelMap;
        },

        /**
         * Returns the channel index for the given channel id.
         *
         * @param {number} channelId - The channel id.
         * @returns {number} - The channel index.
         */
        getChannelIndex: function (channelId) {
            return this._channelMap.indexOf(channelId);
        },

        /**
         * Returns the channel number for the given channel id.
         *
         * @param {number} channelId - The channel id.
         * @returns {number} - The channel number.
         */
        getChannelNumberForId: function (channelId) {
            return this.getChannelById(channelId).getNumber();
        }
    });

    return {

        /**
         * Returns the channel manager instance.
         *
         * @returns {Object} - The channel manager instance.
         */
        getInstance: function () {

            if (!instance) {
                instance = new ChannelManager();
            }

            return instance;
        }
    };
});