/// <reference path="http://localhost/IndustrialDashboard/Scripts/IndustrialDashboard.js" />
define(["app", "underscore"], function (app) {
    var runtime = {
        getLastTagValue: function (tagNames, code, subcode, diff, timezone, callback) {
            /// <summary>
            /// Get last value for tag/tags specified from the runtime table (mapped to the runtime table to activate the runtime feature).
            /// If the tags are not mapped as runtime, they will be automatically mapped.
            /// </summary>  
            /// <param name="tagNames" type="Array">Array with tag names.</param>  
            /// <param name="code" type="Varchar">Code to identify real time mapped tag ids.</param>  
            /// <param name="subcode" type="Varchar" mayBeNull="true">Subcode to identify real time mapped tag ids. Can be null.</param>  
            /// <param name="diff" type="Boolean">Whether to performs a difference between the tags to get and the tags mapped with the code/subcode, if some mapped are not used, then delete those from the mapping table. False to keep them.</param>
            /// <param name="callback/options" type="Function/Object">Callback or object to extend options.</param>
            var that = this; 

            var options = {
                async: true,
                callback: function () { },
            };

            if (_.isFunction(callback)) { options.callback = callback; }
            else if (_.isObject(callback)) { options = _.extend(options, callback) }; 

            var tagNamesArr = (_.isArray(tagNames) ? tagNames : [tagNames]);

            var QP = new Core.Database.QueryParameters();
            QP.Add("tagNames", "VARCHAR", (_.isArray(tagNames) ? tagNames : [tagNames]).join(','));
            QP.Add("code", "VARCHAR", code);
            QP.Add("subcode", "VARCHAR", subcode);
            QP.Add("timezone", "VARCHAR", timezone); 
            QP.Add("diff", "BIT", diff);

            var items = []; 
            Core.Json.CallProcedure(app.DatabaseNames.System + ".SYSTEM.Runtime_GetLastTagValue", QP, {
                onSuccess: function (data) {
                    if (data && data.Table) {
                        var metadata = data.Table;
                        var real = data["Table" + (_.findWhere(metadata, { TableName: 'REAL' })).Index.toString()];
                        var digital = data["Table" + (_.findWhere(metadata, { TableName: 'DIGITAL' })).Index.toString()];
                        var string = data["Table" + (_.findWhere(metadata, { TableName: 'STRING' })).Index.toString()];

                        var parsefn = function(i){
                            return { id: i.TagId, name: i.Name, timestamp: i.Timestamp, value: i.Value }; 
                        }

                        items = items.concat(_.map(real, parsefn), _.map(digital, parsefn), _.map(string, parsefn));
                    }

                    items = _.object(_.pluck(items, "name"), items);

                    _.each(_.difference(tagNamesArr, _.pluck(items, "name")), function (nf) {
                        items[nf] = null; 
                    });

                    //items = tagNamesArr.length > 1 ? items : (tagNamesArr && tagNamesArr[0] && items[tagNamesArr[0]]) ? items[tagNamesArr[0]] : null;

                    if (options.callback != null && _.isFunction(options.callback))
                        options.callback.call(that, items);
                },
                Async: options.async,
                Secured: true,
            }, app.ConnectionStrings.app);

            if (!options.async) return items; 
        },
        getTagValues: function (tagNames, from, to, timezone, callback) {
            /// <summary>
            /// Get historic tag values for tagNames specified, between from and to (UTC).
            /// </summary>  
            /// <param name="tagNames" type="Array">Array with tag names.</param>
            /// <param name="callback/options" type="Function/Object">Callback or object to extend options.</param>
            var that = this;

            var options = {
                async: true,
                callback: function () { },
            };

            if (_.isFunction(callback)) { options.callback = callback; }
            else if (_.isObject(callback)) { options = _.extend(options, callback) };

            var tagNamesArr = (_.isArray(tagNames) ? tagNames : [tagNames]); 

            var QP = new Core.Database.QueryParameters();
            QP.Add("tagNames", "VARCHAR", tagNamesArr.join(','));
            QP.Add("from", "DATETIME", from);
            QP.Add("to", "DATETIME", to);
            QP.Add("timezone", "VARCHAR", timezone);

            var items = {};
            Core.Json.CallProcedure(app.DatabaseNames.System + ".SYSTEM.Historic_GetTagValues", QP, {
                onSuccess: function (data) {
                    if (data && data.Table) {
                        var metadata = data.Table;
                        var real = data["Table" + (_.findWhere(metadata, { TableName: 'REAL' })).Index.toString()];
                        var digital = data["Table" + (_.findWhere(metadata, { TableName: 'DIGITAL' })).Index.toString()];
                        var string = data["Table" + (_.findWhere(metadata, { TableName: 'STRING' })).Index.toString()];                        

                        var parsefn = function (i) {
                            return { id: i.TagId, name: i.Name, timestamp: i.Timestamp, value: i.Value };
                        }

                        var allItems = [].concat(_.map(real, parsefn), _.map(digital, parsefn), _.map(string, parsefn));

                        _.each(tagNamesArr, function (t) {
                            items[t] = _.where(allItems, { name: t });
                            items[t] = _.isArray(items[t]) ? items[t] : []; 
                        }); 
                    }

                    //items = tagNamesArr.length > 1 ? items : (tagNamesArr && tagNamesArr[0] && items[tagNamesArr[0]]) ? items[tagNamesArr[0]] : null; 

                    if (options.callback != null && _.isFunction(options.callback))
                        options.callback.call(that, items);
                },
                Async: options.async,
                Secured: true,
            }, app.ConnectionStrings.app);

            if (!options.async) return items;
        },
    };
    return runtime;
});