import { __exports as beautifier } from '../../../../../../../../_virtual/beautifier.js';
import { __require as requireOptions } from './options.js';
import { __require as requireOutput } from '../core/output.js';
import { __require as requireInputscanner } from '../core/inputscanner.js';
import { __require as requireDirectives } from '../core/directives.js';

/*jshint node:true */

var hasRequiredBeautifier;

function requireBeautifier () {
	if (hasRequiredBeautifier) return beautifier;
	hasRequiredBeautifier = 1;

	var Options = requireOptions().Options;
	var Output = requireOutput().Output;
	var InputScanner = requireInputscanner().InputScanner;
	var Directives = requireDirectives().Directives;

	var directives_core = new Directives(/\/\*/, /\*\//);

	var lineBreak = /\r\n|[\r\n]/;
	var allLineBreaks = /\r\n|[\r\n]/g;

	// tokenizer
	var whitespaceChar = /\s/;
	var whitespacePattern = /(?:\s|\n)+/g;
	var block_comment_pattern = /\/\*(?:[\s\S]*?)((?:\*\/)|$)/g;
	var comment_pattern = /\/\/(?:[^\n\r\u2028\u2029]*)/g;

	function Beautifier(source_text, options) {
	  this._source_text = source_text || '';
	  // Allow the setting of language/file-type specific options
	  // with inheritance of overall settings
	  this._options = new Options(options);
	  this._ch = null;
	  this._input = null;

	  // https://developer.mozilla.org/en-US/docs/Web/CSS/At-rule
	  this.NESTED_AT_RULE = {
	    "page": true,
	    "font-face": true,
	    "keyframes": true,
	    // also in CONDITIONAL_GROUP_RULE below
	    "media": true,
	    "supports": true,
	    "document": true
	  };
	  this.CONDITIONAL_GROUP_RULE = {
	    "media": true,
	    "supports": true,
	    "document": true
	  };
	  this.NON_SEMICOLON_NEWLINE_PROPERTY = [
	    "grid-template-areas",
	    "grid-template"
	  ];

	}

	Beautifier.prototype.eatString = function(endChars) {
	  var result = '';
	  this._ch = this._input.next();
	  while (this._ch) {
	    result += this._ch;
	    if (this._ch === "\\") {
	      result += this._input.next();
	    } else if (endChars.indexOf(this._ch) !== -1 || this._ch === "\n") {
	      break;
	    }
	    this._ch = this._input.next();
	  }
	  return result;
	};

	// Skips any white space in the source text from the current position.
	// When allowAtLeastOneNewLine is true, will output new lines for each
	// newline character found; if the user has preserve_newlines off, only
	// the first newline will be output
	Beautifier.prototype.eatWhitespace = function(allowAtLeastOneNewLine) {
	  var result = whitespaceChar.test(this._input.peek());
	  var newline_count = 0;
	  while (whitespaceChar.test(this._input.peek())) {
	    this._ch = this._input.next();
	    if (allowAtLeastOneNewLine && this._ch === '\n') {
	      if (newline_count === 0 || newline_count < this._options.max_preserve_newlines) {
	        newline_count++;
	        this._output.add_new_line(true);
	      }
	    }
	  }
	  return result;
	};

	// Nested pseudo-class if we are insideRule
	// and the next special character found opens
	// a new block
	Beautifier.prototype.foundNestedPseudoClass = function() {
	  var openParen = 0;
	  var i = 1;
	  var ch = this._input.peek(i);
	  while (ch) {
	    if (ch === "{") {
	      return true;
	    } else if (ch === '(') {
	      // pseudoclasses can contain ()
	      openParen += 1;
	    } else if (ch === ')') {
	      if (openParen === 0) {
	        return false;
	      }
	      openParen -= 1;
	    } else if (ch === ";" || ch === "}") {
	      return false;
	    }
	    i++;
	    ch = this._input.peek(i);
	  }
	  return false;
	};

	Beautifier.prototype.print_string = function(output_string) {
	  this._output.set_indent(this._indentLevel);
	  this._output.non_breaking_space = true;
	  this._output.add_token(output_string);
	};

	Beautifier.prototype.preserveSingleSpace = function(isAfterSpace) {
	  if (isAfterSpace) {
	    this._output.space_before_token = true;
	  }
	};

	Beautifier.prototype.indent = function() {
	  this._indentLevel++;
	};

	Beautifier.prototype.outdent = function() {
	  if (this._indentLevel > 0) {
	    this._indentLevel--;
	  }
	};

	/*_____________________--------------------_____________________*/

	Beautifier.prototype.beautify = function() {
	  if (this._options.disabled) {
	    return this._source_text;
	  }

	  var source_text = this._source_text;
	  var eol = this._options.eol;
	  if (eol === 'auto') {
	    eol = '\n';
	    if (source_text && lineBreak.test(source_text || '')) {
	      eol = source_text.match(lineBreak)[0];
	    }
	  }


	  // HACK: newline parsing inconsistent. This brute force normalizes the this._input.
	  source_text = source_text.replace(allLineBreaks, '\n');

	  // reset
	  var baseIndentString = source_text.match(/^[\t ]*/)[0];

	  this._output = new Output(this._options, baseIndentString);
	  this._input = new InputScanner(source_text);
	  this._indentLevel = 0;
	  this._nestedLevel = 0;

	  this._ch = null;
	  var parenLevel = 0;

	  var insideRule = false;
	  // This is the value side of a property value pair (blue in the following ex)
	  // label { content: blue }
	  var insidePropertyValue = false;
	  var enteringConditionalGroup = false;
	  var insideNonNestedAtRule = false;
	  var insideScssMap = false;
	  var topCharacter = this._ch;
	  var insideNonSemiColonValues = false;
	  var whitespace;
	  var isAfterSpace;
	  var previous_ch;

	  while (true) {
	    whitespace = this._input.read(whitespacePattern);
	    isAfterSpace = whitespace !== '';
	    previous_ch = topCharacter;
	    this._ch = this._input.next();
	    if (this._ch === '\\' && this._input.hasNext()) {
	      this._ch += this._input.next();
	    }
	    topCharacter = this._ch;

	    if (!this._ch) {
	      break;
	    } else if (this._ch === '/' && this._input.peek() === '*') {
	      // /* css comment */
	      // Always start block comments on a new line.
	      // This handles scenarios where a block comment immediately
	      // follows a property definition on the same line or where
	      // minified code is being beautified.
	      this._output.add_new_line();
	      this._input.back();

	      var comment = this._input.read(block_comment_pattern);

	      // Handle ignore directive
	      var directives = directives_core.get_directives(comment);
	      if (directives && directives.ignore === 'start') {
	        comment += directives_core.readIgnored(this._input);
	      }

	      this.print_string(comment);

	      // Ensures any new lines following the comment are preserved
	      this.eatWhitespace(true);

	      // Block comments are followed by a new line so they don't
	      // share a line with other properties
	      this._output.add_new_line();
	    } else if (this._ch === '/' && this._input.peek() === '/') {
	      // // single line comment
	      // Preserves the space before a comment
	      // on the same line as a rule
	      this._output.space_before_token = true;
	      this._input.back();
	      this.print_string(this._input.read(comment_pattern));

	      // Ensures any new lines following the comment are preserved
	      this.eatWhitespace(true);
	    } else if (this._ch === '$') {
	      this.preserveSingleSpace(isAfterSpace);

	      this.print_string(this._ch);

	      // strip trailing space, if present, for hash property checks
	      var variable = this._input.peekUntilAfter(/[: ,;{}()[\]\/='"]/g);

	      if (variable.match(/[ :]$/)) {
	        // we have a variable or pseudo-class, add it and insert one space before continuing
	        variable = this.eatString(": ").replace(/\s+$/, '');
	        this.print_string(variable);
	        this._output.space_before_token = true;
	      }

	      // might be sass variable
	      if (parenLevel === 0 && variable.indexOf(':') !== -1) {
	        insidePropertyValue = true;
	        this.indent();
	      }
	    } else if (this._ch === '@') {
	      this.preserveSingleSpace(isAfterSpace);

	      // deal with less property mixins @{...}
	      if (this._input.peek() === '{') {
	        this.print_string(this._ch + this.eatString('}'));
	      } else {
	        this.print_string(this._ch);

	        // strip trailing space, if present, for hash property checks
	        var variableOrRule = this._input.peekUntilAfter(/[: ,;{}()[\]\/='"]/g);

	        if (variableOrRule.match(/[ :]$/)) {
	          // we have a variable or pseudo-class, add it and insert one space before continuing
	          variableOrRule = this.eatString(": ").replace(/\s+$/, '');
	          this.print_string(variableOrRule);
	          this._output.space_before_token = true;
	        }

	        // might be less variable
	        if (parenLevel === 0 && variableOrRule.indexOf(':') !== -1) {
	          insidePropertyValue = true;
	          this.indent();

	          // might be a nesting at-rule
	        } else if (variableOrRule in this.NESTED_AT_RULE) {
	          this._nestedLevel += 1;
	          if (variableOrRule in this.CONDITIONAL_GROUP_RULE) {
	            enteringConditionalGroup = true;
	          }

	          // might be a non-nested at-rule
	        } else if (parenLevel === 0 && !insidePropertyValue) {
	          insideNonNestedAtRule = true;
	        }
	      }
	    } else if (this._ch === '#' && this._input.peek() === '{') {
	      this.preserveSingleSpace(isAfterSpace);
	      this.print_string(this._ch + this.eatString('}'));
	    } else if (this._ch === '{') {
	      if (insidePropertyValue) {
	        insidePropertyValue = false;
	        this.outdent();
	      }

	      // non nested at rule becomes nested
	      insideNonNestedAtRule = false;

	      // when entering conditional groups, only rulesets are allowed
	      if (enteringConditionalGroup) {
	        enteringConditionalGroup = false;
	        insideRule = (this._indentLevel >= this._nestedLevel);
	      } else {
	        // otherwise, declarations are also allowed
	        insideRule = (this._indentLevel >= this._nestedLevel - 1);
	      }
	      if (this._options.newline_between_rules && insideRule) {
	        if (this._output.previous_line && this._output.previous_line.item(-1) !== '{') {
	          this._output.ensure_empty_line_above('/', ',');
	        }
	      }

	      this._output.space_before_token = true;

	      // The difference in print_string and indent order is necessary to indent the '{' correctly
	      if (this._options.brace_style === 'expand') {
	        this._output.add_new_line();
	        this.print_string(this._ch);
	        this.indent();
	        this._output.set_indent(this._indentLevel);
	      } else {
	        // inside mixin and first param is object
	        if (previous_ch === '(') {
	          this._output.space_before_token = false;
	        } else if (previous_ch !== ',') {
	          this.indent();
	        }
	        this.print_string(this._ch);
	      }

	      this.eatWhitespace(true);
	      this._output.add_new_line();
	    } else if (this._ch === '}') {
	      this.outdent();
	      this._output.add_new_line();
	      if (previous_ch === '{') {
	        this._output.trim(true);
	      }

	      if (insidePropertyValue) {
	        this.outdent();
	        insidePropertyValue = false;
	      }
	      this.print_string(this._ch);
	      insideRule = false;
	      if (this._nestedLevel) {
	        this._nestedLevel--;
	      }

	      this.eatWhitespace(true);
	      this._output.add_new_line();

	      if (this._options.newline_between_rules && !this._output.just_added_blankline()) {
	        if (this._input.peek() !== '}') {
	          this._output.add_new_line(true);
	        }
	      }
	      if (this._input.peek() === ')') {
	        this._output.trim(true);
	        if (this._options.brace_style === "expand") {
	          this._output.add_new_line(true);
	        }
	      }
	    } else if (this._ch === ":") {

	      for (var i = 0; i < this.NON_SEMICOLON_NEWLINE_PROPERTY.length; i++) {
	        if (this._input.lookBack(this.NON_SEMICOLON_NEWLINE_PROPERTY[i])) {
	          insideNonSemiColonValues = true;
	          break;
	        }
	      }

	      if ((insideRule || enteringConditionalGroup) && !(this._input.lookBack("&") || this.foundNestedPseudoClass()) && !this._input.lookBack("(") && !insideNonNestedAtRule && parenLevel === 0) {
	        // 'property: value' delimiter
	        // which could be in a conditional group query

	        this.print_string(':');
	        if (!insidePropertyValue) {
	          insidePropertyValue = true;
	          this._output.space_before_token = true;
	          this.eatWhitespace(true);
	          this.indent();
	        }
	      } else {
	        // sass/less parent reference don't use a space
	        // sass nested pseudo-class don't use a space

	        // preserve space before pseudoclasses/pseudoelements, as it means "in any child"
	        if (this._input.lookBack(" ")) {
	          this._output.space_before_token = true;
	        }
	        if (this._input.peek() === ":") {
	          // pseudo-element
	          this._ch = this._input.next();
	          this.print_string("::");
	        } else {
	          // pseudo-class
	          this.print_string(':');
	        }
	      }
	    } else if (this._ch === '"' || this._ch === '\'') {
	      var preserveQuoteSpace = previous_ch === '"' || previous_ch === '\'';
	      this.preserveSingleSpace(preserveQuoteSpace || isAfterSpace);
	      this.print_string(this._ch + this.eatString(this._ch));
	      this.eatWhitespace(true);
	    } else if (this._ch === ';') {
	      insideNonSemiColonValues = false;
	      if (parenLevel === 0) {
	        if (insidePropertyValue) {
	          this.outdent();
	          insidePropertyValue = false;
	        }
	        insideNonNestedAtRule = false;
	        this.print_string(this._ch);
	        this.eatWhitespace(true);

	        // This maintains single line comments on the same
	        // line. Block comments are also affected, but
	        // a new line is always output before one inside
	        // that section
	        if (this._input.peek() !== '/') {
	          this._output.add_new_line();
	        }
	      } else {
	        this.print_string(this._ch);
	        this.eatWhitespace(true);
	        this._output.space_before_token = true;
	      }
	    } else if (this._ch === '(') { // may be a url
	      if (this._input.lookBack("url")) {
	        this.print_string(this._ch);
	        this.eatWhitespace();
	        parenLevel++;
	        this.indent();
	        this._ch = this._input.next();
	        if (this._ch === ')' || this._ch === '"' || this._ch === '\'') {
	          this._input.back();
	        } else if (this._ch) {
	          this.print_string(this._ch + this.eatString(')'));
	          if (parenLevel) {
	            parenLevel--;
	            this.outdent();
	          }
	        }
	      } else {
	        var space_needed = false;
	        if (this._input.lookBack("with")) {
	          // look back is not an accurate solution, we need tokens to confirm without whitespaces
	          space_needed = true;
	        }
	        this.preserveSingleSpace(isAfterSpace || space_needed);
	        this.print_string(this._ch);

	        // handle scss/sass map
	        if (insidePropertyValue && previous_ch === "$" && this._options.selector_separator_newline) {
	          this._output.add_new_line();
	          insideScssMap = true;
	        } else {
	          this.eatWhitespace();
	          parenLevel++;
	          this.indent();
	        }
	      }
	    } else if (this._ch === ')') {
	      if (parenLevel) {
	        parenLevel--;
	        this.outdent();
	      }
	      if (insideScssMap && this._input.peek() === ";" && this._options.selector_separator_newline) {
	        insideScssMap = false;
	        this.outdent();
	        this._output.add_new_line();
	      }
	      this.print_string(this._ch);
	    } else if (this._ch === ',') {
	      this.print_string(this._ch);
	      this.eatWhitespace(true);
	      if (this._options.selector_separator_newline && (!insidePropertyValue || insideScssMap) && parenLevel === 0 && !insideNonNestedAtRule) {
	        this._output.add_new_line();
	      } else {
	        this._output.space_before_token = true;
	      }
	    } else if ((this._ch === '>' || this._ch === '+' || this._ch === '~') && !insidePropertyValue && parenLevel === 0) {
	      //handle combinator spacing
	      if (this._options.space_around_combinator) {
	        this._output.space_before_token = true;
	        this.print_string(this._ch);
	        this._output.space_before_token = true;
	      } else {
	        this.print_string(this._ch);
	        this.eatWhitespace();
	        // squash extra whitespace
	        if (this._ch && whitespaceChar.test(this._ch)) {
	          this._ch = '';
	        }
	      }
	    } else if (this._ch === ']') {
	      this.print_string(this._ch);
	    } else if (this._ch === '[') {
	      this.preserveSingleSpace(isAfterSpace);
	      this.print_string(this._ch);
	    } else if (this._ch === '=') { // no whitespace before or after
	      this.eatWhitespace();
	      this.print_string('=');
	      if (whitespaceChar.test(this._ch)) {
	        this._ch = '';
	      }
	    } else if (this._ch === '!' && !this._input.lookBack("\\")) { // !important
	      this._output.space_before_token = true;
	      this.print_string(this._ch);
	    } else {
	      var preserveAfterSpace = previous_ch === '"' || previous_ch === '\'';
	      this.preserveSingleSpace(preserveAfterSpace || isAfterSpace);
	      this.print_string(this._ch);

	      if (!this._output.just_added_newline() && this._input.peek() === '\n' && insideNonSemiColonValues) {
	        this._output.add_new_line();
	      }
	    }
	  }

	  var sweetCode = this._output.get_code(eol);

	  return sweetCode;
	};

	beautifier.Beautifier = Beautifier;
	return beautifier;
}

export { requireBeautifier as __require };
//# sourceMappingURL=beautifier.js.map
