import * as d3 from 'd3';
import { d3keybinding } from '../lib/d3.keybinding.js';
import { t, textDirection } from '../util/locale';
import { actionChangePreset } from '../actions/index';
import { operationDelete } from '../operations/index';
import { modeBrowse } from '../modes/index';
import { svgIcon } from '../svg/index';
import { uiPresetIcon } from './preset_icon';
import { uiTagReference } from './tag_reference';
import { utilNoAuto, utilRebind } from '../util';


export function uiPresetList(context) {
    var dispatch = d3.dispatch('choose'),
        id,
        currentPreset,
        autofocus = false;


    function presetList(selection) {
        var entity = context.entity(id),
            geometry = context.geometry(id);

        // Treat entities on addr:interpolation lines as points, not vertices (#3241)
        if (geometry === 'vertex' && entity.isOnAddressLine(context.graph())) {
            geometry = 'point';
        }

        var presets = context.presets().matchGeometry(geometry);

        selection.html('');

        var messagewrap = selection
            .append('div')
            .attr('class', 'header fillL cf');

        var message = messagewrap
            .append('h3')
            .text(t('inspector.choose'));

        if (context.entity(id).isUsed(context.graph())) {
            messagewrap
                .append('button')
                .attr('class', 'preset-choose')
                .on('click', function() { dispatch.call('choose', this, currentPreset); })
                .call(svgIcon((textDirection === 'rtl') ? '#icon-backward' : '#icon-forward'));
        } else {
            messagewrap
                .append('button')
                .attr('class', 'close')
                .on('click', function() {
                    context.enter(modeBrowse(context));
                })
                .call(svgIcon('#icon-close'));
        }

        function keydown() {
            // hack to let delete shortcut work when search is autofocused
            if (search.property('value').length === 0 &&
                (d3.event.keyCode === d3keybinding.keyCodes['⌫'] ||
                 d3.event.keyCode === d3keybinding.keyCodes['⌦'])) {
                d3.event.preventDefault();
                d3.event.stopPropagation();
                operationDelete([id], context)();
            } else if (search.property('value').length === 0 &&
                (d3.event.ctrlKey || d3.event.metaKey) &&
                d3.event.keyCode === d3keybinding.keyCodes.z) {
                d3.event.preventDefault();
                d3.event.stopPropagation();
                context.undo();
            } else if (!d3.event.ctrlKey && !d3.event.metaKey) {
                d3.select(this).on('keydown', null);
            }
        }

        function keypress() {
            // enter
            var value = search.property('value');
            if (d3.event.keyCode === 13 && value.length) {
                list.selectAll('.preset-list-item:first-child').datum().choose();
            }
        }

        function inputevent() {
            var value = search.property('value');
            list.classed('filtered', value.length);
            if (value.length) {
                var results = presets.search(value, geometry);
                message.text(t('inspector.results', {
                    n: results.collection.length,
                    search: value
                }));
                list.call(drawList, results);
            } else {
                list.call(drawList, context.presets().defaults(geometry, 36));
                message.text(t('inspector.choose'));
            }
        }

        var searchWrap = selection
            .append('div')
            .attr('class', 'search-header');

        var search = searchWrap
            .append('input')
            .attr('class', 'preset-search-input')
            .attr('placeholder', t('inspector.search'))
            .attr('type', 'search')
            .call(utilNoAuto)
            .on('keydown', keydown)
            .on('keypress', keypress)
            .on('input', inputevent);

        searchWrap
            .call(svgIcon('#icon-search', 'pre-text'));

        if (autofocus) {
            search.node().focus();
        }

        var listWrap = selection
            .append('div')
            .attr('class', 'inspector-body');

        var list = listWrap
            .append('div')
            .attr('class', 'preset-list fillL cf')
            .call(drawList, context.presets().defaults(geometry, 36));
    }


    function drawList(list, presets) {
        var collection = presets.collection.map(function(preset) {
            return preset.members ? CategoryItem(preset) : PresetItem(preset);
        });

        var items = list.selectAll('.preset-list-item')
            .data(collection, function(d) { return d.preset.id; });

        items.order();

        items.exit()
            .remove();

        items.enter()
            .append('div')
            .attr('class', function(item) { return 'preset-list-item preset-' + item.preset.id.replace('/', '-'); })
            .classed('current', function(item) { return item.preset === currentPreset; })
            .each(function(item) { d3.select(this).call(item); })
            .style('opacity', 0)
            .transition()
            .style('opacity', 1);
    }


    function CategoryItem(preset) {
        var box, sublist, shown = false;

        function item(selection) {
            var wrap = selection.append('div')
                .attr('class', 'preset-list-button-wrap category col12');

            var button = wrap
                .append('button')
                .attr('class', 'preset-list-button')
                .classed('expanded', false)
                .call(uiPresetIcon()
                    .geometry(context.geometry(id))
                    .preset(preset))
                .on('click', function() {
                    var isExpanded = d3.select(this).classed('expanded');
                    var iconName = isExpanded ?
                        (textDirection === 'rtl' ? '#icon-backward' : '#icon-forward') : '#icon-down';
                    d3.select(this)
                        .classed('expanded', !isExpanded);
                    d3.select(this).selectAll('div.label svg.icon use')
                        .attr('href', iconName);
                    item.choose();
                });

            var label = button
                .append('div')
                .attr('class', 'label');

            label
                .call(svgIcon((textDirection === 'rtl' ? '#icon-backward' : '#icon-forward'), 'inline'))
                .append('span')
                .html(function() { return preset.name() + '&hellip;'; });

            box = selection.append('div')
                .attr('class', 'subgrid col12')
                .style('max-height', '0px')
                .style('opacity', 0);

            box.append('div')
                .attr('class', 'arrow');

            sublist = box.append('div')
                .attr('class', 'preset-list fillL3 cf fl');
        }


        item.choose = function() {
            if (!box || !sublist) return;

            if (shown) {
                shown = false;
                box.transition()
                    .duration(200)
                    .style('opacity', '0')
                    .style('max-height', '0px')
                    .style('padding-bottom', '0px');
            } else {
                shown = true;
                sublist.call(drawList, preset.members);
                box.transition()
                    .duration(200)
                    .style('opacity', '1')
                    .style('max-height', 200 + preset.members.collection.length * 80 + 'px')
                    .style('padding-bottom', '20px');
            }
        };

        item.preset = preset;

        return item;
    }


    function PresetItem(preset) {
        function item(selection) {
            var wrap = selection.append('div')
                .attr('class', 'preset-list-button-wrap col12');

            wrap.append('button')
                .attr('class', 'preset-list-button')
                .call(uiPresetIcon()
                    .geometry(context.geometry(id))
                    .preset(preset))
                .on('click', item.choose)
                .append('div')
                .attr('class', 'label')
                .text(preset.name());

            wrap.call(item.reference.button);
            selection.call(item.reference.body);
        }

        item.choose = function() {
            context.presets().choose(preset);

            context.perform(
                actionChangePreset(id, currentPreset, preset),
                t('operations.change_tags.annotation')
            );

            dispatch.call('choose', this, preset);
        };

        item.help = function() {
            d3.event.stopPropagation();
            item.reference.toggle();
        };

        item.preset = preset;
        item.reference = uiTagReference(preset.reference(context.geometry(id)), context);

        return item;
    }


    presetList.autofocus = function(_) {
        if (!arguments.length) return autofocus;
        autofocus = _;
        return presetList;
    };


    presetList.entityID = function(_) {
        if (!arguments.length) return id;
        id = _;
        presetList.preset(context.presets().match(context.entity(id), context.graph()));
        return presetList;
    };


    presetList.preset = function(_) {
        if (!arguments.length) return currentPreset;
        currentPreset = _;
        return presetList;
    };


    return utilRebind(presetList, dispatch, 'on');
}
