"use strict";

App.module("RepresentationModule", function(RepresentationModule, App, Backbone, Marionette, $, _, Logger) {

    RepresentationModule.addInitializer(function(options){

        RepresentationModule.registerMaster({
            id: "entity.recording.pair",
            inherit: "entity._pair",


            // =================================================================
            // config grid header

            _generateHeaderLabel1: function(entityHeaderView) {
                return _.str.sprintf("recording comparison (%s)", this.getConfigParameterValueOrDefaultValue(entityHeaderView.options.config, "comparisonMode"));
            },


            _generateHeaderLabel2: function(viewHeader) {
                return "";
//                var configOnTheLeft = viewHeader.dynamicDerivedConfigData.attributes.recordingConfigOnTheLeft;
//                var configOnTheRight = viewHeader.dynamicDerivedConfigData.attributes.recordingConfigOnTheRight;
//
//                var labelParts = [];
//
//                if (configOnTheLeft) {
//                    labelParts.push(this._generateCollectionConfigTitle(configOnTheLeft));
//                } else {
//                    labelParts.push("×");
//                }
//
//                labelParts.push("   ↔   ");
//
//                if (configOnTheRight) {
//                    labelParts.push(this._generateCollectionConfigTitle(configOnTheRight));
//                } else {
//                    labelParts.push("×");
//                }
//
//                return labelParts.join("");
            },


            // =================================================================
            // dynamic derived config data

            __optionsOfDynamicDerivedConfigData: {
                attributesToExcludeFromHash: ["recordingConfigOnTheLeft", "recordingConfigOnTheRight"],
                customHashSuffixGenerator: function (attributes) {
                    return (attributes.recordingConfigOnTheLeft  ? attributes.recordingConfigOnTheLeft. getClientId() : "x")
                         + (attributes.recordingConfigOnTheRight ? attributes.recordingConfigOnTheRight.getClientId() : "x");
                }
            },

            __updateMethodOfDynamicDerivedConfigData: function (force) {
                this._doUpdate(force);
                if (this.attributes.recordingConfigOnTheLeft && this.attributes.dynamicDefinitionForRecordingOnTheLeft) {
                    return;
                }
                if (this.attributes.recordingConfigOnTheRight && this.attributes.dynamicDefinitionForRecordingOnTheRight) {
                    return;
                }
                var _this = this;
                var interval = setInterval(function() {
                    _this._doUpdate(force);
                    if (_this.attributes.recordingConfigOnTheLeft && !_this.attributes.dynamicDefinitionForRecordingOnTheLeft) {
                        return;
                    }
                    if (_this.attributes.recordingConfigOnTheRight && !_this.attributes.dynamicDefinitionForRecordingOnTheRight) {
                        return;
                    }
                    clearInterval(interval);
                }, 50);
            },

            __doUpdateMethodOfDynamicDerivedConfigData: function (force) {
                var entityConfig = this.options.entityConfig;
                var configGrid = this.options.configGrid;

                // do nothing with orphans (configs just before they are deleted)
                if (!entityConfig.getDimension()) {
                    return;
                }

                // find the nearest recordings on the left and on the right
                var newRecordingConfigOnTheLeft = entityConfig;
                var newRecordingConfigOnTheRight = entityConfig;

                do {
                    newRecordingConfigOnTheLeft = configGrid.getPrevEntityNeighbour(newRecordingConfigOnTheLeft);
                } while (newRecordingConfigOnTheLeft && newRecordingConfigOnTheLeft.getParameterValue("kind") == "pair");

                do {
                    newRecordingConfigOnTheRight = configGrid.getNextEntityNeighbour(newRecordingConfigOnTheRight);
                } while (newRecordingConfigOnTheRight && newRecordingConfigOnTheRight.getParameterValue("kind") == "pair");


                var newDynamicDerivedConfigDataOnTheLeft  = App.dynamicDerivedConfigDataProvider.get(newRecordingConfigOnTheLeft);
                var newDynamicDerivedConfigDataOnTheRight = App.dynamicDerivedConfigDataProvider.get(newRecordingConfigOnTheRight);

                var newDynamicDefinitionForRecordingOnTheLeft  = newDynamicDerivedConfigDataOnTheLeft  ? newDynamicDerivedConfigDataOnTheLeft .attributes.dynamicDefinitionForRecording : null;
                var newDynamicDefinitionForRecordingOnTheRight = newDynamicDerivedConfigDataOnTheRight ? newDynamicDerivedConfigDataOnTheRight.attributes.dynamicDefinitionForRecording : null;

                var attributesToSet = {};

                var arrayOfShortcuts = [
                        [newRecordingConfigOnTheLeft,                "recordingConfigOnTheLeft",     "change:parameters", this.triggerChange],
                        [newRecordingConfigOnTheRight,               "recordingConfigOnTheRight",    "change:parameters", this.triggerChange],
                        [newDynamicDefinitionForRecordingOnTheLeft,  "dynamicDefinitionForRecordingOnTheLeft",  "change", this.triggerChange],
                        [newDynamicDefinitionForRecordingOnTheRight, "dynamicDefinitionForRecordingOnTheRight", "change", this.triggerChange],
                    ];

                for (var i = arrayOfShortcuts.length - 1; i >= 0; --i) {
                    var shortcuts = arrayOfShortcuts[i];
                    var oldAttributeValue = this.attributes[shortcuts[1]];
                    var newAttributeValue = shortcuts[0];
                    if (newAttributeValue != oldAttributeValue) {
                        attributesToSet[shortcuts[1]] = newAttributeValue;
                        if (oldAttributeValue) {
                            this.stopListening(oldAttributeValue, shortcuts[2]);
                        }
                        if (newAttributeValue) {
                            this.listenTo(newAttributeValue, shortcuts[2], shortcuts[3]);
                        }
                    }
                }
                this.set(attributesToSet);
            },


            __triggerChangeMethodOfDynamicDerivedConfigData: function() {
                this.dropCachedHash();
                this.trigger("change");
            },


            generateDynamicDerivedConfigData: function(entityConfig, configGrid) {
                var optionsOfThisDynamicDerivedConfigData = _.clone(this.__optionsOfDynamicDerivedConfigData);
                optionsOfThisDynamicDerivedConfigData.entityConfig = entityConfig;
                optionsOfThisDynamicDerivedConfigData.configGrid = configGrid;

                var dynamicDerivedConfigData = new RepresentationModule.DynamicDerivedConfigData({
                    recordingConfigOnTheLeft: null,
                    recordingConfigOnTheRight: null,
                    dynamicDefinitionForRecordingOnTheLeft: null,
                    dynamicDefinitionForRecordingOnTheRight: null
                }, optionsOfThisDynamicDerivedConfigData);

                dynamicDerivedConfigData.update = this.__updateMethodOfDynamicDerivedConfigData;
                dynamicDerivedConfigData._doUpdate = this.__doUpdateMethodOfDynamicDerivedConfigData;
                dynamicDerivedConfigData.triggerChange = this.__triggerChangeMethodOfDynamicDerivedConfigData;

                dynamicDerivedConfigData.listenTo(configGrid, "change_layout", dynamicDerivedConfigData.update);
                dynamicDerivedConfigData.update();

                return dynamicDerivedConfigData;
            },


            // =================================================================
            // dynamic derived vis instance data


            // -----------------------------------------------------------------
            // dynamic derived vis instance data - base

            __optionsOfDynamicDerivedVisInstanceDataForBase: {
                attributesToExcludeFromHash: ["apiResponseOnTheLeft", "apiResponseOnTheRight"],
                customHashSuffixGenerator: function (attributes) {
                    if (attributes.apiResponseOnTheLeft) {
                        return JSON.stringify(attributes.apiResponseOnTheLeft.errors);
                    } else {
                        return typeof attributes.apiResponseOnTheLeft;
                    }
                    if (attributes.apiResponseOnTheRight) {
                        return JSON.stringify(attributes.apiResponseOnTheRight.errors);
                    } else {
                        return typeof attributes.apiResponseOnTheRight;
                    }
                }
            },


            __upateMethodOfDynamicDerivedVisInstanceDataForBase: function(force) {
                var visInstanceView = this.options.visInstanceView;
                var _this = this;
                _.each(["Right", "Left"], function(side) {
                    var dynamicDefinitionForRecording = visInstanceView.dynamicDerivedConfigDataForEntity.attributes["dynamicDefinitionForRecordingOnThe" + side];
                    if (!dynamicDefinitionForRecording) { // entity kind has changed (e.g. a grid was reset)
                        return;
                    }
                    if (_this.attributes["apiResponseOnThe"+side] !== null) { // null = waiting
                        var recordingLabel = dynamicDefinitionForRecording.attributes.label;
                        if (!recordingLabel) {
                            var attrs = {};
                            attrs["apiRequestURIOnThe" + side] = undefined;
                            attrs["apiRequestParamsHashOnThe" + side] = undefined;
                            attrs["apiResponseOnThe" + side] = undefined;
                            _this.set(attrs);
                            return;
                        }

                        var requestParams = _.clone(visInstanceView.dynamicDerivedConfigDataForView.attributes.basePerspectiveRequestParams);
                        if (!requestParams) {
                            return;
                        }
                        requestParams.uri = visInstanceView.dynamicDerivedConfigDataForEntity.attributes["recordingConfigOnThe" + side].getParameterValue("recordingURI");

                        var apiRequestParamsHash = JSON.stringify(requestParams);
                        if (!force && apiRequestParamsHash == _this.attributes["apiRequestParamsHashOnThe" + side]) {
                            return;
                        }

                        var apiRequestURI = App.DataModule.CliopatriaAPI.request("getRecordingPerspective", requestParams, function(data){
                            if (JSON.stringify(requestParams) != _this.attributes["apiRequestParamsHashOnThe" + side]) {
                                return;
                            }
                            var attrs = {};
                            attrs["apiRequestParamsHashOnThe" + side] = undefined;
                            attrs["apiResponseOnThe" + side] = data;
                            _this.set(attrs);
                        });

                        var attrs = {};
                        attrs["apiRequestURIOnThe" + side] = apiRequestURI;
                        attrs["apiRequestParamsHashOnThe" + side] = apiRequestParamsHash;
                        attrs["apiResponseOnThe" + side] = null;
                        _this.set(attrs);
                    }
                });
            },


            generateDynamicDerivedVisInstanceDataForBase: function(visInstanceView) {
                // An empty object if comparison is not supported
                var viewMaster = visInstanceView._cachedViewMaster;
                if (!viewMaster.options.visInstanceSupportedComparisonModes.length) {
                    return new RepresentationModule.DynamicDerivedVisInstanceData({});
                }

                var optionsForThisDynamicDerivedVisInstanceDataForBase = _.clone(this.__optionsOfDynamicDerivedVisInstanceDataForBase);
                optionsForThisDynamicDerivedVisInstanceDataForBase.visInstanceView = visInstanceView;

                var dynamicDerivedVisInstanceDataForBase = new RepresentationModule.DynamicDerivedVisInstanceData({
                    apiRequestURIOnTheLeft:         undefined,
                    apiRequestParamsHashOnTheLeft:  undefined,
                    apiResponseOnTheLeft:           undefined,
                    apiRequestURIOnTheRight:        undefined,
                    apiRequestParamsHashOnTheRight: undefined,
                    apiResponseOnTheRight:          undefined
                }, optionsForThisDynamicDerivedVisInstanceDataForBase);

                dynamicDerivedVisInstanceDataForBase.update = this.__upateMethodOfDynamicDerivedVisInstanceDataForBase;

                dynamicDerivedVisInstanceDataForBase.listenTo(visInstanceView.dynamicDerivedConfigDataForEntity, "change",  dynamicDerivedVisInstanceDataForBase.update);
                dynamicDerivedVisInstanceDataForBase.listenTo(visInstanceView.dynamicDerivedConfigDataForView, "change:basePerspectiveRequestParams",         dynamicDerivedVisInstanceDataForBase.update);

                dynamicDerivedVisInstanceDataForBase.update();

                return dynamicDerivedVisInstanceDataForBase;
            },


            verifyAllDataForVisInstanceBase: function(visInstanceView) {
                this._verifyThatViewIsNotEmptyOrUnknown(visInstanceView);

                var viewMaster = visInstanceView._cachedViewMaster;
                if (!viewMaster.options.canHaveBase) {
                    return;
                }
                var supportedComparisonModes = viewMaster.options.visInstanceSupportedComparisonModes;
                if (!supportedComparisonModes.length) {
                    throw new RepresentationModule.Error({type: "comparison_not-supported"});
                }
                if (!_.contains(supportedComparisonModes, viewMaster._getVisInstanceViewComparisonMode(visInstanceView))) {
                    throw new RepresentationModule.Error({type: "comparison_wrong-type", supportedTypes: supportedComparisonModes});
                }

                var attributesOfDerivedConfigDataForEntityOnTheLeft  = visInstanceView.dynamicDerivedConfigDataForEntity.attributes;
                var attributesOfDerivedConfigDataForEntityOnTheRight = visInstanceView.dynamicDerivedConfigDataForEntity.attributes;
                var dynamicDefinitionForRecordingOnTheLeft  = attributesOfDerivedConfigDataForEntityOnTheLeft .dynamicDefinitionForRecordingOnTheLeft;
                var dynamicDefinitionForRecordingOnTheRight = attributesOfDerivedConfigDataForEntityOnTheRight.dynamicDefinitionForRecordingOnTheRight;
                var attributesOfRecordingOnTheLeft  = dynamicDefinitionForRecordingOnTheLeft  ? dynamicDefinitionForRecordingOnTheLeft.attributes  : {};
                var attributesOfRecordingOnTheRight = dynamicDefinitionForRecordingOnTheRight ? dynamicDefinitionForRecordingOnTheRight.attributes : {};

                if (attributesOfRecordingOnTheLeft.label === null || attributesOfRecordingOnTheRight.label === null) {
                    throw new RepresentationModule.Error({type: "data-preparing_entity-derived"});
                }
                if (attributesOfRecordingOnTheLeft.label === false || attributesOfRecordingOnTheRight.label === false) {
                    var apiErrorsOnTheLeft  = attributesOfRecordingOnTheLeft .errors || [];
                    var apiErrorsOnTheRight = attributesOfRecordingOnTheRight.errors || [];
                    apiErrors = apiErrorsOnTheLeft.concat(apiErrorsOnTheRight);
                    throw new RepresentationModule.Error({type: "api-error_entity-derived", apiErrors: apiErrors, coverTapAction: this.__coverTapActionThatUpdatesDynamicDerivedData, derivedDataToUpdate: "entity"});
                }
                if (attributesOfRecordingOnTheLeft.label === undefined || attributesOfRecordingOnTheRight.label === undefined) {
                    throw new RepresentationModule.Error({type: "pair_incomplete"});
                }

                var attribytesOfDerivedVisInstanceDataForBase = visInstanceView.dynamicDerivedVisInstanceDataForBase.attributes;
                if (!attribytesOfDerivedVisInstanceDataForBase.apiResponseOnTheLeft || !attribytesOfDerivedVisInstanceDataForBase.apiResponseOnTheRight) {
                    throw new RepresentationModule.Error({type: "data-preparing_base"});
                }
                if (attribytesOfDerivedVisInstanceDataForBase.apiResponseOnTheLeft.errors || attribytesOfDerivedVisInstanceDataForBase.apiResponseOnTheRight.errors) {
                    var apiErrorsOnTheLeft  = attribytesOfDerivedVisInstanceDataForBase.apiResponseOnTheLeft .errors || [];
                    var apiErrorsOnTheRight = attribytesOfDerivedVisInstanceDataForBase.apiResponseOnTheRight.errors || [];
                    var apiErrors = apiErrorsOnTheLeft.concat(apiErrorsOnTheRight);

                    if (apiErrors[0]) {
                        var error0 = apiErrors[0];
                        if (((error0.code == 11 || error0.code == 12) && !apiErrors[1]) || (apiErrors[1] && (apiErrors[1].code == 11 || apiErrors[1].code == 12))) {
                            throw new RepresentationModule.Error({type: "api-message_progress_base", apiErrors: apiErrors, coverTapAction: this.__coverTapActionThatUpdatesDynamicDerivedData, derivedDataToUpdate: "base"});
                        }
                    }

                    throw new RepresentationModule.Error({type: "api-error_base", apiErrors: apiErrors, coverTapAction: this.__coverTapActionThatUpdatesDynamicDerivedData, derivedDataToUpdate: "base"});
                }
            }
        });
    });
}, Logger);
