angular.module('app').service('BlockConfigService', function($rootScope, $q, SQEvents, ComplexitiesService, AppService, L) {
    
    this.setParamDetails = function(targetObj, sourceObj){
        targetObj.key = sourceObj.key;
        targetObj.name = sourceObj.name;
        targetObj.type = sourceObj.type;
        targetObj.generation = sourceObj.generation;
        targetObj.defaultValue = sourceObj.defaultValue;
        targetObj.fixedValue = sourceObj.fixedValue;
        targetObj.originalMinValue = sourceObj.originalMinValue || 0;
        targetObj.originalMaxValue = sourceObj.originalMaxValue || 100000;
        targetObj.minValue = targetObj.generation == instance.generationTypes.fixed ? targetObj.originalMinValue : sourceObj.minValue;
        targetObj.maxValue = targetObj.generation == instance.generationTypes.fixed ? targetObj.originalMaxValue : sourceObj.maxValue;
        targetObj.originalStep = sourceObj.step || 1;
        targetObj.step = targetObj.originalStep;
        targetObj.values = sourceObj.values;
        targetObj.allCharts = sourceObj.allCharts;
        targetObj.options = angular.copy(sourceObj.options);
        targetObj.isCombo = sourceObj.isCombo || isChartParam(sourceObj) || targetObj.values;
        targetObj.paramType = sourceObj.paramType;
    }

    this.setParamSetDetails = function(targetObj, sourceObj){
        targetObj.name = sourceObj.name;
        targetObj.oldName = sourceObj.oldName;
        targetObj.params = angular.copy(sourceObj.params);
    }

    this.refreshSetParamsGrid = function(setParamsGrid, setObj, blockObj){
        setParamsGrid.removeAllRows(true, true);
        
        for(var i=0; i<setObj.params.length; i++){
            var param = setObj.params[i];
            instance.setGenValues(param, blockObj.params, param.key);
            
            setParamsGrid.addRow([
                param.name,
                param.type,
                param.generation,
                instance.getParamPossibleValues(blockObj, param)
            ], true);
        }

        setParamsGrid.bodyRedraw();
    }

    this.refreshParameterSetsGrid = function(parameterSetsGrid, selectedBlock){
        if(!parameterSetsGrid) return;
        
        parameterSetsGrid.removeAllRows(true, true);

        var randomAllWeight = selectedBlock.generatedWeight != null ? selectedBlock.generatedWeight : 1;

        parameterSetsGrid.addRow([
            "All random",
            getSetPossibleValues(null, selectedBlock),
            "{{spinnerWidget value='" + randomAllWeight + "' min='0'}}",
            ""
        ], true);

        var sets = selectedBlock.paramSets;
        if(arrayNotEmpty(sets)){
            for(var i=0; i<sets.length; i++){
                var set = sets[i];

                parameterSetsGrid.addRow([
                    set.name,
                    getSetPossibleValues(set, selectedBlock),
                    "{{spinnerWidget value='" + set.weight + "' min='0'}}",
                    createActionLink('&times;', "row-delete-link", "removeSet")
                ], true);
            }
        }
        
        parameterSetsGrid.addRow([
            createActionLink(L.tsq('Add new set'), "row-add-link", "addNewSet"),
            "",
            "",
            ""
        ], true);
        
        parameterSetsGrid.bodyRedraw();
    }

    this.refreshParametersGrid = function(parametersGrid, blockObj) {
        if(!parametersGrid) return;

        if(arrayNotEmpty(blockObj.customParams)){
            var isExitAfterBars = blockObj.customParams.length == 1 && blockObj.customParams[0].key == '#ExitAfterBars#';
            var enableExitParams = blockObj.enableExitParams;
           
            parametersGrid.removeAllRows(true, true);

            for(var i=0; i<blockObj.customParams.length; i++){
                var param = blockObj.customParams[i];
                if(!isExitAfterBars && ((param.exitMethod && !enableExitParams) || param.key == '#ExitAfterBars.ExitAfterBars#')) continue;

                parametersGrid.addRow([
                    param.name,
                    param.type,
                    param.generation,
                    instance.getParamPossibleValues(blockObj, param)
                ], true);
            }

            parametersGrid.bodyRedraw();
        }
        else {
            parametersGrid.removeAllRows();
        }
    }

    this.setGenValues = function(targetObj, originalParams, paramKey){
        var originalParam = getItem(originalParams, 'key', paramKey);
        //used for special params (Shift, Period...)
        targetObj.originalMinValue = originalParam.originalMinValue;
        targetObj.originalMaxValue = originalParam.originalMaxValue;
        targetObj.genMinValue = originalParam.genMinValue;
        targetObj.genMaxValue = originalParam.genMaxValue;
    }
    
    function getSetPossibleValues(set, selectedBlock){
        var values = "";

        if(set == null){
            if(!selectedBlock.params) return values;

            var params = angular.copy(selectedBlock.params);
            for(var i=0; i<params.length; i++){
                var param = params[i];
                values += (i ? "," : "") + param.name + "=*";
            }

            return values;
        }

        for(var i=0; i<set.params.length; i++){
            var param = set.params[i];
            values += (i ? "," : "") + param.name + "=";

            var originalParam = getItem(selectedBlock.params, 'key', param.key);
            var options = instance.getOptions(selectedBlock, param);

            if(param.generation == instance.generationTypes.fixed){
                if(options && options.length){
                    var selectedOption = getItem(options, 'value', param.fixedValue);
                    values += selectedOption ? selectedOption.name : param.fixedValue;
                }
                else {
                    values += param.fixedValue;
                }
            }
            else {
                if(isChartParam(param)){
                    values += getChartValue(param, originalParam);
                }
                else if(options && options.length){
                    var checkedOptionIndex = -1;
                    for(var o=0; o<options.length; o++){
                        var option = options[o];
                        if(option.checked){
                            if(checkedOptionIndex < 0){
                                checkedOptionIndex = o;
                            }
                            else {
                                checkedOptionIndex = -1;
                                break;
                            }
                        }
                    }
                    if(checkedOptionIndex >= 0){
                        values += options[checkedOptionIndex].name;
                    }
                    else values += "*";
                }
                else {
                    values += "*";
                }
            }
        }
        return values;
    }

    this.getParamPossibleValues = function(blockObj, param){
        var originalParam = getItem(blockObj.params, 'key', param.key);

        if(param.generation == instance.generationTypes.random){
            if(param.type == 'boolean'){
                return 'true,false';
            }
            else if(isChartParam(param)){
                return getChartValue(param, originalParam, true);
            }
            else if(arrayNotEmpty(param.options)){
                return instance.getValuesFromOptions(param.options, true);
            }
            else if(param.values){
                var vals = param.values.split(",");
                var text = "";
                for(var i=0; i<vals.length; i++){
                    text += (i ? "," : "") + vals[i].split("=")[0]; 
                }
                return text;
            }
            else if(valueFilled(param.minValue)){
                var min = param.minValue;
                var max = param.maxValue;
                
                if(originalParam && originalParam.genMinValue){
                    var name = instance.getSpecialValueName(originalParam);

                    if(min == originalParam.genMinValue){
                        min = 'Min ' + name;
                    } 
                    if(max == originalParam.genMaxValue){
                        max = 'Max ' + name;
                    } 
                }
                
                return 'min: ' + min + ", max: " + max + ", step: " + param.step; 
            }
            else if(param.defaultValue){
                return param.defaultValue || '';
            }
        }
        else if(param.generation == instance.generationTypes.fixed){
            var options = instance.getOptions(blockObj, param);
            if(options && options.length){
                param.isCombo = true;
                param.options = angular.copy(options);
            }

            if(param.isCombo){
                if(param.type == 'boolean'){
                    return param.fixedValue;
                }

                for(var i=0; i<param.options.length; i++){
                    var option = param.options[i];
                    if(option.value == param.fixedValue){
                        return option.name;
                    }
                }
            }
            else {
                if(valueFilled(param.fixedValue)) return param.fixedValue;
                else if(valueFilled(param.defaultValue)) return param.defaultValue;
                else return '';
            }
        }
        
        return '';
    }

    function getChartValue(param, originalParam, displayAllCharts){
        if(param.allCharts == null && !param.values){
            if(originalParam){
                instance.setParamDetails(param, originalParam);
            }
        }

        if(param.allCharts){
            return displayAllCharts ? L.tsq('All charts') : '*';
        }
        else {
            if(param.values){
                var vals = param.values.split(",");
                return vals.length == 1 ? vals[0].split("=")[0] : "*";
            }
        }

        return '*';
    }

    this.getSpecialValueName = function(param){
        if(param.paramType){
            if(param.paramType == "period") return L.tsq('period');
            else if(param.paramType == "shift") return L.tsq('shift');
        }

        switch(param.key){
            case '#Shift#': return L.tsq('shift');
            case '#Period#': return L.tsq('period');
            case '#AtrPeriod#': 
            case '#Value#': 
                switch(parseInt(param.genMinValue)){
                    case -1000005: return L.tsq('SL Value');
                    case -1000007: return L.tsq('SL ATR Multiple');
                    case -1000009: return L.tsq('SL ATR Period');
                    case -1000011: return L.tsq('PT Value');
                    case -1000013: return L.tsq('PT ATR Multiple');
                    case -1000015: return L.tsq('PT ATR Period');
                    default: return L.tsq('value');
                }
            default: return L.tsq('value');
        }
    }

    this.getRealGenValue = function(selectedParam, isMinimum){
        var isPeriod = selectedParam.key != '#Shift#' && (!selectedParam.paramType || selectedParam.paramType != "shift");

        var settingsElem = AppService.getTaskConfig();
        var whatToBuildElem = getChildElement(settingsElem, 'WhatToBuild', true);
        if(whatToBuildElem){
            var rulesComplexityElem = getChildElement(whatToBuildElem, 'RulesComplexity', true);
            if(rulesComplexityElem){
                var mainChartElem = getChildElement(rulesComplexityElem, 'Chart', true);
                if(mainChartElem){
                    if(isPeriod){
                        return isMinimum ? getAttrIntValue(mainChartElem, 'minPeriod', 5) : getAttrIntValue(mainChartElem, 'maxPeriod', 50);
                    }
                    else {
                        return isMinimum ? getAttrIntValue(mainChartElem, 'minShift', 0) : getAttrIntValue(mainChartElem, 'maxShift', 5);
                    }
                }
            }
        }
        return isPeriod ? (isMinimum ? 5 : 50) : (isMinimum ? 0 : 5);
    }

    this.getOptions = function(blockObj, param){
        var allOptions = [];
        var paramOptions = [];

        //console.error("getOptions", param);

        if(isChartParam(param)){
            allOptions = instance.getChartOptions();
            paramOptions = instance.getOptionsFromValues(param.values);
        }
        else {
            var originalParam = getItem(blockObj.params, 'key', param.key);
            allOptions = originalParam.options;
            if(arrayEmpty(allOptions)){
                allOptions = instance.getOptionsFromValues(originalParam.values);
            }

            if(arrayEmpty(param.options) && valueFilled(param.values)){
                paramOptions = instance.getOptionsFromValues(param.values);
            }
        }
        
        return instance.getCorrectedOptions(paramOptions, allOptions);
    }

    this.getCorrectedOptions = function(paramOptions, allOptions){
        for(var i=0; i<allOptions.length; i++){
            var optionFound = false;
            for(var a=0; a<paramOptions.length; a++){
                if(allOptions[i].name == paramOptions[a].name){
                    optionFound = true;
                    break;
                }
            }
            allOptions[i].checked = optionFound;
        }

        return allOptions;
    }

    this.getChartOptions = function(){
        return instance.getOptionsFromValues(instance.getChartValues(), true);
    }

    this.getChartValues = function(){
        var values = "";
        
        for(var i=0; i<instance.complexities.length; i++){
            var complexity = instance.complexities[i];
            values += complexity.chartName + "=" + i + ",";
        }
        
        return values.substr(0, values.length - 1);
    }

    this.getOptionsFromValues = function(values, isChart){
        if(!valueFilled(values)) return [];
        
        var items = values.split(",");
        var allOptions = [];

        for(var i=0; i<items.length; i++){
            var item = items[i];
            var data = item.split("=");

            allOptions.push({
                name: data[0],
                value: data.length == 2 ? data[1] : data[0],
                checked: !isChart
            });
        }
        return allOptions;
    }

    this.getValuesFromOptions = function(options, namesOnly){
        var values = "";
        for(var i=0; i<options.length; i++){
            var option = options[i];
            if(option.checked){
                values += option.name + (namesOnly ? "" : ("=" + option.value)) + ",";
            }
        }
        return values.substr(0, values.length - 1);
    }

    this.generateSetName = function(parameterSetsGrid){
        var setNo = parameterSetsGrid.getNumberOfRows();
        var name = 'Set' + setNo;
        var nameFound = false;
        
        while(!nameFound){
            var nameExists = false;
            for(var i=0; i<parameterSetsGrid.getNumberOfRows(); i++){
                if(parameterSetsGrid.getCellValue(i, 0) == name){
                    nameExists = true;
                    name = 'Set' + (setNo + 1);
                    break;
                }
            }
            if(!nameExists){
                nameFound = true;
            }
        }

        return name;
    }

    this.getDefaultSetValues = function(params){
        var values = '*';
        for(var i=1; i<params.length; i++){
            values += ',*';
        }
        return values;
    }

    this.getLastIdIndex = function(){
        return lastIdIndex++;
    }

    var instance = this;
    var lastIdIndex = 0;

    this.generationTypes = {
        random: 'random',
        fixed: 'fixed'
    }

    this.categories = {
        orderTypes : 'orderTypes',
        exitTypes : 'exitTypes',
        signals : 'signals',
        indicators : 'indicators',
        stopLimitBlocks : 'stopLimitBlocks',
        customData : 'customData'
    }

    this.complexities = ComplexitiesService.settings.complexities;

    SQEvents.add('BLOCKS_PARAMS_RELOAD', 'blocks-params-reload');

});