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

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

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

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

import {
    polygonHull as d3polygonHull,
    polygonCentroid as d3polygonCentroid
} from 'd3';

import { utilGetAllNodes } from '../util';


export function modeRotate(context, entityIDs) {
    var mode = {
        id: 'rotate',
        button: 'browse'
    };

    var keybinding = d3keybinding('rotate'),
        behaviors = [
            behaviorEdit(context),
            operationCircularize(entityIDs, context).behavior,
            operationDelete(entityIDs, context).behavior,
            operationMove(entityIDs, context).behavior,
            operationOrthogonalize(entityIDs, context).behavior,
            operationReflectLong(entityIDs, context).behavior,
            operationReflectShort(entityIDs, context).behavior
        ],
        annotation = entityIDs.length === 1 ?
            t('operations.rotate.annotation.' + context.geometry(entityIDs[0])) :
            t('operations.rotate.annotation.multiple'),
        prevGraph,
        prevAngle,
        prevTransform,
        pivot;


    function doRotate() {
        var fn;
        if (context.graph() !== prevGraph) {
            fn = context.perform;
        } else {
            fn = context.replace;
        }

        // projection changed, recalculate pivot
        var projection = context.projection;
        var currTransform = projection.transform();
        if (!prevTransform ||
            currTransform.k !== prevTransform.k ||
            currTransform.x !== prevTransform.x ||
            currTransform.y !== prevTransform.y) {

            var nodes = utilGetAllNodes(entityIDs, context.graph()),
                points = nodes.map(function(n) { return projection(n.loc); });

            pivot = d3polygonCentroid(d3polygonHull(points));
            prevAngle = undefined;
        }


        var currMouse = context.mouse(),
            currAngle = Math.atan2(currMouse[1] - pivot[1], currMouse[0] - pivot[0]);

        if (typeof prevAngle === 'undefined') prevAngle = currAngle;
        var delta = currAngle - prevAngle;

        fn(actionRotate(entityIDs, pivot, delta, projection), annotation);

        prevTransform = currTransform;
        prevAngle = currAngle;
        prevGraph = context.graph();
    }


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


    function cancel() {
        context.pop();
        context.enter(modeSelect(context, entityIDs));
    }


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


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

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

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

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

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


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

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

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

        keybinding.off();
    };


    return mode;
}
