/*****************************************************************************
 * Open MCT Web, Copyright (c) 2014-2015, United States Government
 * as represented by the Administrator of the National Aeronautics and Space
 * Administration. All rights reserved.
 *
 * Open MCT Web is licensed under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0.
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 *
 * Open MCT Web includes source code licensed under additional open source
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 * this source code distribution or the Licensing information page available
 * at runtime from the About dialog for additional information.
 *****************************************************************************/
/*global define*/

define(
    [],
    function () {
        "use strict";

        /**
         * A telemetry handle acts as a helper in issuing requests for
         * new telemetry as well as subscribing to real-time updates
         * for the same telemetry series. This is exposed through the
         * `telemetryHandler` service.
         * @param $q Angular's $q, for promises
         * @param {TelemetrySubscription} subscription a subscription
         *        to supplied telemetry
         * @constructor
         * @memberof platform/telemetry
         */
        function TelemetryHandle($q, subscription) {
            var seriesMap = {},
                active = true,
                self = Object.create(subscription);

            // Request a telemetry series for this specific object
            function requestSeries(telemetryObject, request, callback) {
                var id = telemetryObject.getId(),
                    telemetry = telemetryObject.getCapability('telemetry');

                function receiveSeries(series) {
                    // Store it for subsequent lookup
                    seriesMap[id] = series;
                    // Notify callback of new series data, if there is one
                    if (callback && active) {
                        callback(telemetryObject, series);
                    }
                    // Pass it along for promise-chaining
                    return series;
                }

                // Issue the request via the object's telemetry capability
                return telemetry.requestData(request).then(receiveSeries);
            }

            self.unsubscribe = function () {
                active = false;
                return subscription.unsubscribe();
            };

            /**
             * Get the most recently obtained telemetry data series associated
             * with this domain object.
             * @param {DomainObject} the domain object which has telemetry
             *        data associated with it
             * @return {TelemetrySeries} the most recent telemetry series
             *         (or undefined if there is not one)
             * @memberof platform/telemetry.TelemetryHandle#
             */
            self.getSeries = function (domainObject) {
                var id = domainObject.getId();
                return seriesMap[id];
            };


            /**
             * Change the request duration.
             * @param {TelemetryRequest} request the request to issue
             * @param {Function} [callback] a callback that will be
             *        invoked as new data becomes available, with the
             *        domain object for which new data is available.
             * @memberof platform/telemetry.TelemetryHandle#
             */
            self.request = function (request, callback) {
                // Issue (and handle) the new request from this object
                function issueRequest(telemetryObject) {
                    return requestSeries(telemetryObject, request, callback);
                }

                // Map the request to all telemetry objects
                function issueRequests(telemetryObjects) {
                    return $q.all(telemetryObjects.map(issueRequest));
                }

                // If the request is a simple number, treat it as a duration
                request = (typeof request === 'number') ?
                        { duration: request } : request;

                // Look up telemetry-providing objects from the subscription,
                // then issue new requests.
                return subscription.promiseTelemetryObjects()
                    .then(issueRequests);
            };

            /**
             * Get the latest telemetry datum for this domain object. This
             * will be from real-time telemetry, unless an index is specified,
             * in which case it will be pulled from the historical telemetry
             * series at the specified index. If there is no latest available
             * datum, this will return undefined.
             *
             * @param {DomainObject} domainObject the object of interest
             * @param {number} [index] the index of the data of interest
             * @returns {TelemetryDatum} the most recent datum
             */
            self.getDatum = function (telemetryObject, index) {
                function makeNewDatum(series) {
                    return series ?
                        subscription.makeDatum(telemetryObject, series, index) :
                        undefined;
                }

                return typeof index !== 'number' ?
                        subscription.getDatum(telemetryObject) :
                        makeNewDatum(this.getSeries(telemetryObject));
            };

            return self;
        }

        return TelemetryHandle;

    }
);
