/**
 * @file svgs2ttf
 * @author junmer
 */

/* eslint-env node */

var isSvg = require('is-svg');
var through = require('through2');
var path = require('path');
var replaceExt = require('replace-ext');
var ab2b = require('b3b').ab2b;
var _ = require('lodash');
var bufferToVinyl = require('buffer-to-vinyl');
var TTFWriter = require('fonteditor-core').TTFWriter;
var TTF = require('fonteditor-core').TTF;
var svg2ttfobject = require('fonteditor-core').svg2ttfobject;
var getEmptyttfObject = require('fonteditor-core/ttf/getEmptyttfObject');

/**
 * SvgFont
 *
 * @constructor
 * @param {string} name filename
 * @param {Object} opts opts
 */
function SvgFont(name, opts) {

    this.opts = _.extend(
        {
            adjust: {
                leftSideBearing: 0,
                rightSideBearing: 0,
                ajdustToEmBox: true,
                ajdustToEmPadding: 0
            },
            name: {
                fontFamily: name,
                fontSubFamily: name,
                uniqueSubFamily: name,
                postScriptName: name
            }
        },
        opts
    );

    // empty ttfobj
    var ttfobj = getEmptyttfObject();

    // for save name
    ttfobj.post.format = 2;

    // new TTF
    this.ttf = new TTF(ttfobj);

    // set name
    this.ttf.setName(this.opts.name);

    // unicode start
    this.startCode = opts.startCode || 0xe001;

}

/**
 * add svg
 *
 * @param {string} name     svg basename
 * @param {buffer} contents svg contents
 */
SvgFont.prototype.add = function (name, contents) {

    var ttfObj = svg2ttfobject(
        contents.toString('utf-8'),
        {
            combinePath: true
        }
    );

    var glyf = ttfObj.glyf[0];

    glyf.name = path.basename(name, '.svg');

    if (!Array.isArray(glyf.unicode)) {
        glyf.unicode = [this.startCode++];
    }

    this.ttf.addGlyf(glyf);

};

/**
 * compile ttf contents
 *
 */
SvgFont.prototype.compile = function () {

    if (this.opts.adjust) {
        this.ttf.adjustGlyfPos(null, this.opts.adjust);
        this.ttf.adjustGlyf(null, this.opts.adjust);
    }

    this.contents = ab2b(
        new TTFWriter(
            this.opts
        )
        .write(
            this.ttf.ttf
        )
    );

};


/**
 * svgs2ttf fontmin plugin
 *
 * @param {string} file filename
 * @param {Object} opts opts
 * @param {string} opts.fontName font name
 * @return {Object} stream.Transform instance
 * @api public
 */
module.exports = function (file, opts) {

    if (!file) {
        throw new Error('Missing file option for fontmin-svg2ttf');
    }

    opts = _.extend({hinting: true}, opts);

    var firstFile;
    var fileName;
    var svgFont;

    if (typeof file === 'string') {

        // fix file ext
        file = replaceExt(file, '.ttf');

        // set file name
        fileName = file;
    }
    else if (typeof file.path === 'string') {
        fileName = path.basename(file.path);
        firstFile = bufferToVinyl.file(null, fileName);
    }
    else {
        throw new Error('Missing path in file options for fontmin-svg2ttf');
    }


    function bufferContents(file, enc, cb) {

        // ignore empty files
        if (file.isNull()) {
            cb();
            return;
        }

        // check stream
        if (file.isStream()) {
            this.emit('error', new Error('Streaming not supported'));
            cb();
            return;
        }

        // check svg
        if (!isSvg(file.contents)) {
            cb();
            return;
        }

        // set first file if not already set
        if (!firstFile) {
            firstFile = file;
        }

        // construct SvgFont instance
        if (!svgFont) {
            var fontName = opts.fontName || path.basename(fileName, '.ttf');
            svgFont = new SvgFont(fontName, opts);
        }

        // add file to SvgFont instance
        svgFont.add(file.relative, file.contents);

        cb();
    }


    function endStream(cb) {
        // no files passed in, no file goes out
        if (!firstFile || !svgFont) {
            cb();
            return;
        }

        var joinedFile;

        // if file opt was a file path
        // clone everything from the first file
        if (typeof file === 'string') {
            joinedFile = firstFile.clone({
                contents: false
            });

            joinedFile.path = path.join(firstFile.base, file);
        }
        else {
            joinedFile = firstFile;
        }

        // complie svgfont
        svgFont.compile();

        // set contents
        joinedFile.contents = svgFont.contents;
        joinedFile.ttfObject = svgFont.ttf.ttf;

        this.push(joinedFile);
        cb();
    }

    return through.obj(bufferContents, endStream);

};
