/*
 * grunt-contrib-stylus
 * http://gruntjs.com/
 *
 * Copyright (c) 2012 Eric Woroshow, contributors
 * Licensed under the MIT license.
 * https://github.com/gruntjs/grunt-contrib-stylus/blob/master/LICENSE-MIT
 */

module.exports = function(grunt) {
  'use strict';

  // TODO: ditch this when grunt v0.4 is released
  grunt.util = grunt.util || grunt.utils;

  var path = require('path');

  // TODO: remove if/when we officially drop node <= 0.7.9
  path.sep = path.sep || path.normalize('/');

  grunt.registerMultiTask('stylus', 'Compile Stylus files into CSS', function() {
    var helpers = require('grunt-contrib-lib').init(grunt);

    var options = helpers.options(this, {
      basePath: false,
      flatten: false
    });

    grunt.verbose.writeflags(options, 'Options');

    // TODO: ditch this when grunt v0.4 is released
    this.files = this.files || helpers.normalizeMultiTaskFiles(this.data, this.target);

    var done = this.async();

    var basePath;
    var destType;
    var newFileDest;

    var srcFiles;

    grunt.util.async.forEachSeries(this.files, function(file, next) {
      srcFiles = grunt.file.expandFiles(file.src);

      if (srcFiles.length === 0) {
        grunt.fail.warn('Unable to compile; no valid source files were found.');
      }

      destType = detectDestType(file.dest);

      if (destType === 'individual') {
        basePath = helpers.findBasePath(srcFiles, options.basePath);

        grunt.util.async.forEachSeries(srcFiles, function(srcFile, nextFile) {
          newFileDest = getNewFileDest(file.dest, srcFile, basePath, options.flatten);

          compileStylus(srcFile, options, function(css, err) {
            if(!err) {
              grunt.file.write(newFileDest, css || '');
              grunt.log.writeln('File ' + newFileDest + ' created.');

              nextFile(null);
            } else {
              done();
            }
          });
        }, function(err) {
          next();
        });
      } else {
        grunt.util.async.concatSeries(srcFiles, function(srcFile, nextConcat) {
          compileStylus(srcFile, options, function(css, err) {
            if(!err) {
              nextConcat(null, css);
            } else {
              done();
            }
          });
        }, function(err, css) {
          grunt.file.write(file.dest, css.join('\n') || '');
          grunt.log.writeln('File ' + file.dest + ' created.');

          next();
        });
      }
    }, function() {
      done();
    });
  });

  var compileStylus = function(srcFile, options, callback) {
    options = grunt.util._.extend({filename: srcFile}, options);
    delete options.basePath;
    delete options.flatten;

    var srcCode = grunt.file.read(srcFile);
    var s = require('stylus')(srcCode);

    try {
      s.use(require('nib')());
    } catch (e) {}

    grunt.util._.each(options, function(value, key) {
      s.set(key, value);
    });

    s.render(function(err, css) {
      if (err) {
        grunt.log.error(err);
        grunt.fail.warn('Stylus failed to compile.');

        callback(css, true);
      } else {
        callback(css, null);
      }
    });
  };

  var detectDestType = function(dest) {
    var destFile = path.basename(dest);

    if (grunt.util._.startsWith(destFile, '*')) {
      return 'individual';
    } else {
      return 'single';
    }
  };

  var getNewFileDest = function(dest, srcFile, basePath, flatten) {
    srcFile = path.normalize(srcFile);

    var newDest = path.dirname(dest);
    var newName = path.basename(srcFile, path.extname(srcFile)) + path.extname(dest);
    var relative = path.dirname(srcFile);

    if (flatten) {
      relative = '';
    } else if (basePath && basePath.length > 1) {
      relative = grunt.util._(relative).strRight(basePath).trim(path.sep);
    }

    // make paths outside grunts working dir relative
    relative = relative.replace(/\.\.(\/|\\)/g, '');

    return path.join(newDest, relative, newName);
  };
};
@@ -360,145 +360,8 @@
 s;%0A%0A
-  var path = require('path');%0A%0A  // TODO: remove if/when we officially drop node %3C= 0.7.9%0A  path.sep = path.sep %7C%7C path.normalize('/');%0A%0A
   gr
@@ -434,24 +434,57 @@
 unction() %7B%0A
+    var path = require('path');%0A%0A
     var help
@@ -871,26 +871,8 @@
 th;%0A
-    var destType;%0A
     
@@ -974,24 +974,69 @@
 le, next) %7B%0A
+      file.dest = path.normalize(file.dest);%0A
       srcFil
@@ -1210,82 +1210,47 @@
     
-destType = detectDestType(file.dest);%0A%0A      if (destType === 'individual'
+if (helpers.isIndividualDest(file.dest)
 ) %7B%0A
@@ -1422,26 +1422,39 @@
 eDest = 
-getNewFile
+helpers.buildIndividual
 Dest(fil
@@ -1694,16 +1694,21 @@
 FileDest
+.cyan
  + ' cre
@@ -2304,16 +2304,21 @@
 ile.dest
+.cyan
  + ' cre
@@ -3065,824 +3065,7 @@
   %7D;
-%0A%0A  var detectDestType = function(dest) %7B%0A    var destFile = path.basename(dest);%0A%0A    if (grunt.util._.startsWith(destFile, '*')) %7B%0A      return 'individual';%0A    %7D else %7B%0A      return 'single';%0A    %7D%0A  %7D;%0A%0A  var getNewFileDest = function(dest, srcFile, basePath, flatten) %7B%0A    srcFile = path.normalize(srcFile);%0A%0A    var newDest = path.dirname(dest);%0A    var newName = path.basename(srcFile, path.extname(srcFile)) + path.extname(dest);%0A    var relative = path.dirname(srcFile);%0A%0A    if (flatten) %7B%0A      relative = '';%0A    %7D else if (basePath && basePath.length %3E 1) %7B%0A      relative = grunt.util._(relative).strRight(basePath).trim(path.sep);%0A    %7D%0A%0A    // make paths outside grunts working dir relative%0A    relative = relative.replace(/%5C.%5C.(%5C/%7C%5C%5C)/g, '');%0A%0A    return path.join(newDest, relative, newName);%0A  %7D;
 %0A%7D;

switch local functions over to helpers.