var sed = function (stdin) {
  var args = Array.prototype.slice.call(arguments, 1), script;
  for (var i = 0; i < args.length; ++i) {
    var arg = args[i];

    if (arg.indexOf('-') == 0 && i + 1 != args.length && args[i + 1].indexOf('-') != 0) {
      arg += args[i + 1];
    }

    if (match = arg.match(/^-(-expression=|e)(.*)/)) {
      script = match[2];
    } else if (match = arg.match(/^-(-silent|-quiet|n)/)) {
      //silent = true;
    } else if (arg.indexOf('-') != 0 && !script) {
      script = arg;
    } else {
      //file = arg;
    }
  }
  return sed.execute(stdin, script);
};

sed.execute = function (stdin, script) {
  var match, address = function (value, index) { return true; };

  var readAddress = function () {
    if (match = script.match(/^([0-9]+)(.*)/)) {
      script = match[2];
      return function (line) {
        return function (value, index) {
          return index == line;
        };
      }(match[1]);
    } else if (match = script.match(/^\/(.*?[^\\])\/(.*)/)) {
      script = match[2];
      return function (regex) {
        regex = new RegExp(regex);
        return function (value, index) {
          return regex.test(value);
        };
      }(match[1]);
    } else if (match = script.match(/^\$(.*)/)) {
      script = match[1];
      return function (value, index) {
        return index == stdin.length;
      };
    }
  };

  address = readAddress() || address;
  
  if (match = script.match(/^,(.*)/)) {
    script = match[1];
    address = function (start_address, end_address) {
      var out;
      return function (value, index) {
        if (out) {
          if (end_address(value, index)) {
            out = false;
          }
          return true;
        } else {
          out = start_address(value, index);
          return out;
        }
      };
    }(address, readAddress() || address);
  }

  var func = function (line, stdout) { };
  if (match = script.match(/^s(.)(.*?)\1(.*?)\1(.*?)$/)) {
    func = function (regex, replace, flag) {
      regex = new RegExp(regex, flag);
      var replaced;
      return function (line, stdout) {
        stdout.push(flag.indexOf('g') == -1 && replaced ? line : line.replace(regex, replace));
        replaced = true;
      };
    }(match[2], match[3], match[4]);
  } else if (script.indexOf('q') == 0) {
    func = function (line, stdout) {
      stdout.push(line);
      return true;
    };
  } else if (match = script.match(/^c (.*)$/)) {
    func = function (text) {
      return function (line, stdout) {
        stdout.push(text);
      };
    }(match[1]);
  } else if (match = script.match(/^a (.*)$/)) {
    func = function (text) {
      return function (line, stdout) {
        stdout.push(line);
        stdout.push(text);
      };
    }(match[1]);
  } else if (match = script.match(/^i (.*)$/)) {
    func = function (text) {
      return function (line, stdout) {
        stdout.push(text);
        stdout.push(line);
      };
    }(match[1]);
  }

  var stdout = [];
  for (var i = 0; i < stdin.length; ++i) {
    var line = stdin[i];
    if (!address(line, i + 1)) {
      stdout.push(line);
      continue;
    }

    if (func(line, stdout)) {
      return stdout;
    }
  }

  return stdout;
};
