'use strict';

var Lib = require('../../../lib');
var Color = require('../../../components/color');
var Registry = require('../../../registry');

var handleSubplotDefaults = require('../../subplot_defaults');
var supplyGl3dAxisLayoutDefaults = require('./axis_defaults');
var layoutAttributes = require('./layout_attributes');
var getSubplotData = require('../../get_data').getSubplotData;

var GL3D = 'gl3d';

module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) {
    var hasNon3D = layoutOut._basePlotModules.length > 1;

    // some layout-wide attribute are used in all scenes
    // if 3D is the only visible plot type
    function getDfltFromLayout(attr) {
        if(hasNon3D) return;

        var isValid = Lib.validate(layoutIn[attr], layoutAttributes[attr]);
        if(isValid) return layoutIn[attr];
    }

    handleSubplotDefaults(layoutIn, layoutOut, fullData, {
        type: GL3D,
        attributes: layoutAttributes,
        handleDefaults: handleGl3dDefaults,
        fullLayout: layoutOut,
        font: layoutOut.font,
        fullData: fullData,
        getDfltFromLayout: getDfltFromLayout,
        autotypenumbersDflt: layoutOut.autotypenumbers,
        paper_bgcolor: layoutOut.paper_bgcolor,
        calendar: layoutOut.calendar
    });
};

function handleGl3dDefaults(sceneLayoutIn, sceneLayoutOut, coerce, opts) {
    /*
     * Scene numbering proceeds as follows
     * scene
     * scene2
     * scene3
     *
     * and d.scene will be undefined or some number or number string
     *
     * Also write back a blank scene object to user layout so that some
     * attributes like aspectratio can be written back dynamically.
     */

    var bgcolor = coerce('bgcolor');
    var bgColorCombined = Color.combine(bgcolor, opts.paper_bgcolor);

    var cameraKeys = ['up', 'center', 'eye'];

    for(var j = 0; j < cameraKeys.length; j++) {
        coerce('camera.' + cameraKeys[j] + '.x');
        coerce('camera.' + cameraKeys[j] + '.y');
        coerce('camera.' + cameraKeys[j] + '.z');
    }

    coerce('camera.projection.type');

    /*
     * coerce to positive number (min 0) but also do not accept 0 (>0 not >=0)
     * note that 0's go false with the !! call
     */
    var hasAspect = !!coerce('aspectratio.x') &&
                    !!coerce('aspectratio.y') &&
                    !!coerce('aspectratio.z');

    var defaultAspectMode = hasAspect ? 'manual' : 'auto';
    var aspectMode = coerce('aspectmode', defaultAspectMode);

    /*
     * We need aspectratio object in all the Layouts as it is dynamically set
     * in the calculation steps, ie, we cant set the correct data now, it happens later.
     * We must also account for the case the user sends bad ratio data with 'manual' set
     * for the mode. In this case we must force change it here as the default coerce
     * misses it above.
     */
    if(!hasAspect) {
        sceneLayoutIn.aspectratio = sceneLayoutOut.aspectratio = {x: 1, y: 1, z: 1};

        if(aspectMode === 'manual') sceneLayoutOut.aspectmode = 'auto';

        /*
         * kind of like autorange - we need the calculated aspectmode back in
         * the input layout or relayout can cause problems later
         */
        sceneLayoutIn.aspectmode = sceneLayoutOut.aspectmode;
    }

    var fullGl3dData = getSubplotData(opts.fullData, GL3D, opts.id);

    supplyGl3dAxisLayoutDefaults(sceneLayoutIn, sceneLayoutOut, {
        font: opts.font,
        scene: opts.id,
        data: fullGl3dData,
        bgColor: bgColorCombined,
        calendar: opts.calendar,
        autotypenumbersDflt: opts.autotypenumbersDflt,
        fullLayout: opts.fullLayout
    });

    Registry.getComponentMethod('annotations3d', 'handleDefaults')(
        sceneLayoutIn, sceneLayoutOut, opts
    );

    var dragmode = opts.getDfltFromLayout('dragmode');

    if(dragmode !== false) {
        if(!dragmode) {
            dragmode = 'orbit';

            if(sceneLayoutIn.camera &&
                sceneLayoutIn.camera.up) {
                var x = sceneLayoutIn.camera.up.x;
                var y = sceneLayoutIn.camera.up.y;
                var z = sceneLayoutIn.camera.up.z;

                if(z !== 0) {
                    if(!x || !y || !z) {
                        dragmode = 'turntable';
                    } else if(z / Math.sqrt(x * x + y * y + z * z) > 0.999) {
                        dragmode = 'turntable';
                    }
                }
            } else {
                dragmode = 'turntable';
            }
        }
    }

    coerce('dragmode', dragmode);
    coerce('hovermode', opts.getDfltFromLayout('hovermode'));
}
