// Copyright © Selmo Technology GmbH. All Rights Reserved

using SelmoStudio.Hmi.Server.SelmoHmi.Sequence.Model.Dto;
using System.Drawing;
using System.Text;

namespace SelmoStudio.Hmi.Server.Shared.Model.Diagram
{
    internal class DiagramSvgMapper
    {
        internal static string ToHtml(LogicDiagram diagramDto, LogicDiagramStep activeStep)
        {
            var viewport = CalculateViewport(diagramDto);

            StringBuilder sb = new StringBuilder();
            sb.AppendLine($"<svg viewBox=\"{viewport.X} {viewport.Y} {viewport.Width} {viewport.Height}\">");

            sb.AppendLine(CreateStepSvg(diagramDto.Steps, activeStep));
            sb.AppendLine(CreateConnectorsSvg(diagramDto.Connections));

            sb.AppendLine("</svg>");

            return sb.ToString();
        }

        public static (double X, double Y, double Width, double Height) CalculateViewport(LogicDiagram diagramDto)
        {
            var minX = double.PositiveInfinity;
            var minY = double.PositiveInfinity;
            var maxX = double.NegativeInfinity;
            var maxY = double.NegativeInfinity;

            foreach (var step in diagramDto.Steps)
            {
                minX = Math.Min(minX, step.DiagramPositionX);
                minY = Math.Min(minY, step.DiagramPositionY);
                maxX = Math.Max(maxX, step.DiagramPositionX + step.SizeX);
                maxY = Math.Max(maxY, step.DiagramPositionY + step.SizeY);
            }

            foreach (var connection in diagramDto.Connections)
            {
                minX = Math.Min(minX, Math.Min(connection.DiagramPositionX, Math.Min(connection.DiagramBezierStartPointX,
                    Math.Min(connection.DiagramBezierEndPointX, Math.Min(connection.DiagramStartPointX, connection.DiagramEndPointX)))));
                minY = Math.Min(minY, Math.Min(connection.DiagramPositionY, Math.Min(connection.DiagramBezierStartPointY,
                    Math.Min(connection.DiagramBezierEndPointY, Math.Min(connection.DiagramStartPointY, connection.DiagramEndPointY)))));
                maxX = Math.Max(maxX, Math.Max(connection.DiagramPositionX, Math.Max(connection.DiagramBezierStartPointX,
                    Math.Max(connection.DiagramBezierEndPointX, Math.Max(connection.DiagramStartPointX, connection.DiagramEndPointX)))));
                maxY = Math.Max(maxY, Math.Max(connection.DiagramPositionY, Math.Max(connection.DiagramBezierStartPointY,
                    Math.Max(connection.DiagramBezierEndPointY, Math.Max(connection.DiagramStartPointY, connection.DiagramEndPointY)))));
            }

            var padding = 20;
            minX -= padding;
            minY -= padding;
            maxX += padding;
            maxY += padding;

            var width = maxX - minX;
            var height = maxY - minY;

            return (minX, minY, width, height);
        }

        private static string CreateStepSvg(List<LogicDiagramStep> steps, LogicDiagramStep activeStep)
        {
            StringBuilder sb = new StringBuilder();
            foreach (LogicDiagramStep step in steps)
            {
                sb.AppendLine(ToSvgPath(step, activeStep != null ? step.Id.Equals(activeStep.Id) : false));
            }

            return sb.ToString();
        }

        private static string ToSvgPath(LogicDiagramStep step, bool isActiveStep)
        {
            return DiagramElementCreator.GetElement(step, isActiveStep);
        }

        private static string CreateConnectorsSvg(List<LogicDiagramConnection> connections)
        {
            StringBuilder sb = new StringBuilder();
            foreach (LogicDiagramConnection connection in connections)
            {
                sb.AppendLine("<g>");
                sb.AppendLine(ConnectorToSvgPath(connection));
                sb.AppendLine(ArrowMarkerToSvgPath(connection));
                sb.AppendLine("</g>");
            }

            return sb.ToString();
        }

        private static string ConnectorToSvgPath(LogicDiagramConnection connection)
        {
            return DiagramElementCreator.GetConnector(connection);
        }

        private static string ArrowMarkerToSvgPath(LogicDiagramConnection connection)
        {
            return DiagramElementCreator.GetArrowMarker(connection);
        }
    }
}