package ru.yandex.webmaster3.core.digest.graphics.draw;

import com.google.common.collect.Lists;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ru.yandex.webmaster3.core.digest.graphics.draw.data.*;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * Created by ifilippov5 on 19.09.17.
 */
public class DrawGraphUtil {
    private static final Logger log = LoggerFactory.getLogger(DrawGraphUtil.class);
    private static final int SECTORS_COUNT = 3;
    private static final int MARGIN_Y = 0;

    public static String draw(List<PointLong> pastSeries, List<PointLong> currentSeries, ChartSettings chartSettings) {
        List<PointLong> points = new ArrayList<>();
        points.clear();
        points.addAll(pastSeries);
        points.addAll(currentSeries);
        ComputeBordersUtil.FrameBoundaries frame =
                ComputeBordersUtil.computeBorders(points, SECTORS_COUNT);

        //инвертируем по оси Y
        pastSeries = pastSeries.stream().map(point -> new PointLong(point.getX(), frame.top - point.getY() + frame.bottom)).collect(Collectors.toList());
        currentSeries = currentSeries.stream().map(point -> new PointLong(point.getX(), frame.top - point.getY() + frame.bottom)).collect(Collectors.toList());

        int chartWidth = chartSettings.getChartWidth();
        int chartHeight = chartSettings.getChartHeight() - MARGIN_Y;

        double scaleCoeffX = computeScaleCoeff(frame.left, frame.right, chartWidth);
        double scaleCoeffY = computeScaleCoeff(frame.bottom, frame.top, chartHeight - MARGIN_Y);
        Polyline pastPolyline = createScaledSeries(frame.left, scaleCoeffX, frame.bottom, scaleCoeffY, pastSeries, chartHeight, chartWidth);
        Polyline currentPolyline = createScaledSeries(frame.left, scaleCoeffX, frame.bottom, scaleCoeffY, currentSeries, chartHeight, chartWidth);

        List<SecondaryAxisX> axes = new ArrayList<>();
        Iterator<Long> reverseDivisions = Lists.reverse(frame.axisYDivisions).iterator();
        for (long division : frame.axisYDivisions) {
            double yCoordinate = (division - frame.bottom) * scaleCoeffY + MARGIN_Y;
            SecondaryAxisX axis = new SecondaryAxisX(yCoordinate,
                    Label.createLabel(new Point(6, yCoordinate + chartSettings.getLabelRy()),
                            reverseDivisions.next()));
            axes.add(axis);
        }

        return ChartGeneratorUtil.generateSvg(pastPolyline, currentPolyline, axes, chartSettings);
    }

    private static double computeScaleCoeff(long min, long max, long value) {
        return (double)value / (max - min);
    }

    private static Point toPoint(PointLong point) {
        return new Point(point.getX(), point.getY());
    }

    private static Polyline createScaledSeries(double shiftX, double scaleCoeffX, double shiftY, double scaleCoeffY, List<PointLong> points,
                                               double height, double width) {
        List<Point> scaledPoints = points.stream().map(DrawGraphUtil::toPoint).map(point ->
                point.scale(shiftX, scaleCoeffX, shiftY, scaleCoeffY, MARGIN_Y, height, width)).collect(Collectors.toList());
        return new Polyline(scaledPoints);
    }
}
