/*
 * Copyright 2015 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.template.soy.jbcsrc.shared;

import static com.google.common.base.Preconditions.checkArgument;

import com.google.template.soy.base.internal.BaseUtils;

/**
 * Utilities for translating soy symbols to and from strings that are suitable for use in java class
 * files.  These utilities are shared between the compiler and the runtime system.
 */
public final class Names {
  public static final String CLASS_PREFIX = "com.google.template.soy.jbcsrc.gen.";
  public static final String INTERNAL_CLASS_PREFIX = CLASS_PREFIX.replace('.', '/');

  private Names() {}

  /**
   * Translate a user controlled Soy name to a form that is safe to encode in a java class, method
   * or field name.
   *
   * <p>Soy identifiers are very simple, they are restricted to the following regex:
   * {@code [a-zA-Z_]([a-zA-Z_0-9])*}. So a template name is just one or more identifiers separated
   * by {@code .} characters.  To escape it, we simply replace all '.'s with '_'s, and all '_'s with
   * '__' and prefix with a package name.
   */
  public static String javaClassNameFromSoyTemplateName(String soyTemplate) {
    checkArgument(BaseUtils.isDottedIdentifier(soyTemplate),
        "%s is not a valid template name.", soyTemplate);
    return CLASS_PREFIX + soyTemplate;
  }

  /**
   * Given the soy namespace and file name returns the path where the corresponding resource should
   * be stored.
   */
  public static String javaFileName(String soyNamespace, String fileName) {
    checkArgument(BaseUtils.isDottedIdentifier(soyNamespace),
        "%s is not a valid soy namspace name.", soyNamespace);
    return (CLASS_PREFIX + soyNamespace).replace('.', '/') + '/' + fileName;
  }

  /**
   * Translates a Java class name generated by {@link #javaClassNameFromSoyTemplateName}, back to
   * the original soy template name.
   */
  public static String soyTemplateNameFromJavaClassName(String javaClass) {
    if (!javaClass.startsWith(CLASS_PREFIX)) {
      throw new IllegalArgumentException("java class: " + javaClass
          + " is not a mangled soy template name");
    }
    return javaClass.substring(CLASS_PREFIX.length());
  }

  /**
   * Rewrites the given stack trace by replacing all references to generated jbcsrc types with the
   * original template names. 
   */
  public static void rewriteStackTrace(Throwable throwable) {
    StackTraceElement[] stack = throwable.getStackTrace();
    for (int i = 0; i < stack.length; i++) {
      StackTraceElement curr = stack[i];
      if (curr.getClassName().startsWith(CLASS_PREFIX)) {
        stack[i] = new StackTraceElement(
            soyTemplateNameFromJavaClassName(curr.getClassName()), 
            curr.getMethodName(),  // TODO(lukes): remove the method name? only if it == 'render'?
            curr.getFileName(), 
            curr.getLineNumber());
      }
    }
    throwable.setStackTrace(stack);
  }
}
