'use strict';
define(['ol3js', 'angular', 'toastr'], function(ol, angular, toastr) {
  var maStyle = function() {
    /* ------------------------------------------------------
     * Methods used by annotations
     */

    function getPointAnnotationShape(annotationGraphic, zoomratio) {
      var imageStyle;
      if ('SYMBOL' === annotationGraphic.styleMode && annotationGraphic.Mark) {
        imageStyle = getPointMarkerAnnotationShape(
          annotationGraphic,
          zoomratio
        );
      } else
        imageStyle = getPointSVGAnnotationShape(annotationGraphic, zoomratio);
      if (imageStyle == undefined) return undefined;
      else
        return {
          image: imageStyle,
        };
    }

    function getCssParameterByName(cssParameters, hitParamName) {
      for (var i in cssParameters) {
        var cssParam = cssParameters[i];
        if (cssParam && hitParamName === cssParam._name) return cssParam;
      }

      return null;
    }

    function getTextAnnotationShape(
      annotationGraphic,
      zoomRatio,
      params,
      withText
    ) {
      if (withText == undefined) withText = true;
      var stroke = getStroke(annotationGraphic, undefined, zoomRatio);
      var template = getDefaultTemplate('Label');
      //-- Taille fixe ou proportionnelle
      template.fixedSize = annotationGraphic.fixedSize;
      //-- Couleur autour du texte
      if (annotationGraphic.noColorFill)
        template.text.stroke.color = 'rgba(0,0,0,0)';
      else if (stroke != undefined && stroke.color_)
        template.text.stroke.color = stroke.color_;
      else if (annotationGraphic.stroke != undefined)
        template.text.stroke.color = annotationGraphic.stroke.color;
      //-- Couleur des caractéres du texte
      if (annotationGraphic.Fill != undefined)
        template.text.fill.color =
          annotationGraphic.Fill.CssParameter[0].__text;
      else if (annotationGraphic.fill != undefined)
        template.text.fill.color = annotationGraphic.fill.color;

      var font = template.text.font;
      var elts = font.split(' ');
      var size = parseInt(elts[0]) * zoomRatio;
      elts[0] = size.toFixed() + 'px';
      font = elts.join(' ');
      if (params && params.textStrokeWidth != undefined)
        if (params.textStrokeWidth == 0) template.text.stroke.width = 0;
        else template.text.stroke.width = params.textStrokeWidth;
      template.text.stroke.width = 0;
      //template.text.fill.color = 'rgba(0,0,0,0)';
      var styleText = {
        font: font,
        rotation: (annotationGraphic.Rotation * Math.PI) / 180,
        fill: new ol.style.Fill(template.text.fill),
      };
      if (withText) styleText.text = annotationGraphic.textValue;
      if (params) {
        if (params.offsetX) styleText.offsetX = params.offsetX;
        if (params.offsetY) styleText.offsetY = params.offsetY;
        if (params.textBaseline) styleText.textBaseline = params.textBaseline;
      }

      return {
        text: new ol.style.Text(styleText),
      };
    }

    function getSymbolStyleMarker(scale, feat, annotationGraphic, zoomratio) {
      var imgStyleOptions = {};
      var imgStyle, anchor;
      var markerType = annotationGraphic.Mark.WellKnownName;

      imgStyleOptions.src = location.origin + location.pathname;
      imgStyleOptions.src += 'img/print/' + markerType + '.png';

      imgStyleOptions.size = feat
        .getStyle()
        .getImage()
        .getSize();
      anchor = feat
        .getStyle()
        .getImage()
        .getAnchor();
      if (anchor != null)
        imgStyleOptions.anchor = [
          anchor[0] / imgStyleOptions.size[0],
          anchor[1] / imgStyleOptions.size[1],
        ];
      imgStyle = new ol.style.Icon(imgStyleOptions);

      imgStyle.setRotation(
        (feat
          .getStyle()
          .getImage()
          .getRotation() *
          180) /
          Math.PI
      );
      // imgStyle.setScale(feat.getProperties().styleTemplate.image.scale)

      var ratio;
      scale > feat.getProperties().styleTemplate.scale100
        ? (ratio = feat.getProperties().styleTemplate.scale100 / scale)
        : (ratio = scale / feat.getProperties().styleTemplate.scale100);
      imgStyle.setScale(feat.getProperties().styleGraphic.image.scale * ratio);

      return new ol.style.Style({ image: imgStyle });
    }
    function getPolylineAnnotationShape(annotationGraphic, zoomratio) {
      var stroke = getStroke(annotationGraphic, undefined, zoomratio);

      return {
        stroke: stroke,
      };
    }

    function getPolygonAnnotationShape(annotationGraphic, zoomratio) {
      if ('SYMBOL' === annotationGraphic.styleMode)
        return getSimplePolygonAnnotationShape(annotationGraphic, zoomratio);
      else return getHashedPolygonAnnotationShape(annotationGraphic);
    }
    function hexToRGB(hex, alpha) {
      var r = parseInt(hex.slice(1, 3), 16),
        g = parseInt(hex.slice(3, 5), 16),
        b = parseInt(hex.slice(5, 7), 16);

      if (alpha) {
        return 'rgba(' + r + ', ' + g + ', ' + b + ', ' + alpha + ')';
      } else {
        return 'rgb(' + r + ', ' + g + ', ' + b + ')';
      }
    }
    function getSimplePolygonAnnotationShape(annotationGraphic, zoomratio) {
      var fill = getFill(annotationGraphic);
      var stroke = getStroke(annotationGraphic, undefined, zoomratio);
      if (fill != null && annotationGraphic.opacity) {
        var colFill = fill.getColor();
        var newCol;
        var newOpa = annotationGraphic.opacity / 100;
        if (colFill.includes('#')) {
          newCol = hexToRGB(colFill, newOpa);
        } else {
          newCol =
            colFill.substr(0, colFill.lastIndexOf(',') + 1) + newOpa + ')';
        }
        fill.setColor(newCol);
      }
      return {
        fill: fill,
        stroke: stroke,
      };
    }

    function getHashedPolygonAnnotationShape(annotationGraphic) {
      //console.log(annotationGraphic);

      var hashColor;
      var simpleFill = getFill(annotationGraphic);
      if (!annotationGraphic.opacity) {
        annotationGraphic.opacity = 1;
      }
      if (annotationGraphic.Fill != null) {
        hashColor = getCssParameterByName(
          annotationGraphic.Fill.CssParameter,
          'hash-color'
        ).__text;
      } else {
        hashColor = 'rgba(220,220,220,1)';
      }
      var fill = new ol.style.FillPattern({
        //pattern: annotationGraphic.hashtemplate,
        pattern: annotationGraphic.hashtemplate,
        ratio: 1,
        color: hashColor,
        offset: 0,
        scale: 1,
        fill: simpleFill,
        size: 5,
        spacing: 10,
        opacity: annotationGraphic.opacity,
        angle: 0,
      });

      var stroke = getStroke(annotationGraphic);

      return {
        fill: fill,
        stroke: stroke,
        rotation: annotationGraphic.Rotation,
      };
    }

    function getPointSVGAnnotationShape(annotationGraphic, zoomratio) {
      //console.log(annotationGraphic.ExternalGraphic.Format);
      //src: annotationGraphic.ExternalGraphic.OnlineResource._href,
      var src;
      if (annotationGraphic.image && annotationGraphic.image.src) {
        src = annotationGraphic.image.src;
      } else {
        if (annotationGraphic.ExternalGraphic != undefined)
          src = annotationGraphic.ExternalGraphic.OnlineResource._href;
      }
      if (src == undefined) return undefined;
      else
        return new ol.style.Icon({
          src: src,
          scale: parseFloat(annotationGraphic.Size) * zoomratio,
          rotation: (annotationGraphic.Rotation * Math.PI) / 180,
          anchor: [
            annotationGraphic.Displacement.DisplacementX,
            annotationGraphic.Displacement.DisplacementY,
          ],
        });
    }

    function hexToRGBA(hex, opacity) {
      if (hex.length != 7) return 'rgba(220,220,220,1)';
      else
        return (
          'rgba(' +
          (hex = hex.replace('#', ''))
            .match(new RegExp('(.{' + hex.length / 3 + '})', 'g'))
            .map(function(l) {
              return parseInt(hex.length % 2 ? l + l : l, 16);
            })
            .concat(opacity || 1)
            .join(',') +
          ')'
        );
    }

    function getFill(annotationGraphic, opacity) {
      if (
        (annotationGraphic.noColorFill == null ||
          annotationGraphic.noColorFill == false) &&
        annotationGraphic.Fill != undefined
      ) {
        var color = getCssParameterByName(
          annotationGraphic.Fill.CssParameter,
          'fill'
        ).__text;
        return color
          ? new ol.style.Fill({ color: hexToRGBA(color, opacity / 100.0) })
          : null;
      } else return null;
    }

    function getStroke(annotationGraphic, isSimple, zoomratio, opacity) {
      var stroke = null;

      if (angular.isDefined(annotationGraphic.Stroke)) {
        if (opacity == undefined) opacity = 100.0;
        var strokeCssParameters = annotationGraphic.Stroke.CssParameter;
        var strokeWidth = getCssParameterByName(
          strokeCssParameters,
          'stroke-width'
        ).__text;
        var nStrokeWidth =
          strokeWidth == null || strokeWidth.length == 0
            ? 1
            : parseInt(strokeWidth);
        nStrokeWidth *= zoomratio;
        var strokeConfig = {
          color: hexToRGBA(
            getCssParameterByName(strokeCssParameters, 'stroke').__text,
            opacity / 100.0
          ),
          width: nStrokeWidth,
        };

        if (
          annotationGraphic.type != 'TextSymbolizer' &&
          (isSimple == undefined || isSimple == false)
        ) {
          var strokeLineJoin = getCssParameterByName(
            strokeCssParameters,
            'stroke-linejoin'
          ).__text;
          if (strokeLineJoin != null && strokeLineJoin.length > 0)
            strokeConfig.lineJoin = strokeLineJoin;
        }
        let strokeDashArray = getCssParameterByName(
          strokeCssParameters,
          'stroke-dasharray'
        );
        if (strokeDashArray != null) strokeDashArray = strokeDashArray.__text;
        if (strokeDashArray != null && strokeDashArray.length > 0) {
          strokeConfig.lineDash = strokeDashArray.split(' ');
          strokeConfig.lineDash = strokeConfig.lineDash.map(function(x) {
            return parseFloat(x) * nStrokeWidth;
          });
        }
        stroke = new ol.style.Stroke(strokeConfig);
      }

      return stroke;
    }

    function getPointMarkerAnnotationShape(annotationGraphic, zoomratio) {
      var markerType = annotationGraphic.Mark.WellKnownName;

      var styleDesc = {};
      styleDesc.radius = parseFloat(annotationGraphic.Size) * zoomratio;
      styleDesc.fill = getFill(
        annotationGraphic.Mark,
        annotationGraphic.opacity
      );
      styleDesc.stroke = getStroke(
        annotationGraphic.Mark,
        true,
        zoomratio,
        annotationGraphic.opacity
      );

      if (angular.isDefined(styleDesc.stroke) && styleDesc.stroke != null) {
        styleDesc.stroke.width_ *= zoomratio;
      }

      styleDesc.offset = [
        annotationGraphic.Displacement.DisplacementX,
        annotationGraphic.Displacement.DisplacementY,
      ];

      if (markerType == 'shape://oarrow' || markerType == 'shape://carrow') {
        styleDesc.rotation =
          (annotationGraphic.Rotation * Math.PI) / 180 - Math.PI / 6;
      } else {
        styleDesc.rotation = (annotationGraphic.Rotation * Math.PI) / 180;
      }

      switch (markerType) {
        case 'circle':
          return new ol.style.Circle(styleDesc);

        case 'square':
          styleDesc.points = 4;
          styleDesc.angle = Math.PI / 4;
          return new ol.style.RegularShape(styleDesc);

        case 'triangle':
          styleDesc.points = 3;
          styleDesc.angle = 0;
          return new ol.style.RegularShape(styleDesc);

        case 'star':
          styleDesc.points = 5;
          styleDesc.radius2 = 4;
          styleDesc.angle = 0;
          return new ol.style.RegularShape(styleDesc);

        case 'cross':
          styleDesc.points = 4;
          styleDesc.radius2 = 0;
          styleDesc.angle = 0;
          return new ol.style.RegularShape(styleDesc);

        case 'x':
          styleDesc.points = 4;
          styleDesc.radius2 = 0;
          styleDesc.angle = Math.PI / 4;
          return new ol.style.RegularShape(styleDesc);
        case 'shape://oarrow':
          styleDesc.points = 3;
          styleDesc.angle = 0;
          styleDesc.stroke.setLineCap('square');
          styleDesc.stroke.setLineDash([parseFloat(3.45 * styleDesc.radius)]);
          return new ol.style.RegularShape(styleDesc);
        case 'shape://carrow':
          styleDesc.points = 3;
          styleDesc.angle = 0;
          return new ol.style.RegularShape(styleDesc);
      }

      styleDesc.points = 4;
      styleDesc.radius = 10 * zoomratio;
      styleDesc.angle = Math.PI / 4;
      return new ol.style.RegularShape(styleDesc);
    }

    /*
     * Generate an OpenLayers style from a style template
     */
    function getAnnotationStyle(
      type,
      annotationGraphic,
      zoomratio,
      params,
      withText
    ) {
      var styleConfig = null;
      if (zoomratio == undefined) zoomratio = 1.0;
      switch (type) {
        case 'Point':
          styleConfig = getPointAnnotationShape(annotationGraphic, zoomratio);
          break;
        case 'Polygon':
          styleConfig = getPolygonAnnotationShape(annotationGraphic, zoomratio);
          break;
        case 'LineString':
          styleConfig = getPolylineAnnotationShape(
            annotationGraphic,
            zoomratio
          );
          break;
        case 'text':
        case 'Text':
          styleConfig = getTextAnnotationShape(
            annotationGraphic,
            zoomratio,
            params,
            withText
          );
          break;
      }

      if (styleConfig == undefined) return undefined;
      else return new ol.style.Style(styleConfig);
    }

    /*
     * Generate an OpenLayers style from a style template
     */
    function getDefaultStyle(type, styleTemplate) {
      let style = {};
      switch (type) {
        case 'Point':
          style.image = new ol.style.Circle({
            radius: styleTemplate.image.radius,
            fill: new ol.style.Fill(styleTemplate.image.fill),
          });
          break;
        case 'Symbol':
          style.image = new ol.style.Icon({
            //anchor: [0.5, 46],
            //anchorXUnits: 'fraction',
            //anchorYUnits: 'pixels',
            opacity: 1,
            src: styleTemplate.image.src,
            scale: styleTemplate.image.scale,
            rotation: styleTemplate.image.rotation,
          });
          break;
        case 'text':
        case 'Text':
        case 'Label':
          style.text = new ol.style.Text({
            text: styleTemplate.text.text,
            font: styleTemplate.text.font,
            //offsetX: styleTemplate.text.offsetX,
            //offsetY: styleTemplate.text.offsetY,
            rotation: styleTemplate.text.rotation,
            fill: new ol.style.Fill(styleTemplate.text.fill),
            stroke: new ol.style.Stroke(styleTemplate.text.stroke),
          });
          break;
        case 'Polygon':
          style.fill = new ol.style.Fill(styleTemplate.fill);
          style.stroke = new ol.style.Stroke(styleTemplate.stroke);

          break;
        case 'LineString':
          style.stroke = new ol.style.Stroke(styleTemplate.stroke);
          break;
      }
      let result = new ol.style.Style(style);
      return result;
    }

    /*
     * Provide a style template for the given annotation type.
     * They can be edited with the user interface, can be stored,
     * and transformed into OpenLayers styles when needed.
     * We cannot edit or store OpenLayers styles directly.
     */
    function getDefaultTemplate(type) {
      var templates = {
        Point: {
          image: {
            radius: 5,
            fill: { color: '#d35400' },
          },
        },
        Symbol: {
          image: {
            src: 'img/widget/gsw/gsw_01.png',
            scale: 1,
            rotation: 0,
          },
        },
        LineString: {
          stroke: {
            color: '#d35400',
            width: 3,
          },
        },
        Polygon: {
          stroke: {
            color: '#d35400',
            width: 3,
          },
          fill: { color: 'rgba(255,255,255,0.4)' },
          opacity: 100,
        },
        Text: {
          text: '',
          backgroundColor: '#ffffff',
          textColor: '#000000',
          opacity: 100,
          image: {
            radius: 7,
            fill: { color: '#f6c531' },
          },
        },
        Label: {
          text: {
            text: 'Label',
            font: '16px sans-serif',
            //offsetX: 0,
            //offsetY: 0,
            rotation: 0,
            fill: { color: '#ffffff' },
            stroke: {
              // outline
              color: '#000000',
              width: 2,
            },
          },
        },
      };
      if (templates[type]) {
        return templates[type];
      }
    }

    return {
      getDefaultStyle: getDefaultStyle,
      getAnnotationStyle: getAnnotationStyle,
      getDefaultTemplate: getDefaultTemplate,
      getSymbolStyleMarker: getSymbolStyleMarker,
    };
  };

  maStyle.$inject = [];
  return maStyle;
});
