package org.robolectric.res;

import org.jetbrains.annotations.NotNull;

import java.io.File;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class ResName {
  private static final Pattern FQN_PATTERN = Pattern.compile("^([^:]*):([^/]+)/(.+)$");
  private static final int NAMESPACE = 1;
  private static final int TYPE = 2;
  private static final int NAME = 3;

  public final @NotNull String packageName;
  public final @NotNull String type;
  public final @NotNull String name;

  public final int hashCode;

  public ResName(@NotNull String packageName, @NotNull String type, @NotNull String name) {
    this.packageName = packageName;
    this.type = type;
    this.name = name.indexOf('.') != -1 ? name.replace('.', '_').trim() : name.trim();

    hashCode = computeHashCode();
  }

  public ResName(@NotNull String fullyQualifiedName) {
    Matcher matcher = FQN_PATTERN.matcher(fullyQualifiedName.trim());
    if (!matcher.find()) {
      throw new IllegalStateException("\"" + fullyQualifiedName + "\" is not fully qualified");
    }
    packageName = matcher.group(NAMESPACE);
    type = matcher.group(TYPE);
    String nameStr = matcher.group(NAME);
    name = nameStr.indexOf('.') != -1 ? nameStr.replace('.', '_') : nameStr;

    hashCode = computeHashCode();
    if (packageName.equals("xmlns")) throw new IllegalStateException("\"" + fullyQualifiedName + "\" unexpected");
  }

  public static @NotNull String qualifyResourceName(@NotNull String possiblyQualifiedResourceName, String defaultPackageName, String defaultType) {
    ResName resName = qualifyResName(possiblyQualifiedResourceName, defaultPackageName, defaultType);
    return resName.getFullyQualifiedName();
  }

  public static @NotNull ResName qualifyResName(@NotNull String possiblyQualifiedResourceName, ResName defaults) {
    return qualifyResName(possiblyQualifiedResourceName, defaults.packageName, defaults.type);
  }

  public static @NotNull ResName qualifyResName(@NotNull String possiblyQualifiedResourceName, String defaultPackageName, String defaultType) {
    int indexOfColon = possiblyQualifiedResourceName.indexOf(':');
    int indexOfSlash = possiblyQualifiedResourceName.indexOf('/');
    String type = null;
    String packageName = null;
    String name = possiblyQualifiedResourceName;
    if (indexOfColon > indexOfSlash) {
      if (indexOfSlash > 0) {
        type = possiblyQualifiedResourceName.substring(0, indexOfSlash);
      }
      packageName = possiblyQualifiedResourceName.substring(indexOfSlash + 1, indexOfColon);
      name =  possiblyQualifiedResourceName.substring(indexOfColon + 1);
    } else if (indexOfSlash > indexOfColon) {
      if (indexOfColon > 0) {
        packageName = possiblyQualifiedResourceName.substring(0, indexOfColon);
      }
      type = possiblyQualifiedResourceName.substring(indexOfColon + 1, indexOfSlash);
      name = possiblyQualifiedResourceName.substring(indexOfSlash + 1);
    }

    return new ResName(packageName == null ? defaultPackageName : packageName,
        type == null ? defaultType : type,
        name);
  }

  public static Integer getResourceId(ResourceIndex resourceIndex, String possiblyQualifiedResourceName, String contextPackageName) {
    if (possiblyQualifiedResourceName == null) {
      return null;
    }

    if (possiblyQualifiedResourceName.equals("@null")) {
      return null;
    }

    String fullyQualifiedResourceName = qualifyResourceName(possiblyQualifiedResourceName, contextPackageName, null);

    fullyQualifiedResourceName = fullyQualifiedResourceName.replaceAll("[@+]", "");
    Integer resourceId = resourceIndex.getResourceId(new ResName(fullyQualifiedResourceName));
    // todo warn if resourceId is null
    return resourceId;
  }

  public static ResName qualifyFromFilePath(@NotNull final String packageName, @NotNull final String filePath) {
    final FileFsFile filePathFile = new FileFsFile(new File(filePath));
    final String type = filePathFile.getParent().getName().split("-")[0];
    final String name = filePathFile.getBaseName();

    return new ResName(packageName, type, name);
  }

  public ResName qualify(String string) {
    return new ResName(qualifyResourceName(string.replace("@", ""), packageName, null));
  }

  @Override
  public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;

    ResName resName = (ResName) o;

    if (hashCode() != resName.hashCode()) return false;

    if (!packageName.equals(resName.packageName)) return false;
    if (!type.equals(resName.type)) return false;
    if (!name.equals(resName.name)) return false;

    return true;
  }

  @Override
  public int hashCode() {
    return hashCode;
  }

  @Override
  public String toString() {
    return "ResName{" + getFullyQualifiedName() + "}";
  }

  public String getFullyQualifiedName() {
    return packageName + ":" + type + "/" + name;
  }

  public String getNamespaceUri() {
    return "http://schemas.android.com/apk/res/" + packageName;
  }

  public ResName withPackageName(String packageName) {
    if (packageName.equals(this.packageName)) return this;
    return new ResName(packageName, type, name);
  }

  public void mustBe(String expectedType) {
    if (!type.equals(expectedType)) {
      throw new RuntimeException("expected " + getFullyQualifiedName() + " to be a " + expectedType + ", is a " + type);
    }
  }

  private int computeHashCode() {
    int result = packageName.hashCode();
    result = 31 * result + type.hashCode();
    result = 31 * result + name.hashCode();
    return result;
  }
}

@@ -4120,144 +4120,8 @@
  %7D%0A%0A
-  public ResName qualify(String string) %7B%0A    return new ResName(qualifyResourceName(string.replace(%22@%22, %22%22), packageName, null));%0A  %7D%0A%0A
   @O

remove unused method