import * as d3 from 'd3';
import _ from 'lodash';
import { geoExtent, geoPolygonIntersectsPolygon } from '../geo/index';
import { utilDetect } from '../util/detect';
import toGeoJSON from '@mapbox/togeojson';


export function svgGpx(projection, context, dispatch) {
    var showLabels = true,
        detected = utilDetect(),
        layer;


    function init() {
        if (svgGpx.initialized) return;  // run once

        svgGpx.geojson = {};
        svgGpx.enabled = true;

        function over() {
            d3.event.stopPropagation();
            d3.event.preventDefault();
            d3.event.dataTransfer.dropEffect = 'copy';
        }

        d3.select('body')
            .attr('dropzone', 'copy')
            .on('drop.localgpx', function() {
                d3.event.stopPropagation();
                d3.event.preventDefault();
                if (!detected.filedrop) return;
                drawGpx.files(d3.event.dataTransfer.files);
            })
            .on('dragenter.localgpx', over)
            .on('dragexit.localgpx', over)
            .on('dragover.localgpx', over);

        svgGpx.initialized = true;
    }


    function drawGpx(selection) {
        var geojson = svgGpx.geojson,
            enabled = svgGpx.enabled;

        layer = selection.selectAll('.layer-gpx')
            .data(enabled ? [0] : []);

        layer.exit()
            .remove();

        layer = layer.enter()
            .append('g')
            .attr('class', 'layer-gpx')
            .merge(layer);


        var paths = layer
            .selectAll('path')
            .data([geojson]);

        paths.exit()
            .remove();

        paths = paths.enter()
            .append('path')
            .attr('class', 'gpx')
            .merge(paths);


        var path = d3.geoPath(projection);

        paths
            .attr('d', path);


        var labels = layer.selectAll('text')
            .data(showLabels && geojson.features ? geojson.features : []);

        labels.exit()
            .remove();

        labels = labels.enter()
            .append('text')
            .attr('class', 'gpx')
            .merge(labels);

        labels
            .text(function(d) {
                return d.properties.desc || d.properties.name;
            })
            .attr('x', function(d) {
                var centroid = path.centroid(d);
                return centroid[0] + 7;
            })
            .attr('y', function(d) {
                var centroid = path.centroid(d);
                return centroid[1];
            });

    }


    function toDom(x) {
        return (new DOMParser()).parseFromString(x, 'text/xml');
    }


    function getExtension(fileName) {
        if (_.isUndefined(fileName)) {
            return '';
        }

        var lastDotIndex = fileName.lastIndexOf('.');
        if (lastDotIndex < 0) {
            return '';
        }

        return fileName.substr(lastDotIndex);
    }


    function parseSaveAndZoom(extension, data) {
        switch (extension) {
            default:
                drawGpx.geojson(toGeoJSON.gpx(toDom(data))).fitZoom();
                break;
            case '.kml':
                drawGpx.geojson(toGeoJSON.kml(toDom(data))).fitZoom();
                break;
            case '.geojson':
            case '.json':
                drawGpx.geojson(JSON.parse(data)).fitZoom();
                break;
        }
    }


    drawGpx.showLabels = function(_) {
        if (!arguments.length) return showLabels;
        showLabels = _;
        return this;
    };


    drawGpx.enabled = function(_) {
        if (!arguments.length) return svgGpx.enabled;
        svgGpx.enabled = _;
        dispatch.call('change');
        return this;
    };


    drawGpx.hasGpx = function() {
        var geojson = svgGpx.geojson;
        return (!(_.isEmpty(geojson) || _.isEmpty(geojson.features)));
    };


    drawGpx.geojson = function(gj) {
        if (!arguments.length) return svgGpx.geojson;
        if (_.isEmpty(gj) || _.isEmpty(gj.features)) return this;
        svgGpx.geojson = gj;
        dispatch.call('change');
        return this;
    };


    drawGpx.url = function(url) {
        d3.text(url, function(err, data) {
            if (!err) {
                var extension = getExtension(url);
                parseSaveAndZoom(extension, data);
            }
        });
        return this;
    };


    drawGpx.files = function(fileList) {
        if (!fileList.length) return this;
        var f = fileList[0],
            reader = new FileReader();

        reader.onload = (function(file) {
            var extension = getExtension(file.name);

            return function (e) {
                parseSaveAndZoom(extension, e.target.result);
            };
        })(f);

        reader.readAsText(f);
        return this;
    };


    drawGpx.fitZoom = function() {
        if (!this.hasGpx()) return this;
        var geojson = svgGpx.geojson;

        var map = context.map(),
            viewport = map.trimmedExtent().polygon(),
            coords = _.reduce(geojson.features, function(coords, feature) {
                var c = feature.geometry.coordinates;

                /* eslint-disable no-fallthrough */
                switch (feature.geometry.type) {
                    case 'Point':
                        c = [c];
                    case 'MultiPoint':
                    case 'LineString':
                        break;

                    case 'MultiPolygon':
                        c = _.flatten(c);
                    case 'Polygon':
                    case 'MultiLineString':
                        c = _.flatten(c);
                        break;
                }
                /* eslint-enable no-fallthrough */

                return _.union(coords, c);
            }, []);

        if (!geoPolygonIntersectsPolygon(viewport, coords, true)) {
            var extent = geoExtent(d3.geoBounds({ type: 'LineString', coordinates: coords }));
            map.centerZoom(extent.center(), map.trimmedExtentZoom(extent));
        }

        return this;
    };


    init();
    return drawGpx;
}
