'use strict';

import _ from 'lodash';
import File from 'vinyl';
import gulp from 'gulp';
import merge from 'merge-stream';
import sprity from 'sprity';
import svgSprite from 'gulp-svg-sprite';
import through2 from 'through2';
import { humanize, titleize } from 'underscore.string';


/** Names of directories containing icons. */
const ICON_CATEGORIES = [
  'action',
  'alert',
  'av',
  'communication',
  'content',
  'device',
  'editor',
  'file',
  'hardware',
  'image',
  'maps',
  'navigation',
  'notification',
  'places',
  'social',
  'toggle',
];


/** Standard PNG colors. */
const PNG_COLORS = [
  'black',
  'white',
];


/**
 * Generates PNG sprites and their corresponding CSS files for each category of
 * icon, and places them in `sprites/css-sprite`.
 *
 * TODO(shyndman): Add support for double density sprites.
 */
gulp.task('png-sprites', () =>
  _(getCategoryColorPairs())
    .map(([ category, color ]) =>
      sprity.src({
        src: `./${ category }/1x_web/*_${ color }_24dp.png`,
        style: `sprite-${ category }-${ color }.css`,
        name: `sprite-${ category }-${ color }`,
        engine: 'sprity-gm',
        orientation: 'left-right'
      }))
    .thru(merge)
    .value()
    .pipe(gulp.dest('./sprites/css-sprite/')));


/**
 * Generates CSS and Symbol-based SVG sprites for each category, and places
 * them in `sprites/svg-sprite`.
 */
gulp.task('svg-sprites', () =>
  _(ICON_CATEGORIES)
    .map((category) =>
      gulp.src(`./${ category }/svg/production/*_24px.svg`)
        .pipe(svgSprite(getSvgSpriteConfig(category))))
    .thru(merge)
    .value()
    .pipe(gulp.dest('./sprites/svg-sprite')));


/**
 * Generates a file to allow the consumption of the icon font by Iconjar
 * (http://geticonjar.com/).
 */
gulp.task('iconjar', () =>
  gulp.src('./iconfont/codepoints')
    .pipe(generateIjmap('MaterialIcons-Regular.ijmap'))
    .pipe(gulp.dest('./iconfont/')));


/** Runs all tasks. */
gulp.task('default', ['png-sprites', 'svg-sprites', 'iconjar']);


/**
 * Returns a stream that transforms between our icon font's codepoint file
 * and an Iconjar ijmap.
 */
function generateIjmap(ijmapPath) {
  return through2.obj((codepointsFile, encoding, callback) => {
    const ijmap = {
      icons: codepointsToIjmap(codepointsFile.contents.toString())
    };

    callback(null, new File({
      path: ijmapPath,
      contents: new Buffer(JSON.stringify(ijmap), 'utf8')
    }));

    function codepointsToIjmap(codepoints) {
      return _(codepoints)
        .split('\n')       // split into lines
        .reject(_.isEmpty) // remove empty lines
        .reduce((codepointMap, line) => {   // build up the codepoint map
          let [ name, codepoint ] = line.split(' ');
          codepointMap[codepoint] = { name: titleize(humanize(name)) };
          return codepointMap;
        }, {});
    }
  });
}


/**
 * Returns the SVG sprite configuration for the specified category.
 */
function getSvgSpriteConfig(category) {
  return {
    shape: {
      dimension: {
        maxWidth: 24,
        maxHeight: 24
      },
    },
    mode: {
      css : {
        bust: false,
        dest: './',
        sprite: `./svg-sprite-${ category }.svg`,
        example: {
          dest: `./svg-sprite-${ category }.html`
        },
        render: {
          css: {
            dest: `./svg-sprite-${ category }.css`
          }
        }
      },
      symbol : {
        bust: false,
        dest: './',
        sprite: `./svg-sprite-${ category }-symbol.svg`,
        example: {
          dest: `./svg-sprite-${ category }-symbol.html`
        }
      }
    }
  };
}


/**
 * Returns the catesian product of categories and colors.
 */
function getCategoryColorPairs() {
  return _(ICON_CATEGORIES)
    .map((category) =>
      _.zip(_.times(PNG_COLORS.length, () => category), PNG_COLORS))
    .flatten() // flattens 1 level
    .value();
}
