/**
 * Copyright 2013-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */
/*global exports:true*/
'use strict';
var Syntax = require('esprima-fb').Syntax;
var utils = require('../src/utils');

function commaAfterLastParen(value) {
  var state = 'normal';
  var commaPos = 0;
  for (var i = 0; i < value.length; ++i) {
    if (state === 'normal') {
      if (value.substr(i, 2) === '//') {
        state = 'singleline';
        i += 1;
      } else if (value.substr(i, 2) === '/*') {
        state = 'multiline';
        i += 1;
      } else if (value.charAt(i).trim() !== '') {
        commaPos = i + 1;
      }
    } else if (state === 'singleline' && value.charAt(i) === '\n') {
      state = 'normal';
    } else if (state === 'multiline' &&
        value.charAt(i) === '*' &&
        i + 1 < value.length &&
        value.charAt(i + 1) === '/') {
      i += 1;
      state = 'normal';
    }
  }
  return value.substring(0, commaPos) + ', ' + trimLeft(value.substring(commaPos));
}

function renderJSXLiteral(object, isLast, state, start, end) {
  var lines = object.value.split(/\r\n|\n|\r/);

  if (start) {
    utils.append(start, state);
  }

  var lastNonEmptyLine = 0;

  lines.forEach(function(line, index) {
    if (line.match(/[^ \t]/)) {
      lastNonEmptyLine = index;
    }
  });

  lines.forEach(function(line, index) {
    var isFirstLine = index === 0;
    var isLastLine = index === lines.length - 1;
    var isLastNonEmptyLine = index === lastNonEmptyLine;

    // replace rendered whitespace tabs with spaces
    var trimmedLine = line.replace(/\t/g, ' ');

    // trim whitespace touching a newline
    if (!isFirstLine) {
      trimmedLine = trimmedLine.replace(/^[ ]+/, '');
    }
    if (!isLastLine) {
      trimmedLine = trimmedLine.replace(/[ ]+$/, '');
    }

    if (!isFirstLine) {
      utils.append(line.match(/^[ \t]*/)[0], state);
    }

    if (trimmedLine || isLastNonEmptyLine) {
      utils.append(
        JSON.stringify(trimmedLine) +
        (!isLastNonEmptyLine ? ' + " " +' : ''),
        state);

      if (isLastNonEmptyLine) {
        if (end) {
          utils.append(end, state);
        }
        if (!isLast) {
          utils.append(', ', state);
        }
      }

      // only restore tail whitespace if line had literals
      if (trimmedLine && !isLastLine) {
        utils.append(line.match(/[ \t]*$/)[0], state);
      }
    }

    if (!isLastLine) {
      utils.append('\n', state);
    }
  });

  utils.move(object.range[1], state);
}

function renderJSXExpressionContainer(traverse, object, isLast, path, state) {
  // Plus 1 to skip `{`.
  utils.move(object.range[0] + 1, state);
  utils.catchup(object.expression.range[0], state);
  traverse(object.expression, path, state);

  if (!isLast && object.expression.type !== Syntax.JSXEmptyExpression) {
    // If we need to append a comma, make sure to do so after the expression.
    utils.catchup(object.expression.range[1], state, trimLeft);
    utils.catchup(object.range[1] - 1, state, commaAfterLastParen);
  } else {
    // Minus 1 to skip `}`.
    utils.catchup(object.range[1] - 1, state, trimLeft);
  }
  utils.move(object.range[1], state);
  return false;
}

function quoteAttrName(attr) {
  // Quote invalid JS identifiers.
  if (!/^[a-z_$][a-z\d_$]*$/i.test(attr)) {
    return '"' + attr + '"';
  }
  return attr;
}

function trimLeft(value) {
  return value.replace(/^[ ]+/, '');
}

exports.renderJSXExpressionContainer = renderJSXExpressionContainer;
exports.renderJSXLiteral = renderJSXLiteral;
exports.quoteAttrName = quoteAttrName;
exports.trimLeft = trimLeft;
