angular.module("app").directive("chartSetup", function ($rootScope, $q, $timeout, AppService, DataService, UniqueIdGenerator, SQConstants, SQEvents, L, WhatToBuildService) {
    return {
        restrict: 'E',
        replace: true,
        templateUrl: "../app/directives/chartSetup/views/chartSetup.html",
        scope: {
            setup: '=',
            mainSetup: '@',
            onMainSymbolChange: '&',
            onMainDatesChange: '&',
            onSubchartsChange: '&',
            ngDisabled: '='
        },
        link: function (scope, element, attrs) {

            //pouziva sa v Optimizeri z DataCtrl pre nastavenia spravneho poctu subcharts
            DataService.subchartsCountChanged = function(count) {
                scope.additionalCharts.count = count;
            }

            function init() {
                initialized = false;
                scope.symbolDateRange = DataService.getSymbolDateRange(scope.setup.symbol);

                scope.constants.subchartData = angular.copy(scope.availableData);
                scope.constants.subchartData.splice(0, 0, {
                    symbol: 'Same as main chart'
                });

                try {
                    scope.additionalCharts.count = scope.setup.subcharts.length;
                } catch (err) {
                    console.error(err);
                }

                DataService.loadAvailablePrecisions(scope.precisions, scope.setup.symbol, scope.setup.engine);

                //console.error("init", angular.copy(scope.setup));
                initCommissions();

                $timeout(function () {
                    initialized = true;
                    scope.forceDateChange = false;
                });
            }

            function loadAvailableData(data){
                if(data && data.action == SQConstants.getConstants().dataUpdateTypes.rename){
                    var symbolNames = data.symbols.split("##");
                    if(DataService.correctSetupSymbolNames(scope.setup, symbolNames[0], symbolNames[1])){
                        symbolCorrected = true;
                    }
                }

                scope.availableData.length = 0;
                scope.constants = SQConstants.getConstants();
                if(!scope.constants.data) return;
                
                for(var i=0; i<scope.constants.data.length; i++){
                    var data = scope.constants.data[i];
                    if(data.rows > 0 && data.show){
                        scope.availableData.push(data);
                    }
                }
            }

            function initCommissions() {
                $timeout(function () {
                    var config = DataService.getCommissionSettings(null, getCommissionsConfigElement());
                    scope.commPGInstance.setSettings(config);
                }, 0, false);
            }

            function getCommissionsConfigElement() {
                return xmlToObject(scope.setup.commissions).find("Commissions")[0];
            }

            var commGridLoaded = false;
            scope.afterPGInit = function(){
                commGridLoaded = true;
            }

            scope.onCommPGChange = function () {
                var newType = scope.commPGInstance.getSelectedType(); //method name
                var configElement = getCommissionsConfigElement();

                //console.error("onCommPGChange", newType);

                //switching to other method
                if (curCommissionType != newType) {
                    curCommissionType = newType;

                    var commissionSettings = DataService.getCommissionSettings(newType, configElement);

                    if (commissionSettings.method == newType) {
                        scope.commPGInstance.setSettings(commissionSettings);
                    }
                }
                
                DataService.updateCommissionSettings(newType, scope.commPGInstance, configElement);
                scope.setup.commissions = xmlToString(configElement);
            }

            scope.resetDates = function () {
                var symbolData = DataService.getSymbolData(scope.setup.symbol);
                if (symbolData) {
                    scope.setup.dateFrom = timeToDateString(symbolData.dateFrom);
                    scope.setup.dateTo = timeToDateString(symbolData.dateTo);

                    if (scope.mainSetup == 'true' && scope.onMainDatesChange) {
                        scope.onMainDatesChange({
                            dateFrom: scope.setup.dateFrom,
                            dateTo: scope.setup.dateTo
                        });
                    }
                }
            }

            scope.onDateFromChange = function (date) {
                scope.setup.dateFrom = date;
                onDateChange();
            }

            scope.onDateToChange = function (date) {
                scope.setup.dateTo = date;
                onDateChange();
            }

            function onDateChange() {
                var dateFrom = getDate(scope.setup.dateFrom);
                var dateTo = getDate(scope.setup.dateTo);

                //console.error("onDateChange", angular.copy(scope.setup));
                if (dateTo < dateFrom) {
                    if (oldDateFrom && oldDateTo) {
                        scope.setup.dateFrom = oldDateFrom;
                        scope.setup.dateTo = oldDateTo;
                    }

                    $rootScope.showError(L.tsq("Date from must be before date to"));
                    try { scope.$digest(); } catch(err){}
                    return;
                }

                oldDateFrom = scope.setup.dateFrom;
                oldDateTo = scope.setup.dateTo;

                if (scope.mainSetup == 'true' && scope.onMainDatesChange) {
                    scope.onMainDatesChange({
                        dateFrom: scope.setup.dateFrom,
                        dateTo: scope.setup.dateTo
                    });
                }
            }

            scope.getCommisionSwapLabel = function() {           
                let commissionLabel = getCommissionLabel();
                let swapLabel = getSwapLabel();

                return commissionLabel + " | " + swapLabel;
            }

            function getCommissionLabel(){
                if(!commGridLoaded) return "N/A";

                var type = scope.commPGInstance.getSelectedType();     
                if(!type) return "N/A";

                var data = scope.commPGInstance.getSelectedValues();       
                
                var commissionsLabel = type;

                var method = getItem(scope.commissionMethods, "class", type);
                if(method) {
                    commissionsLabel = L.tsq(method.display);

                    for(var i=0; i<data.length; i++) {
                        var property = data[i];
                        var value = property.value;
                        var key = property.key;
                        
                        commissionsLabel = commissionsLabel.replace("#"+key+"#", value); 
                    }
                }

                return commissionsLabel;
            }

            function getSwapLabel(){
                if(!scope.setup.swap){
                    return L.tsq("No swap");
                }

                let elSwap = xmlToObject(scope.setup.swap).find("Swap")[0];
                if(!getAttrBooleanValue(elSwap, "use", false)){
                    return L.tsq("No swap");
                }

                let swapType = getAttrStringValue(elSwap, "type", scope.constants.swapTypes.money);
                let swapLong = getAttrFloatValue(elSwap, "long", 0);
                let swapShort = getAttrFloatValue(elSwap, "short", 0);
                let typeChar = swapType === scope.constants.swapTypes.money ? "$" : (swapType === scope.constants.swapTypes.percent ? "%" : "points");

                return L.tsq("long: %s, short: %s", [(swapLong + typeChar), (swapShort + typeChar)]); 
            }

            scope.showOtherSettingsPopup = function () {
                showPopup('#' + scope.otherParamsPopupId);
            }

            scope.getPrecisionLabel = function(){
                var selectedPrecision = getItem(scope.precisions, "value", scope.setup.precision);
                return selectedPrecision ? L.tsq(selectedPrecision.name) : '';
            }

            scope.isTSSymbol = function(symbol){
                symbol = symbol == "Same as main chart" ? scope.setup.symbol : symbol;
                var symbolData = getItem(scope.constants.data, "symbol", symbol);
                return symbolData.barType != 1;
            }

            scope.getEngineLabel = function () {
                var engine = getItem(scope.constants.engineTypes, "value", scope.setup.engine);
                return engine ? engine.name : '??? '+scope.setup.engine;
            }

            //- Event Handlers --------------------------------------------------------------

            function onEvent(event, data) {
                if (event == SQEvents.get('DATA_CHANGED')) {
                    loadAvailableData(data);

                    scope.constants.subchartData = angular.copy(scope.availableData);
                    scope.constants.subchartData.splice(0, 0, {
                        symbol: 'Same as main chart'
                    });
                    
                    scope.symbolDateRange = DataService.getSymbolDateRange(scope.setup.symbol);
                } 
                else if (event == SQEvents.get('SETTINGS_TASK_CHANGED')){       //called when switching between tasks in Custom Projects
                    taskSwitched = true;                                        //this will prevent resetting spread to default value
                }
                else if (event == SQEvents.get('SETTINGS_TAB_RELOAD')) {
                    if (data == 'Data' || data == 'all') {
                        initialized = false;
                        scope.forceDateChange = true;
                        $timeout(init, 1000, false);        //without a long enough timeout, slippage gets reset for TS and MC engine when switching between tasks

                        taskType = AppService.getTask().type;
                        scope.showSubchartSpinner = showSubchartSpinner();
                    }
                } 
                else return;

                try { scope.$digest(); } catch (er) {}
            }

            var destroySymbolWatch = scope.$watch("setup.symbol", function (newValue, oldValue) {
                try {
                    if (symbolCorrected){
                        symbolCorrected = false;
                        return;
                    }

                    if (initialized) {
                        if(newValue == null || newValue == 'null'){
                            scope.setup.symbol = '';
                            return;
                        }

                        symbolCorrected = true;
                        DataService.changeSetupDetails(scope.setup, scope.precisions, taskSwitched ? null : oldValue);  //taskSwitched prevents resetting spread to default value when switching between tasks
                        symbolCorrected = false;

                        //console.error("chartsetup symbol watch", angular.copy(scope.setup));
                        scope.symbolDateRange = DataService.getSymbolDateRange(scope.setup.symbol);

                        if (scope.mainSetup == 'true' && scope.onMainSymbolChange) {
                            scope.onMainSymbolChange({
                                symbol: scope.setup.symbol
                            });
                        }

                        initCommissions();

                    } else {
                        $timeout(init, 0, false);
                    }
                }
                finally {
                    if(taskSwitched){   
                        taskSwitched = false;   
                    }
                }
            });

            var destroyEngineWatch = scope.$watch("setup.engine", function (newValue, oldValue) {
                if (initialized) {
                    DataService.loadAvailablePrecisions(scope.precisions, scope.setup.symbol, newValue);

                    var curPrecision = getItem(scope.precisions, "value", scope.setup.precision);
                    if(!curPrecision && scope.precisions.length>0){
                        scope.setup.precision = scope.precisions[0].value;
                    }
                }
            });

            var destroySymbolDataRangeWatch = scope.$watch("symbolDateRange", function (newValue, oldValue) {
                if (valueFilled(newValue) && newValue != "N/A"){
                    var dates = scope.symbolDateRange.split(" - ");
                    if (dates.length == 2) {
                        scope.symbolDateRangeFrom = dates[0];
                        scope.symbolDateRangeTo = dates[1];
                    }
                    else {
                        var defaultDate = getDateString(new Date(0));
                        scope.symbolDateRangeFrom = defaultDate;
                        scope.symbolDateRangeTo = defaultDate;
                    }
                }
            });

            scope.onSubchartsChangeEvent = function() {
                if (initialized && scope.onSubchartsChange) {
                    scope.onSubchartsChange({
                        subchartCount: scope.additionalCharts.count
                    });
                }
            }

            scope.$on("$destroy", function () {
                destroySymbolWatch();
                destroySymbolDataRangeWatch();
                destroyEngineWatch();

                UniqueIdGenerator.removeId(scope.otherParamsPopupId);
                SQEvents.removeListener(listenerId);
            });

            function showSubchartSpinner() {
                if((taskType == 'Retest' || taskType == 'Optimize') && scope.mainSetup == "true") return true;

                if(taskType == 'Build' && (WhatToBuildService.config.strategyType == WhatToBuildService.strategyTypes.improve || WhatToBuildService.config.strategyType == WhatToBuildService.strategyTypes.template)) return true;

                return false;
            }

            //- Initialization --------------------------------------------------------------

            var initialized = false;
            var symbolCorrected = false;
            var taskSwitched = false;

            var oldDateFrom = scope.setup.dateFrom;
            var oldDateTo = scope.setup.dateTo;

            var curCommissionType;

            scope.constants = angular.copy(SQConstants.getConstants());
            scope.precisions = scope.constants.precisions;
            scope.symbolDateRange = "N/A";
            scope.additionalCharts = {
                count: 0
            };
            scope.otherParamsPopupId = UniqueIdGenerator.generateId();

            scope.commPGInstance = {};
            scope.commissionMethods = DataService.commissionMethods;
            scope.forceDateChange = false;
            scope.availableData = [];

            loadAvailableData();

            if (scope.mainSetup == "false") init(); //to load symbol details on first change

            var taskType = AppService.getTask().type;
            scope.showSubchartSpinner = showSubchartSpinner();

            var listenerId = "ChartSetup-" + scope.otherParamsPopupId;
            SQEvents.addListener(listenerId, [SQEvents.get('DATA_CHANGED'), SQEvents.get('SETTINGS_TAB_RELOAD'), SQEvents.get('SETTINGS_TASK_CHANGED')], onEvent);
        }
    };
});

/**
 * Commission settings are saved as an xml string of property grid config in setup.commissions object
 */