import _ from 'lodash';
import {
    svgPointTransform,
    svgTagClasses
} from './index';

import {
    geoAngle,
    geoEuclideanDistance,
    geoInterp,
    geoLineIntersection
} from '../geo/index';


export function svgMidpoints(projection, context) {

    return function drawMidpoints(selection, graph, entities, filter, extent) {
        var layer = selection.selectAll('.layer-hit');

        var mode = context.mode();
        if (mode && mode.id !== 'select') {
            layer.selectAll('g.midpoint').remove();
            return;
        }

        var poly = extent.polygon(),
            midpoints = {};

        for (var i = 0; i < entities.length; i++) {
            var entity = entities[i];

            if (entity.type !== 'way')
                continue;
            if (!filter(entity))
                continue;
            if (context.selectedIDs().indexOf(entity.id) < 0)
                continue;

            var nodes = graph.childNodes(entity);
            for (var j = 0; j < nodes.length - 1; j++) {

                var a = nodes[j],
                    b = nodes[j + 1],
                    id = [a.id, b.id].sort().join('-');

                if (midpoints[id]) {
                    midpoints[id].parents.push(entity);
                } else {
                    if (geoEuclideanDistance(projection(a.loc), projection(b.loc)) > 40) {
                        var point = geoInterp(a.loc, b.loc, 0.5),
                            loc = null;

                        if (extent.intersects(point)) {
                            loc = point;
                        } else {
                            for (var k = 0; k < 4; k++) {
                                point = geoLineIntersection([a.loc, b.loc], [poly[k], poly[k + 1]]);
                                if (point &&
                                    geoEuclideanDistance(projection(a.loc), projection(point)) > 20 &&
                                    geoEuclideanDistance(projection(b.loc), projection(point)) > 20)
                                {
                                    loc = point;
                                    break;
                                }
                            }
                        }

                        if (loc) {
                            midpoints[id] = {
                                type: 'midpoint',
                                id: id,
                                loc: loc,
                                edge: [a.id, b.id],
                                parents: [entity]
                            };
                        }
                    }
                }
            }
        }


        function midpointFilter(d) {
            if (midpoints[d.id])
                return true;

            for (var i = 0; i < d.parents.length; i++) {
                if (filter(d.parents[i])) {
                    return true;
                }
            }

            return false;
        }


        var groups = layer
            .selectAll('g.midpoint')
            .filter(midpointFilter)
            .data(_.values(midpoints), function(d) { return d.id; });

        groups.exit()
            .remove();

        var enter = groups.enter()
            .insert('g', ':first-child')
            .attr('class', 'midpoint');

        enter.append('polygon')
            .attr('points', '-6,8 10,0 -6,-8')
            .attr('class', 'shadow');

        enter.append('polygon')
            .attr('points', '-3,4 5,0 -3,-4')
            .attr('class', 'fill');

        groups = groups
            .merge(enter)
            .attr('transform', function(d) {
                var translate = svgPointTransform(projection),
                    a = graph.entity(d.edge[0]),
                    b = graph.entity(d.edge[1]),
                    angleVal = Math.round(geoAngle(a, b, projection) * (180 / Math.PI));
                return translate(d) + ' rotate(' + angleVal + ')';
            })
            .call(svgTagClasses().tags(
                function(d) { return d.parents[0].tags; }
            ));

        // Propagate data bindings.
        groups.select('polygon.shadow');
        groups.select('polygon.fill');

    };
}
