import * as d3 from 'd3';
import { d3keybinding } from '../lib/d3.keybinding.js';
import { t } from '../util/locale';

import { actionMove } from '../actions/index';
import { behaviorEdit } from '../behavior/index';

import {
    modeBrowse,
    modeSelect
} from './index';

import {
    operationCircularize,
    operationDelete,
    operationOrthogonalize,
    operationReflectLong,
    operationReflectShort,
    operationRotate
} from '../operations/index';


export function modeMove(context, entityIDs, baseGraph) {
    var mode = {
        id: 'move',
        button: 'browse'
    };

    var keybinding = d3keybinding('move'),
        behaviors = [
            behaviorEdit(context),
            operationCircularize(entityIDs, context).behavior,
            operationDelete(entityIDs, context).behavior,
            operationOrthogonalize(entityIDs, context).behavior,
            operationReflectLong(entityIDs, context).behavior,
            operationReflectShort(entityIDs, context).behavior,
            operationRotate(entityIDs, context).behavior
        ],
        annotation = entityIDs.length === 1 ?
            t('operations.move.annotation.' + context.geometry(entityIDs[0])) :
            t('operations.move.annotation.multiple'),
        prevGraph,
        cache,
        origin,
        nudgeInterval;


    function vecSub(a, b) {
        return [a[0] - b[0], a[1] - b[1]];
    }


    function edge(point, size) {
        var pad = [80, 20, 50, 20],   // top, right, bottom, left
            x = 0,
            y = 0;

        if (point[0] > size[0] - pad[1])
            x = -10;
        if (point[0] < pad[3])
            x = 10;
        if (point[1] > size[1] - pad[2])
            y = -10;
        if (point[1] < pad[0])
            y = 10;

        if (x || y) {
            return [x, y];
        } else {
            return null;
        }
    }


    function doMove(nudge) {
        nudge = nudge || [0, 0];

        var fn;
        if (prevGraph !== context.graph()) {
            cache = {};
            origin = context.map().mouseCoordinates();
            fn = context.perform;
        } else {
            fn = context.overwrite;
        }

        var currMouse = context.mouse(),
            origMouse = context.projection(origin),
            delta = vecSub(vecSub(currMouse, origMouse), nudge);

        fn(actionMove(entityIDs, delta, context.projection, cache), annotation);
        prevGraph = context.graph();
    }


    function startNudge(nudge) {
        if (nudgeInterval) window.clearInterval(nudgeInterval);
        nudgeInterval = window.setInterval(function() {
            context.pan(nudge);
            doMove(nudge);
        }, 50);
    }


    function stopNudge() {
        if (nudgeInterval) {
            window.clearInterval(nudgeInterval);
            nudgeInterval = null;
        }
    }


    function move() {
        doMove();
        var nudge = edge(context.mouse(), context.map().dimensions());
        if (nudge) {
            startNudge(nudge);
        } else {
            stopNudge();
        }
    }


    function finish() {
        d3.event.stopPropagation();
        context.enter(modeSelect(context, entityIDs));
        stopNudge();
    }


    function cancel() {
        if (baseGraph) {
            while (context.graph() !== baseGraph) context.pop();
            context.enter(modeBrowse(context));
        } else {
            context.pop();
            context.enter(modeSelect(context, entityIDs));
        }
        stopNudge();
    }


    function undone() {
        context.enter(modeBrowse(context));
    }


    mode.enter = function() {
        origin = context.map().mouseCoordinates();
        prevGraph = null;
        cache = {};

        behaviors.forEach(function(behavior) {
            context.install(behavior);
        });

        context.surface()
            .on('mousemove.move', move)
            .on('click.move', finish);

        context.history()
            .on('undone.move', undone);

        keybinding
            .on('⎋', cancel)
            .on('↩', finish);

        d3.select(document)
            .call(keybinding);
    };


    mode.exit = function() {
        stopNudge();

        behaviors.forEach(function(behavior) {
            context.uninstall(behavior);
        });

        context.surface()
            .on('mousemove.move', null)
            .on('click.move', null);

        context.history()
            .on('undone.move', null);

        keybinding.off();
    };


    return mode;
}
