module.exports = function (grunt) {
  grunt.loadNpmTasks('grunt-autoprefixer');
  grunt.loadNpmTasks('grunt-contrib-less');
  grunt.loadNpmTasks('grunt-contrib-sass');
  grunt.loadNpmTasks('grunt-contrib-concat');
  grunt.loadNpmTasks('grunt-contrib-connect');
  grunt.loadNpmTasks('grunt-contrib-clean');
  grunt.loadNpmTasks('grunt-contrib-watch');

  var configBridge = grunt.file.readJSON('./bower_components/bootstrap/grunt/configBridge.json', { encoding: 'utf8' });

  // Project configuration.
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    builddir: '.',
    buildtheme: '',
    banner: '/*!\n' +
            ' * <%= pkg.name %> v<%= pkg.version %>\n' +
            ' * Homepage: <%= pkg.homepage %>\n' +
            ' * Copyright 2012-<%= grunt.template.today("yyyy") %> <%= pkg.author %>\n' +
            ' * Licensed under <%= pkg.license %>\n' +
            ' * Based on Bootstrap\n' +
            '*/\n',
    swatch: {
      amelia:{}, cerulean:{}, cosmo:{}, cyborg:{}, darkly:{},
      flatly:{}, journal:{}, lumen:{}, paper:{}, readable:{},
      sandstone:{}, simplex:{}, slate:{}, spacelab:{}, superhero:{},
      united:{}, yeti:{}, custom:{}
    },
    clean: {
      build: {
        src: ['*/build.less', '*/build.scss', '!global/build.less', '!global/build.scss']
      }
    },
    concat: {
      options: {
        banner: '<%= banner %>',
        stripBanners: false
      },
      dist: {
        src: [],
        dest: ''
      }
    },
    less: {
      dist: {
        options: {
          compress: false,
          strictMath: true
        },
        files: {}
      }
    },
    autoprefixer: {
      options: {
        browsers: configBridge.config.autoprefixerBrowsers
      },
      dist: {
        src: '*/bootstrap.css'
      }
    },
    watch: {
      files: ['*/variables.less', '*/bootswatch.less', '*/index.html'],
      tasks: 'build',
      options: {
        livereload: true,
        nospawn: true
      }
    },
    connect: {
      base: {
        options: {
          port: 3000,
          livereload: true,
          open: true
        }
      },
      keepalive: {
        options: {
          port: 3000,
          livereload: true,
          keepalive: true,
          open: true
        }
      }
    }
  });

  grunt.registerTask('none', function() {});

  grunt.registerTask('build', 'build a regular theme', function(theme, compress) {
    var theme = theme == undefined ? grunt.config('buildtheme') : theme;
    var compress = compress == undefined ? true : compress;

    var isValidTheme = grunt.file.exists(theme, 'variables.less') && grunt.file.exists(theme, 'bootswatch.less');
 
     // cancel the build (without failing) if this directory is not a valid theme
    if (!isValidTheme) {
      return;
    }

    var concatSrc;
    var concatDest;
    var lessDest;
    var lessSrc;
    var files = {};
    var dist = {};
    concatSrc = 'global/build.less';
    concatDest = theme + '/build.less';
    lessDest = '<%=builddir%>/' + theme + '/bootstrap.css';
    lessSrc = [ theme + '/' + 'build.less' ];

    dist = {src: concatSrc, dest: concatDest};
    grunt.config('concat.dist', dist);
    files = {}; files[lessDest] = lessSrc;
    grunt.config('less.dist.files', files);
    grunt.config('less.dist.options.compress', false);

    grunt.task.run(['concat', 'less:dist', 'prefix:' + lessDest, 'clean:build',
      compress ? 'compress:'+lessDest+':'+'<%=builddir%>/' + theme + '/bootstrap.min.css':'none']);
  });

grunt.registerTask('build_scss', 'build a regular theme from scss', function(theme, compress) {
    var theme = theme == undefined ? grunt.config('buildtheme') : theme;
    var compress = compress == undefined ? true : compress;

    var isValidTheme = grunt.file.exists(theme, '_variables.scss') && grunt.file.exists(theme, '_bootswatch.scss');

     // cancel the build (without failing) if this directory is not a valid theme
    if (!isValidTheme) {
      return;
    }
    var concatSrc;
    var concatDest;
    var scssDest;
    var scssSrc;
    var files = {};
    var dist = {};
    concatSrc = 'global/build.scss';
    concatDest = theme + '/build.scss';
    scssDest = '<%=builddir%>/' + theme + '/bootstrap.css';
    scssSrc = [theme + '/' + 'build.scss'];

    dist = {src: concatSrc, dest: concatDest};
    grunt.config('concat.dist', dist);
    files = {};
    files[scssDest] = scssSrc;
    grunt.config('sass.dist.files', files);
    grunt.config('sass.dist.options.style', 'expanded');
    grunt.config('sass.dist.options.precision', 8);
    grunt.config('sass.dist.options.unix-newlines', true);
 
    grunt.task.run(['concat', 'sass:dist', 'prefix:' + scssDest, 'clean:build',
        compress ? 'compress_scss:' + scssDest + ':' + '<%=builddir%>/' + theme + '/bootstrap.min.css' : 'none']);
  });
  
  grunt.registerTask('prefix', 'autoprefix a generic css', function(fileSrc) {
    grunt.config('autoprefixer.dist.src', fileSrc);
    grunt.task.run('autoprefixer');
  });

  grunt.registerTask('compress', 'compress a generic css', function(fileSrc, fileDst) {
    var files = {}; files[fileDst] = fileSrc;
    grunt.log.writeln('compressing file ' + fileSrc);

    grunt.config('less.dist.files', files);
    grunt.config('less.dist.options.compress', true);
    grunt.task.run(['less:dist']);
  });

  grunt.registerTask('compress_scss', 'compress a generic css with sass', function(fileSrc, fileDst) {
    var files = {}; files[fileDst] = fileSrc;
    grunt.log.writeln('compressing file ' + fileSrc);

    grunt.config('sass.dist.files', files);
    grunt.config('sass.dist.options.style', 'compressed');
    grunt.task.run(['sass:dist']);
  });

  grunt.registerMultiTask('swatch', 'build a theme', function() {
    var t = this.target;
    grunt.task.run('build:'+t);
  });

  grunt.registerTask('swatch_scss', 'build a theme from scss ', function (theme) {
    var t = theme;
    if (!t) {
      for (var t in grunt.config('swatch')) {
        grunt.task.run('build_scss:' + t);
      }
    } else {
      grunt.task.run('build_scss:' + t);
    }
  });

  grunt.event.on('watch', function(action, filepath) {
    var path = require('path');
    var theme = path.dirname(filepath);
    grunt.config('buildtheme', theme);
  });

  /**
  * Regex borrowed form
  * https://gist.github.com/rosskevin/ddfe895091de2ca5f931
  * */
  grunt.registerTask('convert_less', 'Convert less to scss using regular expression', function () {
    var convertBaseDir = '';
    grunt.file.expand(convertBaseDir + '*/*.less').forEach(function (lessFile) {
      if (lessFile !=="global/build.less"){
        var srcContents = grunt.file.read(lessFile);
        var out = srcContents
                // 1.  replace @ with $
                .replace(/@(?!import|media|keyframes|-)/g, '$')
                // 2.  replace mixins
                .replace(/[\.#](?![0-9])([\w\-]*)\s*\((.*)\)\s*\{/g, '@mixin $1($2){')
                // 3.  In LESS, bootstrap namespaces mixins, in SASS they are just prefixed e.g #gradient > .vertical-three-colors becomes @include gradient-vertical-three-colors
                .replace(/[\.#](?![0-9])([\w\-]*)\s>\s\.(.*;)/g, '@include $1-$2')
                // 4.  replace includes
                .replace(/[\.#](?![0-9])([\w\-].*\(.*;)/g, '@include $1')
                // 5.  replace no param mixin includes with empty parens
                .replace(/@include\s([\w\-]*\s*);/g, '@include $1();')
                // 6.  replace extends .class; @extend .class;
                .replace(/(\.(?![0-9])([\w\-]+);)/g, '@extend $1')
                // 7.  replace string literals
                .replace(/~"(.*)"/g, '#{"$1"}')
                // 8.  replace interpolation  ${var} > #{$var} 
                .replace(/\$\{(.*)\}/g, '#{$$$1}')
                // 9.  replace spin to adjust-hue (function name diff)
                .replace(/spin\(/g, 'adjust-hue(')
                // 10. replace bower and imports in build.scss
                .replace(/bootstrap\/less\//g, 'bootstrap-sass-official/assets/stylesheets/')
                .replace(/\.less/g, '')
                // 11. replace icon-font-path value with conditional for asset helpers
                .replace(/(\$icon-font-path:).*;/g, '$1 if($bootstrap-sass-asset-helper, "bootstrap/", "../fonts/bootstrap/");')
                // 12. set bootswatch's web-font-path value as !default
                .replace(/(\$web-font-path:.*);/g, '$1 !default;')
                // 13. Remove the web-font mixin which breaks in libsass
                .replace(/[\s\S][\s\S]@mixin web-font.*([\s\S]*?).*;([\s\S]*?)}([\s\S]*?)/,"")
                // 14. Replace usage of the web-font mixin with variable interpolation
                .replace(/@include web-font/,'@import url');

                if (/\/variables.less$/.test(lessFile)) {
                // 15. set default value of $bootstrap-sass-asset-helper to false
                  out = "$bootstrap-sass-asset-helper: false;\n" + out;
                // 16. only assign variables if they haven't been previously set e.g. $var: #f00; > $var: #f00 !default;
                  out = out.replace(/^(\$.*);/gm, '$1 !default;');
                }

        var baseDirRegex = new RegExp("^" + convertBaseDir, "g");
        var sassFile = lessFile.replace(baseDirRegex, '').replace(/\.less$/, '.scss').replace(/(bootswatch|variables)/, '_$1');
        grunt.file.write(sassFile, out);
        grunt.log.writeln('Converted less file:  ', lessFile, Array(27 - lessFile.length).join(' '),'> ', sassFile);
      }
    });
  });

  grunt.registerTask('server', 'connect:keepalive');

  grunt.registerTask('default', ['connect:base', 'watch']);
};
