'use strict';

var Lib = require('../../lib');
var handleSubplotDefaults = require('../subplot_defaults');
var getSubplotData = require('../get_data').getSubplotData;

var constants = require('./constants');
var layoutAttributes = require('./layout_attributes');

var axesNames = constants.axesNames;

module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) {
    handleSubplotDefaults(layoutIn, layoutOut, fullData, {
        type: 'geo',
        attributes: layoutAttributes,
        handleDefaults: handleGeoDefaults,
        fullData: fullData,
        partition: 'y'
    });
};

function handleGeoDefaults(geoLayoutIn, geoLayoutOut, coerce, opts) {
    var subplotData = getSubplotData(opts.fullData, 'geo', opts.id);
    var traceIndices = subplotData.map(function(t) { return t._expandedIndex; });

    var resolution = coerce('resolution');
    var scope = coerce('scope');
    var scopeParams = constants.scopeDefaults[scope];

    var projType = coerce('projection.type', scopeParams.projType);
    var isAlbersUsa = geoLayoutOut._isAlbersUsa = projType === 'albers usa';

    // no other scopes are allowed for 'albers usa' projection
    if(isAlbersUsa) scope = geoLayoutOut.scope = 'usa';

    var isScoped = geoLayoutOut._isScoped = (scope !== 'world');
    var isSatellite = geoLayoutOut._isSatellite = projType === 'satellite';
    var isConic = geoLayoutOut._isConic = projType.indexOf('conic') !== -1 || projType === 'albers';
    var isClipped = geoLayoutOut._isClipped = !!constants.lonaxisSpan[projType];

    if(geoLayoutIn.visible === false) {
        // should override template.layout.geo.show* - see issue 4482

        // make a copy
        var newTemplate = Lib.extendDeep({}, geoLayoutOut._template);

        // override show*
        newTemplate.showcoastlines = false;
        newTemplate.showcountries = false;
        newTemplate.showframe = false;
        newTemplate.showlakes = false;
        newTemplate.showland = false;
        newTemplate.showocean = false;
        newTemplate.showrivers = false;
        newTemplate.showsubunits = false;
        if(newTemplate.lonaxis) newTemplate.lonaxis.showgrid = false;
        if(newTemplate.lataxis) newTemplate.lataxis.showgrid = false;

        // set ref to copy
        geoLayoutOut._template = newTemplate;
    }
    var visible = coerce('visible');

    var show;
    for(var i = 0; i < axesNames.length; i++) {
        var axisName = axesNames[i];
        var dtickDflt = [30, 10][i];
        var rangeDflt;

        if(isScoped) {
            rangeDflt = scopeParams[axisName + 'Range'];
        } else {
            var dfltSpans = constants[axisName + 'Span'];
            var hSpan = (dfltSpans[projType] || dfltSpans['*']) / 2;
            var rot = coerce(
                'projection.rotation.' + axisName.substr(0, 3),
                scopeParams.projRotate[i]
            );
            rangeDflt = [rot - hSpan, rot + hSpan];
        }

        var range = coerce(axisName + '.range', rangeDflt);
        coerce(axisName + '.tick0');
        coerce(axisName + '.dtick', dtickDflt);

        show = coerce(axisName + '.showgrid', !visible ? false : undefined);
        if(show) {
            coerce(axisName + '.gridcolor');
            coerce(axisName + '.gridwidth');
            coerce(axisName + '.griddash');
        }

        // mock axis for autorange computations
        geoLayoutOut[axisName]._ax = {
            type: 'linear',
            _id: axisName.slice(0, 3),
            _traceIndices: traceIndices,
            setScale: Lib.identity,
            c2l: Lib.identity,
            r2l: Lib.identity,
            autorange: true,
            range: range.slice(),
            _m: 1,
            _input: {}
        };
    }

    var lonRange = geoLayoutOut.lonaxis.range;
    var latRange = geoLayoutOut.lataxis.range;

    // to cross antimeridian w/o ambiguity
    var lon0 = lonRange[0];
    var lon1 = lonRange[1];
    if(lon0 > 0 && lon1 < 0) lon1 += 360;

    var centerLon = (lon0 + lon1) / 2;
    var projLon;

    if(!isAlbersUsa) {
        var dfltProjRotate = isScoped ? scopeParams.projRotate : [centerLon, 0, 0];

        projLon = coerce('projection.rotation.lon', dfltProjRotate[0]);
        coerce('projection.rotation.lat', dfltProjRotate[1]);
        coerce('projection.rotation.roll', dfltProjRotate[2]);

        show = coerce('showcoastlines', !isScoped && visible);
        if(show) {
            coerce('coastlinecolor');
            coerce('coastlinewidth');
        }

        show = coerce('showocean', !visible ? false : undefined);
        if(show) coerce('oceancolor');
    }

    var centerLonDflt;
    var centerLatDflt;

    if(isAlbersUsa) {
        // 'albers usa' does not have a 'center',
        // these values were found using via:
        //   projection.invert([geoLayout.center.lon, geoLayoutIn.center.lat])
        centerLonDflt = -96.6;
        centerLatDflt = 38.7;
    } else {
        centerLonDflt = isScoped ? centerLon : projLon;
        centerLatDflt = (latRange[0] + latRange[1]) / 2;
    }

    coerce('center.lon', centerLonDflt);
    coerce('center.lat', centerLatDflt);

    if(isSatellite) {
        coerce('projection.tilt');
        coerce('projection.distance');
    }

    if(isConic) {
        var dfltProjParallels = scopeParams.projParallels || [0, 60];
        coerce('projection.parallels', dfltProjParallels);
    }

    coerce('projection.scale');

    show = coerce('showland', !visible ? false : undefined);
    if(show) coerce('landcolor');

    show = coerce('showlakes', !visible ? false : undefined);
    if(show) coerce('lakecolor');

    show = coerce('showrivers', !visible ? false : undefined);
    if(show) {
        coerce('rivercolor');
        coerce('riverwidth');
    }

    show = coerce('showcountries', isScoped && scope !== 'usa' && visible);
    if(show) {
        coerce('countrycolor');
        coerce('countrywidth');
    }

    if(scope === 'usa' || (scope === 'north america' && resolution === 50)) {
        // Only works for:
        //   USA states at 110m
        //   USA states + Canada provinces at 50m
        coerce('showsubunits', visible);
        coerce('subunitcolor');
        coerce('subunitwidth');
    }

    if(!isScoped) {
        // Does not work in non-world scopes
        show = coerce('showframe', visible);
        if(show) {
            coerce('framecolor');
            coerce('framewidth');
        }
    }

    coerce('bgcolor');

    var fitBounds = coerce('fitbounds');

    // clear attributes that will get auto-filled later
    if(fitBounds) {
        delete geoLayoutOut.projection.scale;

        if(isScoped) {
            delete geoLayoutOut.center.lon;
            delete geoLayoutOut.center.lat;
        } else if(isClipped) {
            delete geoLayoutOut.center.lon;
            delete geoLayoutOut.center.lat;
            delete geoLayoutOut.projection.rotation.lon;
            delete geoLayoutOut.projection.rotation.lat;
            delete geoLayoutOut.lonaxis.range;
            delete geoLayoutOut.lataxis.range;
        } else {
            delete geoLayoutOut.center.lon;
            delete geoLayoutOut.center.lat;
            delete geoLayoutOut.projection.rotation.lon;
        }
    }
}
