/* jslint node: true */
'use strict';

//  ENiGMA½
const MenuModule    = require('./menu_module.js').MenuModule;
const Errors        = require('../core/enig_error.js').Errors;
const ANSI          = require('./ansi_term.js');
const Config        = require('./config.js').get;
const {
    getMessageAreaByTag
}                   = require('./message_area.js');

//  deps
const async         = require('async');
const _             = require('lodash');

exports.moduleInfo = {
    name    : 'Show Art',
    desc    : 'Module for more advanced methods of displaying art',
    author  : 'NuSkooler',
};

exports.getModule = class ShowArtModule extends MenuModule {
    constructor(options) {
        super(options);
        this.config = Object.assign({}, _.get(options, 'menuConfig.config'), { extraArgs : options.extraArgs });

        this.config.method = this.config.method || 'random';
        this.config.optional = _.get(this.config, 'optional', true);
    }

    initSequence() {
        const self = this;

        async.series(
            [
                function before(callback) {
                    return self.beforeArt(callback);
                },
                function showArt(callback) {
                    //
                    //  How we show art depends on our configuration
                    //
                    let handler = {
                        extraArgs       : self.showByExtraArgs,
                        sequence        : self.showBySequence,
                        random          : self.showByRandom,
                        fileBaseArea    : self.showByFileBaseArea,
                        messageConf     : self.showByMessageConf,
                        messageArea     : self.showByMessageArea,
                    }[self.config.method] || self.showRandomArt;

                    handler = handler.bind(self);

                    return handler(callback);
                }
            ],
            err => {
                if(err && !self.config.optional) {
                    self.client.log.warn('Error during init sequence', { error : err.message } );
                    return self.prevMenu( () => { /* dummy */ } );
                }

                self.finishedLoading();
                return self.autoNextMenu( () => { /* dummy */ } );
            }
        );
    }

    showByExtraArgs(cb) {
        this.getArtKeyValue(this.config.key, (err, artSpec) => {
            if(err) {
                return cb(err);
            }
            const options = {
                pause   : this.shouldPause(),
                desc    : 'extraArgs',
            };
            return this.displaySingleArtWithOptions(artSpec, options, cb);
        });
    }

    showBySequence(cb) {
        return cb(null);
    }

    showByRandom(cb) {
        return cb(null);
    }

    showByFileBaseArea(cb) {
        this.getArtKeyValue('areaTag', (err, key) => {
            if(err) {
                return cb(err);
            }
            return this.displaySingleArtByConfigPath( [ 'fileBase', 'areas', key, 'art' ], cb);
        });
    }

    showByMessageConf(cb) {
        this.getArtKeyValue('confTag', (err, key) => {
            if(err) {
                return cb(err);
            }
            return this.displaySingleArtByConfigPath( [ 'messageConferences', key, 'art' ], cb);
        });
    }

    showByMessageArea(cb) {
        this.getArtKeyValue('areaTag', (err, key) => {
            if(err) {
                return cb(err);
            }

            const area = getMessageAreaByTag(key);
            if(!area) {
                return cb(Errors.DoesNotExist(`No area by areaTag ${key} found`));
            }
            return cb(null);    //  :TODO: REMOVE ME --- currently NYI
        });
    }

    displaySingleArtByConfigPath(configPath, cb) {
        const desc = configPath.join('.');
        const artSpec = _.get(Config(), configPath);
        if(!artSpec) {
            return cb(Errors.MissingConfig(`No art defined at path ${desc}`));
        }
        const options = {
            desc,
            pause   : this.shouldPause(),
        };
        return this.displaySingleArtWithOptions(artSpec, options, cb);
    }

    getArtKeyValue(defaultKey, cb) {
        const key = this.config.key || defaultKey;
        if(!_.isString(key)) {
            return cb(Errors.MissingConfig('Config option "key" is required for method "extraArgs"'));
        }

        const path = key.split('.');
        const artKey = _.get(this.config, [ 'extraArgs' ].concat(path) );
        if(!_.isString(artKey)) {
            return cb(Errors.MissingParam(`Invalid or missing "extraArgs.${key}" value`));
        }

        return cb(null, artKey);
    }

    displaySingleArtWithOptions(artSpec, options, cb) {
        const self = this;
        async.waterfall(
            [
                function art(callback) {
                    //  :TODO: we really need a way to supply an explicit path to look in, e.g. general/area_art/
                    self.displayAsset(
                        artSpec,
                        self.menuConfig.config,
                        (err, artData) => {
                            if(err) {
                                return callback(err);
                            }
                            const mciData = { menu : artData.mciMap };
                            return callback(null, mciData);
                        }
                    );
                },
                function recordCursorPosition(mciData, callback) {
                    if(!options.pause) {
                        return callback(null, mciData, null);   //  cursor position not needed
                    }

                    self.client.once('cursor position report', pos => {
                        const pausePosition = { row : pos[0], col : 1 };
                        return callback(null, mciData, pausePosition);
                    });

                    self.client.term.rawWrite(ANSI.queryPos());
                },
                function afterArtDisplayed(mciData, pausePosition, callback) {
                    self.mciReady(mciData, err => {
                        return callback(err, pausePosition);
                    });
                },
                function displayPauseIfRequested(pausePosition, callback) {
                    if(!options.pause) {
                        return callback(null);
                    }
                    return self.pausePrompt(pausePosition, callback);
                },
            ],
            err => {
                if(err) {
                    self.client.log.warn( { artSpec, error : err.message }, `Failed to display "${options.desc}" art`);
                }
                return cb(err);
            }
        );
    }
};