angular
  .module("app")
  .directive(
    "blockConfig",
    function ($rootScope, $q, $timeout, SQEvents, BlockConfigService, L) {
      return {
        restrict: "E",
        replace: true,
        templateUrl: "../app/directives/blockConfig/blockConfig.html",
        scope: {
          selectedBlock: "=",
          onFormulaEdit: "=",
        },
        link: function (scope, element, attrs) {
          function init() {
            $timeout(
              function () {
                initParametersGrid();
                initParameterSetsGrid();
                initSetParamsGrid();

                BlockConfigService.refreshParametersGrid(
                  parametersGrid,
                  scope.selectedBlock
                );
                BlockConfigService.refreshParameterSetsGrid(
                  parameterSetsGrid,
                  scope.selectedBlock
                );
              },
              0,
              false
            );
          }

          function initParametersGrid() {
            parametersGrid = new sqGrid(scope.parametersGridId);

            var columns = [
              { title: L.tsq("Parameter name"), type: "text", sort: "text" },
              { title: L.tsq("Type"), type: "text", sort: "text" },
              { title: L.tsq("Generation"), type: "text", sort: "text" },
              { title: L.tsq("Possible values"), type: "text", sort: "text" },
            ];

            var widths = [150, 55, 80, "*"];

            parametersGrid.setFirstColumnAsId(true, false);
            parametersGrid.setColumns(columns, !!parametersGrid);
            parametersGrid.setWidths(widths, !!parametersGrid);
            parametersGrid.setEmptyGridText(L.tsq("No parameters defined."));
            parametersGrid.disableSorting();

            parametersGrid.onCellDoubleClick = function (rowIndex) {
              editingParamSet = false;
              onParamDblClick(parametersGrid, rowIndex);
            };

            parametersGrid.headerRedraw();
          }

          function initParameterSetsGrid() {
            parameterSetsGrid = new sqGrid(scope.parameterSetsGridId);

            var columns = [
              { title: L.tsq("Set name"), type: "text", sort: "text" },
              { title: L.tsq("Possible values"), type: "text", sort: "text" },
              { title: L.tsq("Weight"), type: "text", sort: "number" },
              { title: "", type: "text", sort: "text" },
            ];

            var widths = [150, "*", 50, 30];

            parameterSetsGrid.setFirstColumnAsId(true, false);
            parameterSetsGrid.setColumns(columns, !!parameterSetsGrid);
            parameterSetsGrid.setWidths(widths, !!parameterSetsGrid);
            parameterSetsGrid.setEmptyGridText(L.tsq("No parameters defined."));
            parameterSetsGrid.disableSorting();

            parameterSetsGrid.defineWidget("spinnerWidget", sqGridSpinner);

            parameterSetsGrid.onCellDoubleClick = function (rowIndex) {
              if (
                rowIndex == 0 ||
                rowIndex == parameterSetsGrid.getNumberOfRows() - 1
              )
                return;

              editingParamSet = true;
              BlockConfigService.setParamSetDetails(
                scope.selectedParamSet,
                scope.selectedBlock.paramSets[rowIndex - 1]
              );
              scope.selectedParamSet.oldName = scope.selectedParamSet.name;

              BlockConfigService.refreshSetParamsGrid(
                setParamsGrid,
                scope.selectedParamSet,
                scope.selectedBlock
              );

              try {
                scope.$digest();
              } catch (err) {}
              showPopup("#" + scope.editParamSetPopupId);
            };

            parameterSetsGrid.cellEventHandler = function (
              rowIndex,
              cellIndex,
              eventName,
              args
            ) {
              switch (eventName) {
                case "addNewSet":
                  onCreateNewSet();
                  break;
                case "removeSet":
                  onRemoveSet(rowIndex);
                  break;
                case "spinnerUpdated":
                  var newValue = args[0];
                  if (rowIndex == 0) {
                    scope.selectedBlock.generatedWeight = newValue;
                  } else {
                    scope.selectedBlock.paramSets[
                      rowIndex - 1
                    ].weight = newValue;
                  }

                  scope.selectedBlock.isChanged = true;
                  scope.selectedBlock.paramSetsChanged = true;
                  break;
              }
            };

            parameterSetsGrid.headerRedraw();
          }

          function onCreateNewSet() {
            var setNo = parameterSetsGrid.getNumberOfRows() - 1;
            var name = BlockConfigService.generateSetName(parameterSetsGrid);
            var defaultValues = BlockConfigService.getDefaultSetValues(
              scope.selectedBlock.params
            );

            parameterSetsGrid.removeRowByIndex(setNo); //remove last row
            parameterSetsGrid.addRow([
              name,
              defaultValues,
              "{{spinnerWidget value='1' min='0'}}",
              createActionLink("&times;", "row-delete-link", "removeSet"),
            ]);
            parameterSetsGrid.addRow(
              [
                createActionLink(
                  L.tsq("Add new set"),
                  "row-add-link",
                  "addNewSet"
                ),
                "",
                "",
                "",
              ],
              true
            );

            scope.selectedBlock.paramSets = scope.selectedBlock.paramSets || [];
            scope.selectedBlock.paramSets.push({
              name: name,
              params: angular.copy(scope.selectedBlock.params),
              weight: 1,
            });
            scope.selectedBlock.isChanged = true;
            scope.selectedBlock.paramSetsChanged = true;

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

          function onRemoveSet(rowIndex) {
            $rootScope.showConfirm(
              L.tsq("Delete parameter set"),
              L.tsq("Do you want to delete selected parameter set?"),
              function (confirmed) {
                if (confirmed) {
                  parameterSetsGrid.removeRowByIndex(rowIndex);
                  scope.selectedBlock.paramSets.splice(rowIndex - 1, 1); //first row is random set
                  scope.selectedBlock.isChanged = true;
                  scope.selectedBlock.paramSetsChanged = true;

                  try {
                    scope.$digest();
                  } catch (err) {}
                }
              },
              true
            );
          }

          function initSetParamsGrid() {
            if ($("#" + scope.setParamsGridId).length == 0) {
              $timeout(function () {
                initSetParamsGrid();
              }, 200);
              return;
            }
            setParamsGrid = new sqGrid(scope.setParamsGridId);
            var columns = [
              { title: L.tsq("Name"), type: "text", sort: "text" },
              { title: L.tsq("Type"), type: "text", sort: "text" },
              { title: L.tsq("Generation"), type: "text", sort: "text" },
              { title: L.tsq("Possible values"), type: "text", sort: "text" },
            ];

            var widths = [100, 80, 80, "*"];

            setParamsGrid.setFirstColumnAsId(true, false);
            setParamsGrid.setColumns(columns, !!setParamsGrid);
            setParamsGrid.setWidths(widths, !!setParamsGrid);
            setParamsGrid.setEmptyGridText(L.tsq("No parameters defined."));
            setParamsGrid.disableSorting();

            setParamsGrid.onCellDoubleClick = function (rowIndex) {
              onParamDblClick(setParamsGrid, rowIndex);
            };

            setParamsGrid.headerRedraw();
          }

          function onParamDblClick(grid, rowIndex) {
            var param;

            if (editingParamSet) {
              param = scope.selectedParamSet.params[rowIndex];
            } else {
              var name = grid.getCellValue(rowIndex, 0);
              param =
                getItem(scope.selectedBlock.customParams, "name", name) ||
                getItem(scope.selectedBlock.params, "name", name);
            }

            BlockConfigService.setParamDetails(scope.selectedParam, param);
            BlockConfigService.setGenValues(
              scope.selectedParam,
              scope.selectedBlock.params,
              param.key
            );

            if (param.type == "value") {
              $rootScope.showError(
                L.tsq("Parameters of type 'value' cannot be modified.")
              );
              return;
            }

            scope.selectedParam.customMinValue =
              scope.selectedParam.minValue != scope.selectedParam.genMinValue;
            scope.selectedParam.customMaxValue =
              scope.selectedParam.maxValue != scope.selectedParam.genMaxValue;

            if (param.generation == "formula") {
              scope.onFormulaEdit(param);
            } else if (param.key == "#Symbol#") {
              $rootScope.showError(
                L.tsq("Symbol parameter cannot be modified")
              );
            } else {
              if (
                scope.selectedParam.isCombo &&
                (arrayEmpty(scope.selectedParam.options) || isChartParam(param))
              ) {
                scope.selectedParam.options = BlockConfigService.getOptions(
                  scope.selectedBlock,
                  scope.selectedParam
                );
              }
              showPopup("#" + scope.editParamPopupId);
            }

            if (
              !valueFilled(scope.selectedParam.fixedValue) &&
              valueFilled(scope.selectedParam.defaultValue)
            ) {
              scope.selectedParam.fixedValue = parseFloat(
                scope.selectedParam.defaultValue
              );
            }

            updateFixedValueLabel();

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

          function updateFixedValueLabel() {
            if (!scope.selectedParam.options) return;
            var option = getItem(
              scope.selectedParam.options,
              "value",
              scope.selectedParam.fixedValue
            );
            scope.selectedParam.fixedValueDisplay = option ? option.name : "";
          }

          scope.onSaveParamConfig = function () {
            //check values
            if (
              scope.selectedParam.generation == scope.generationTypes.random &&
              arrayNotEmpty(scope.selectedParam.options) &&
              scope.selectedParam.type != "boolean"
            ) {
              var noneChecked = true;
              for (var i = 0; i < scope.selectedParam.options.length; i++) {
                var option = scope.selectedParam.options[i];
                if (option.checked) {
                  noneChecked = false;
                  break;
                }
              }
              if (noneChecked && !scope.selectedParam.allCharts) {
                $rootScope.showError(
                  L.tsq("You must check at least one option")
                );
                return;
              }

              scope.selectedParam.values = BlockConfigService.getValuesFromOptions(
                scope.selectedParam.options
              );
            } else if (
              scope.selectedParam.generation == scope.generationTypes.fixed
            ) {
              if (!valueFilled(scope.selectedParam.fixedValue)) {
                $rootScope.showError(L.tsq("Fixed value must be set"));
                return;
              }
            }

            //save settings
            if (editingParamSet) {
              var param = getItem(
                scope.selectedParamSet.params,
                "key",
                scope.selectedParam.key
              );
              BlockConfigService.setParamDetails(param, scope.selectedParam);
              BlockConfigService.refreshSetParamsGrid(
                setParamsGrid,
                scope.selectedParamSet,
                scope.selectedBlock
              );

              scope.selectedBlock.paramSetsChanged = true;
            } else {
              var param = getItem(
                scope.selectedBlock.customParams,
                "key",
                scope.selectedParam.key
              );
              BlockConfigService.setParamDetails(param, scope.selectedParam);
              BlockConfigService.refreshParametersGrid(
                parametersGrid,
                scope.selectedBlock
              );
            }

            scope.selectedBlock.isChanged = true;

            hidePopup("#" + scope.editParamPopupId);
          };

          scope.onSaveParamSetConfig = function () {
            if (
              scope.selectedParamSet.name != scope.selectedParamSet.oldName &&
              getItem(
                scope.selectedBlock.paramSets,
                "name",
                scope.selectedParamSet.name
              )
            ) {
              $rootScope.showError(
                L.tsq(
                  "Parameter set '%s' already exists. Please choose another name",
                  [scope.selectedParamSet.name]
                )
              );
              return;
            }

            var paramSet = getItem(
              scope.selectedBlock.paramSets,
              "name",
              scope.selectedParamSet.oldName
            );
            BlockConfigService.setParamSetDetails(
              paramSet,
              scope.selectedParamSet
            );
            BlockConfigService.refreshParameterSetsGrid(
              parameterSetsGrid,
              scope.selectedBlock
            );

            scope.selectedBlock.isChanged = true;
            scope.selectedBlock.paramSetsChanged = true;

            hidePopup("#" + scope.editParamSetPopupId);
          };

          scope.refreshGrids = function () {
            $timeout(
              function () {
                window.dispatchEvent(new Event("resize"));
              },
              0,
              false
            );
          };

          scope.onResetMinMaxToDefault = function () {
            scope.selectedBlock.indicatorMin =
              scope.selectedBlock.originalIndicatorMin;
            scope.selectedBlock.indicatorMax =
              scope.selectedBlock.originalIndicatorMax;
            scope.selectedBlock.indicatorStep =
              scope.selectedBlock.originalIndicatorStep;
          };

          /**
           * Called when changing from fixed to random generation type
           */
          function onRandomParamGeneration() {
            var originalParam = getItem(
              scope.selectedBlock.params,
              "key",
              scope.selectedParam.key
            );
            BlockConfigService.setParamDetails(
              scope.selectedParam,
              originalParam
            );
            if (scope.selectedParam.isCombo) {
              scope.selectedParam.options = BlockConfigService.getOptions(
                scope.selectedBlock,
                originalParam
              );
            }
            scope.selectedParam.generation = scope.generationTypes.random;
          }

          function onFixedParamGeneration() {
            var originalParam = getItem(
              scope.selectedBlock.params,
              "key",
              scope.selectedParam.key
            );
            scope.selectedParam.fixedValue = parseFloat(
              originalParam.defaultValue
            );
            scope.selectedParam.minValue = parseFloat(
              originalParam.originalMinValue
            );
            scope.selectedParam.maxValue = parseFloat(
              originalParam.originalMaxValue
            );
            scope.selectedParam.generation = scope.generationTypes.fixed;

            updateFixedValueLabel();
          }

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

          var destroyGenerationWatch = scope.$watch(
            "selectedParam",
            function (newValue, oldValue) {
              if (newValue.key == oldValue.key) {
                if (
                  newValue.generation == scope.generationTypes.random &&
                  oldValue.generation == scope.generationTypes.fixed
                ) {
                  onRandomParamGeneration();
                } else if (
                  newValue.generation == scope.generationTypes.fixed &&
                  oldValue.generation == scope.generationTypes.random
                ) {
                  onFixedParamGeneration();
                }
              }
            },
            true
          );

          var destroyFixedValueWatch = scope.$watch(
            "selectedParam.fixedValue",
            function () {
              updateFixedValueLabel();
            }
          );

          function onEvent(event, data) {
            if (event == SQEvents.get("BLOCKS_PARAMS_RELOAD")) {
              BlockConfigService.refreshParametersGrid(
                parametersGrid,
                scope.selectedBlock
              );
              BlockConfigService.refreshParameterSetsGrid(
                parameterSetsGrid,
                scope.selectedBlock
              );
              $timeout(function () {
                window.dispatchEvent(new Event("resize"));
              });
            } else return;

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

          scope.$on("$destroy", function () {
            destroyGenerationWatch();
            destroyFixedValueWatch();
            SQEvents.removeListener(listenerId);
          });

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

          var lastIdIndex = BlockConfigService.getLastIdIndex();

          scope.parametersGridId = "block_params_grid_p" + lastIdIndex;
          scope.parameterSetsGridId = "block_params_grid_s" + lastIdIndex;
          scope.setParamsGridId = "block_params_grid_sp" + lastIdIndex;
          scope.editParamPopupId = "block_edit_param_popup" + lastIdIndex;
          scope.editParamSetPopupId = "block_edit_set_popup" + lastIdIndex;

          scope.getRealGenValue = BlockConfigService.getRealGenValue;

          var parametersGrid, parameterSetsGrid, setParamsGrid;
          var editingParamSet = false;

          scope.selectedTab = "sets";

          scope.selectedParamSet = {};
          scope.selectedParam = {};

          scope.categories = BlockConfigService.categories;
          scope.generationTypes = BlockConfigService.generationTypes;

          scope.getSpecialValueName = BlockConfigService.getSpecialValueName;

          scope.disableParamSets = "disableparamsets" in attrs;

          var listenerId = "BlockConfig-" + lastIdIndex;
          SQEvents.addListener(
            listenerId,
            [SQEvents.get("BLOCKS_PARAMS_RELOAD")],
            onEvent
          );

          $timeout(init, 1000, false);
        },
      };
    }
  );
