/**
 * Handle calling [[Call]] of built-in String object
 *
 * @return completion-value
 */
ecma_completion_value_t
ecma_builtin_string_dispatch_call (const ecma_value_t *arguments_list_p, /**< arguments list */
                                   ecma_length_t arguments_list_len) /**< number of arguments */
{
  JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL);

  ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();

  if (arguments_list_len == 0)
  {
    ecma_string_t *str_p = ecma_new_ecma_string_from_magic_string_id (LIT_MAGIC_STRING__EMPTY);
    ecma_value_t str_value = ecma_make_string_value (str_p);

    ret_value = ecma_make_normal_completion_value (str_value);
  }
  else
  {
    ret_value = ecma_op_to_string (arguments_list_p[0]);
  }

  return ret_value;
} /* ecma_builtin_string_dispatch_call */
/**
 * String object creation operation.
 *
 * See also: ECMA-262 v5, 15.5.2.1
 *
 * @return ecma value
 *         Returned value must be freed with ecma_free_value
 */
ecma_value_t
ecma_op_create_string_object (const ecma_value_t *arguments_list_p, /**< list of arguments that
                                                                         are passed to String constructor */
                              ecma_length_t arguments_list_len) /**< length of the arguments' list */
{
  JERRY_ASSERT (arguments_list_len == 0
                || arguments_list_p != NULL);

  ecma_string_t *prim_prop_str_value_p;

  ecma_number_t length_value;

  if (arguments_list_len == 0)
  {
    prim_prop_str_value_p = ecma_new_ecma_string_from_magic_string_id (LIT_MAGIC_STRING__EMPTY);
    length_value = ECMA_NUMBER_ZERO;
  }
  else
  {
    ecma_value_t to_str_arg_value = ecma_op_to_string (arguments_list_p[0]);

    if (ECMA_IS_VALUE_ERROR (to_str_arg_value))
    {
      return to_str_arg_value;
    }
    else
    {
      JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (to_str_arg_value));
      JERRY_ASSERT (ecma_is_value_string (to_str_arg_value));

      prim_prop_str_value_p = ecma_get_string_from_value (to_str_arg_value);

      ecma_length_t string_len = ecma_string_get_length (prim_prop_str_value_p);
      length_value = ((ecma_number_t) (uint32_t) string_len);
    }
  }

#ifndef CONFIG_DISABLE_STRING_BUILTIN
  ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_STRING_PROTOTYPE);
#else /* CONFIG_DISABLE_STRING_BUILTIN */
  ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_OBJECT_PROTOTYPE);
#endif /* !CONFIG_DISABLE_STRING_BUILTIN */

  ecma_object_t *obj_p = ecma_create_object (prototype_obj_p,
                                             false,
                                             true,
                                             ECMA_OBJECT_TYPE_STRING);
  ecma_deref_object (prototype_obj_p);

  /*
   * [[Class]] property is not stored explicitly for objects of ECMA_OBJECT_TYPE_STRING type.
   *
   * See also: ecma_object_get_class_name
   */

  ecma_property_t *prim_value_prop_p = ecma_create_internal_property (obj_p,
                                                                      ECMA_INTERNAL_PROPERTY_ECMA_VALUE);
  ecma_set_internal_property_value (prim_value_prop_p, ecma_make_string_value (prim_prop_str_value_p));

  // 15.5.5.1
  ecma_string_t *length_magic_string_p = ecma_new_ecma_length_string ();
  ecma_property_t *length_prop_p = ecma_create_named_data_property (obj_p,
                                                                    length_magic_string_p,
                                                                    ECMA_PROPERTY_FIXED);

  ecma_set_named_data_property_value (length_prop_p, ecma_make_number_value (length_value));
  ecma_deref_ecma_string (length_magic_string_p);

  return ecma_make_object_value (obj_p);
} /* ecma_op_create_string_object */
/**
 * Helper method to count and convert the arguments for the Function constructor call.
 *
 * Performs the operation described in ECMA 262 v5.1 15.3.2.1 steps 5.a-d
 *
 *
 * @return completion value - concatenated arguments as a string.
 *         Returned value must be freed with ecma_free_completion_value.
 */
static ecma_completion_value_t
ecma_builtin_function_helper_get_function_expression (const ecma_value_t *arguments_list_p, /** < arguments list */
                                                      ecma_length_t arguments_list_len) /** < number of arguments */
{
  JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL);

  ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();

  ecma_string_t *left_parenthesis_str_p, *right_parenthesis_str_p;
  ecma_string_t *left_brace_str_p, *right_brace_str_p;
  ecma_string_t *comma_str_p;
  ecma_string_t *function_kw_str_p, *empty_str_p;
  ecma_string_t *expr_str_p, *concated_str_p;

  left_parenthesis_str_p = ecma_new_ecma_string_from_magic_string_id (LIT_MAGIC_STRING_LEFT_PARENTHESIS_CHAR);
  right_parenthesis_str_p = ecma_new_ecma_string_from_magic_string_id (LIT_MAGIC_STRING_RIGHT_PARENTHESIS_CHAR);

  left_brace_str_p = ecma_new_ecma_string_from_magic_string_id (LIT_MAGIC_STRING_LEFT_BRACE_CHAR);
  right_brace_str_p = ecma_new_ecma_string_from_magic_string_id (LIT_MAGIC_STRING_RIGHT_BRACE_CHAR);

  comma_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_COMMA_CHAR);

  function_kw_str_p = ecma_new_ecma_string_from_magic_string_id (LIT_MAGIC_STRING_FUNCTION);
  empty_str_p = ecma_new_ecma_string_from_magic_string_id (LIT_MAGIC_STRING__EMPTY);

  /* First, we only process the function arguments skipping the function body */
  ecma_length_t number_of_function_args = (arguments_list_len == 0 ? 0 : arguments_list_len - 1);

  expr_str_p = ecma_concat_ecma_strings (left_parenthesis_str_p, function_kw_str_p);

  concated_str_p = ecma_concat_ecma_strings (expr_str_p, left_parenthesis_str_p);
  ecma_deref_ecma_string (expr_str_p);
  expr_str_p = concated_str_p;

  for (ecma_length_t idx = 0;
       idx < number_of_function_args && ecma_is_completion_value_empty (ret_value);
       idx++)
  {
    ECMA_TRY_CATCH (str_arg_value,
                    ecma_op_to_string (arguments_list_p[idx]),
                    ret_value);

    ecma_string_t *str_p = ecma_get_string_from_value (str_arg_value);

    concated_str_p = ecma_concat_ecma_strings (expr_str_p, str_p);
    ecma_deref_ecma_string (expr_str_p);
    expr_str_p = concated_str_p;

    if (idx < number_of_function_args - 1)
    {
      concated_str_p = ecma_concat_ecma_strings (expr_str_p, comma_str_p);
      ecma_deref_ecma_string (expr_str_p);
      expr_str_p = concated_str_p;
    }

    ECMA_FINALIZE (str_arg_value);
  }

  if (ecma_is_completion_value_empty (ret_value))
  {
    concated_str_p = ecma_concat_ecma_strings (expr_str_p, right_parenthesis_str_p);
    ecma_deref_ecma_string (expr_str_p);
    expr_str_p = concated_str_p;

    concated_str_p = ecma_concat_ecma_strings (expr_str_p, left_brace_str_p);
    ecma_deref_ecma_string (expr_str_p);
    expr_str_p = concated_str_p;

    if (arguments_list_len != 0)
    {
      ECMA_TRY_CATCH (str_arg_value,
                      ecma_op_to_string (arguments_list_p[arguments_list_len - 1]),
                      ret_value);

      ecma_string_t *body_str_p = ecma_get_string_from_value (str_arg_value);

      concated_str_p = ecma_concat_ecma_strings (expr_str_p, body_str_p);
      ecma_deref_ecma_string (expr_str_p);
      expr_str_p = concated_str_p;

      ECMA_FINALIZE (str_arg_value);
    }

    concated_str_p = ecma_concat_ecma_strings (expr_str_p, right_brace_str_p);
    ecma_deref_ecma_string (expr_str_p);
    expr_str_p = concated_str_p;

    concated_str_p = ecma_concat_ecma_strings (expr_str_p, right_parenthesis_str_p);
    ecma_deref_ecma_string (expr_str_p);
    expr_str_p = concated_str_p;
  }

  ecma_deref_ecma_string (left_parenthesis_str_p);
  ecma_deref_ecma_string (right_parenthesis_str_p);
  ecma_deref_ecma_string (left_brace_str_p);
  ecma_deref_ecma_string (right_brace_str_p);
  ecma_deref_ecma_string (comma_str_p);
  ecma_deref_ecma_string (function_kw_str_p);
  ecma_deref_ecma_string (empty_str_p);

  if (ecma_is_completion_value_empty (ret_value))
  {
    ret_value = ecma_make_normal_completion_value (ecma_make_string_value (expr_str_p));
  }
  else
  {
    ecma_deref_ecma_string (expr_str_p);
  }

  return ret_value;
} /* ecma_builtin_function_helper_get_function_expression */
/**
 * Get specified magic string
 *
 * @return ecma-string containing specified magic string
 */
ecma_string_t *
ecma_get_magic_string (lit_magic_string_id_t id) /**< magic string id */
{
  return ecma_new_ecma_string_from_magic_string_id (id);
} /* ecma_get_magic_string */