"use strict";

var _classProps = function (child, staticProps, instanceProps) {
  if (staticProps) Object.defineProperties(child, staticProps);
  if (instanceProps) Object.defineProperties(child.prototype, instanceProps);
};

var CssSyntaxError = require("postcss/lib/css-syntax-error");
var autoprefixer = require("autoprefixer-core");
var path = require("path");
var fs = require("fs-extra");

var Binary = (function () {
  var Binary = function Binary(process) {
    this.arguments = process.argv.slice(2);
    this.stdin = process.stdin;
    this.stderr = process.stderr;
    this.stdout = process.stdout;

    this.status = 0;
    this.command = "compile";
    this.inputFiles = [];

    this.processOptions = {};
    this.processorOptions = {};
    this.parseArguments();
  };

  _classProps(Binary, null, {
    help: {
      writable: true,
      value: function () {
        return ("Usage: autoprefixer [OPTION...] FILES\n\nParse CSS files and add prefixed properties and values.\n\nOptions:\n  -b, --browsers BROWSERS  add prefixes for selected browsers\n  -o, --output FILE        set output file\n  -d, --dir DIR            set output dir\n  -m, --map                generate source map\n      --no-map             skip source map even if previous map exists\n      --no-inline          do not inline maps to data:uri\n      --inline-map         force inline map\n      --annotation PATH    change map location relative from CSS file\n      --no-map-annotation  skip source map annotation comment is CSS\n      --no-sources-content remove origin CSS from maps\n      --sources-content    force include origin CSS into map\n      --no-cascade         do not create nice visual cascade of prefixes\n      --safe               try to fix CSS syntax errors\n  -i, --info               show selected browsers and properties\n  -h, --help               show help text\n  -v, --version            print program version");
      }
    },
    desc: {
      writable: true,
      value: function () {
        return ("Files:\n  If you didn't set input files, autoprefixer will read from stdin stream.\n\n  By default, prefixed CSS will rewrite original files.\n\n  You can specify output file or directory by '-o' argument.\n  For several input files you can specify only output directory by '-d'.\n\n  Output CSS will be written to stdout stream on '-o -' argument or stdin input.\n\nSource maps:\n  On '-m' argument Autoprefixer will generate source map for changes near\n  output CSS (for out/main.css it generates out/main.css.map).\n\n  If previous source map will be near input files (for example, in/main.css\n  and in/main.css.map) Autoprefixer will apply previous map to output\n  source map.\n\nBrowsers:\n  Separate browsers by comma. For example, '-b \"> 1%, opera 12\"'.\n  You can set browsers by global usage statictics: '-b \\\"> 1%\\\"'.\n  or last version: '-b \"last 2 versions\"'.");
      }
    },
    print: {
      writable: true,
      value: function (str) {
        str = str.replace(/\n$/, "");
        this.stdout.write(str + "\n");
      }
    },
    error: {
      writable: true,
      value: function (str) {
        this.status = 1;
        this.stderr.write(str + "\n");
      }
    },
    version: {
      writable: true,
      value: function () {
        return require("./package.json").version;
      }
    },
    parseArguments: {
      writable: true,
      value: function () {
        var args = this.arguments.slice();
        while (args.length > 0) {
          var arg = args.shift();

          if (arg == "-h" || arg == "--help") {
            this.command = "showHelp";
          } else if (arg == "-v" || arg == "--version") {
            this.command = "showVersion";
          } else if (arg == "-i" || arg == "--info") {
            this.command = "info";
          } else if (arg == "-m" || arg == "--map") {
            this.processOptions.map = {};
          } else if (arg == "--no-map") {
            this.processOptions.map = false;
          } else if (arg == "-I" || arg == "--inline-map") {
            if (typeof (this.processOptions.map) == "undefined") {
              this.processOptions.map = {};
            }
            this.processOptions.map.inline = true;
          } else if (arg == "--no-inline-map") {
            if (typeof (this.processOptions.map) == "undefined") {
              this.processOptions.map = {};
            }
            this.processOptions.map.inline = false;
          } else if (arg == "--annotation") {
            if (typeof (this.processOptions.map) == "undefined") {
              this.processOptions.map = {};
            }
            this.processOptions.map.annotation = args.shift();
          } else if (arg == "--no-map-annotation") {
            if (typeof (this.processOptions.map) == "undefined") {
              this.processOptions.map = {};
            }
            this.processOptions.map.annotation = false;
          } else if (arg == "--sources-content") {
            if (typeof (this.processOptions.map) == "undefined") {
              this.processOptions.map = {};
            }
            this.processOptions.map.sourcesContent = true;
          } else if (arg == "--no-sources-content") {
            if (typeof (this.processOptions.map) == "undefined") {
              this.processOptions.map = {};
            }
            this.processOptions.map.sourcesContent = false;
          } else if (arg == "--no-cascade") {
            this.processorOptions.cascade = false;
          } else if (arg == "--safe") {
            this.processOptions.safe = true;
          } else if (arg == "-b" || arg == "--browsers") {
            this.processorOptions.browsers = args.shift().split(",").map(function (i) {
              return i.trim();
            });
          } else if (arg == "-o" || arg == "--output") {
            this.outputFile = args.shift();
          } else if (arg == "-d" || arg == "--dir") {
            this.outputDir = args.shift();
          } else {
            if (arg.match(/^-\w$/) || arg.match(/^--\w[\w-]+$/)) {
              this.command = undefined;

              this.error("autoprefixer: Unknown argument " + arg);
              this.error("");
              this.error(this.help());
            } else {
              this.inputFiles.push(arg);
            }
          }
        }
      }
    },
    showHelp: {
      writable: true,
      value: function (done) {
        this.print(this.help());
        this.print("");
        this.print(this.desc());
        done();
      }
    },
    showVersion: {
      writable: true,
      value: function (done) {
        this.print("autoprefixer " + this.version());
        done();
      }
    },
    info: {
      writable: true,
      value: function (done) {
        this.print(this.compiler().info());
        done();
      }
    },
    startWork: {
      writable: true,
      value: function () {
        this.waiting += 1;
      }
    },
    endWork: {
      writable: true,
      value: function () {
        this.waiting -= 1;
        if (this.waiting <= 0) this.doneCallback();
      }
    },
    workError: {
      writable: true,
      value: function (str) {
        this.error(str);
        this.endWork();
      }
    },
    compiler: {
      writable: true,
      value: function () {
        if (!this.compilerCache) {
          this.compilerCache = autoprefixer(this.processorOptions);
        }
        return this.compilerCache;
      }
    },
    compileCSS: {
      writable: true,
      value: function (css, output, input) {
        var _this = this;
        var opts = {};
        for (var name in this.processOptions) {
          opts[name] = this.processOptions[name];
        }
        if (input) opts.from = input;
        if (output != "-") opts.to = output;

        var result;
        try {
          result = this.compiler().process(css, opts);
        } catch (error) {
          if (error.autoprefixer) {
            this.error("autoprefixer: " + error.message);
          } else if (error instanceof CssSyntaxError) {
            this.error("autoprefixer:" + error.toString());
          } else {
            this.error("autoprefixer: Internal error");
            if (error.stack) {
              this.error("");
              this.error(error.stack);
            }
          }
        }

        if (!result) return this.endWork();

        if (output == "-") {
          this.print(result.css);
          this.endWork();
        } else {
          fs.outputFile(output, result.css, function (error) {
            if (error) _this.error("autoprefixer: " + error);

            if (result.map) {
              var map;
              if (opts.map && opts.map.annotation) {
                map = path.resolve(path.dirname(output), opts.map.annotation);
              } else {
                map = output + ".map";
              }
              fs.writeFile(map, result.map, function (error) {
                if (error) _this.error("autoprefixer: " + error);
                _this.endWork();
              });
            } else {
              _this.endWork();
            }
          });
        }
      }
    },
    files: {
      writable: true,
      value: function () {
        if (this.inputFiles.length === 0 && !this.outputFile) {
          this.outputFile = "-";
        }

        var i, file, list = [];
        if (this.outputDir) {
          if (this.inputFiles.length === 0) {
            this.error("autoprefixer: For STDIN input you need " + "to specify output file (by -o FILE),\n " + "not output dir");
            return;
          }

          var dir = this.outputDir;
          if (fs.existsSync(dir) && !fs.statSync(dir).isDirectory()) {
            this.error("autoprefixer: Path " + dir + " is a file, not directory");
            return;
          }

          var output;
          for (i = 0; i < this.inputFiles.length; i++) {
            file = this.inputFiles[i];
            output = path.join(this.outputDir, path.basename(file));
            list.push([file, output]);
          }
        } else if (this.outputFile) {
          if (this.inputFiles.length > 1) {
            this.error("autoprefixer: For several files you can " + "specify only output dir (by -d DIR`),\n" + "not one output file");
            return;
          }

          for (i = 0; i < this.inputFiles.length; i++) {
            list.push([this.inputFiles[i], this.outputFile]);
          }
        } else {
          for (i = 0; i < this.inputFiles.length; i++) {
            list.push([this.inputFiles[i], this.inputFiles[i]]);
          }
        }

        return list;
      }
    },
    compile: {
      writable: true,
      value: function (done) {
        var _this2 = this;
        this.waiting = 0;
        this.doneCallback = done;

        var files = this.files();
        if (!files) return done();

        if (files.length === 0) {
          this.startWork();

          var css = "";
          this.stdin.resume();
          this.stdin.on("data", function (chunk) {
            return css += chunk;
          });
          this.stdin.on("end", function () {
            _this2.compileCSS(css, _this2.outputFile);
          });
        } else {
          var i, input, output;
          for (i = 0; i < files.length; i++) {
            this.startWork();
          }
          for (i = 0; i < files.length; i++) {
            var _ref = files[i];
            input = _ref[0];
            output = _ref[1];


            if (!fs.existsSync(input)) {
              this.workError("autoprefixer: File " + input + "doesn't exists");
              continue;
            }

            (function (input, output) {
              fs.readFile(input, function (error, css) {
                if (error) {
                  _this2.workError("autoprefixer: " + error.message);
                } else {
                  _this2.compileCSS(css, output, input);
                }
              });
            })(input, output);
          }
        }
      }
    },
    run: {
      writable: true,
      value: function (done) {
        if (this.command) {
          this[this.command](done);
        } else {
          done();
        }
      }
    }
  });

  return Binary;
})();

module.exports = Binary;