public class ElementConstraints {
  public static final String MANIFEST = "manifest";
  public static final String APPLICATION = "application";
  public static final String ACTIVITY = "activity";
  public static final String INTENT_FILTER = "intent-filter";
  public static final String ACTION = "action";
  public static final String USES_PERMISSION = "uses-permission";

  public static final String RESOURCE = "resources";
} public enum Extension {
  JAVA(".java"), XML(".xml"), GRADLE(".gradle"), PRO(".pro"), JSON(".json");

  private String extensionName;

  Extension(String extensionName) {
    this.extensionName = extensionName;
  }

  @Override
  public String toString() {
    return extensionName.toLowerCase();
  }
} public class IntentConstraints {
  public static final String ACTION_MAIN = "android.intent.action.MAIN";
} public enum Permission {
  INTERNET;

  @Override
  public String toString() {
    return "android.permission." + name();
  }
} public class AttributeContraints {
  public static final String NAME = "android:name";
} public class SyntaxConstraints {
  public static final String IDENTIFIER_PACKAGE = "package";
  public static final String IDENTIFIER_IMPORT = "import";

  public static final String REPLACE_STRING = "%%";
  public static final String DEFAULT_INDENT = "  ";
  public static final String NEWLINE = "\n";
} public class ActivityNotFoundException extends RuntimeException {
  public ActivityNotFoundException() {
    super("failed to find main activity");
  }
} public class PackageNotFoundException extends RuntimeException {
  public PackageNotFoundException() {
    super("failed to find pacakage");
  }
} public class InjectionXmlFile extends InjectionBaseFile<ManifestConfig> {
  protected Document document;
  protected Element rootElement;

  public InjectionXmlFile(String fullPathname) {
    super(fullPathname);

    XmlDomReader xmlDomParser = new XmlDomReader(this);
    document = xmlDomParser.getDocument();
    rootElement = document.getDocumentElement();
  }

  @Override
  public void apply() {
    XmlDomWriter xmlDomWriter = new XmlDomWriter();
    try {
      xmlDomWriter.writeDocument(this, document);
    } catch (TransformerException | IOException e) {
      e.printStackTrace();
    }
  }
} public class ManifestConfig extends Config {
  @SerializedName("element")
  private List<ManifestElement> manifestElements;

  public ManifestConfig(String path, String fileNameEx) {
    super(path, fileNameEx);
  }

  public List<ManifestElement> getManifestElements() {
    return manifestElements;
  }

  @Override
  public String toString() {
    return "ManifestConfig{" +
        "manifestElements=" + manifestElements +
        '}';
  }
} public class ManifestElement {
  @SerializedName("node")
  private List<String> nodes;

  @SerializedName("attribute")
  private Map<String, String> attributes;

  public List<String> getNodes() {
    return nodes;
  }

  public Map<String, String> getAttributes() {
    return attributes;
  }

  @Override
  public String toString() {
    return "ManifestElement{" +
        "nodes=" + nodes +
        ", attributes=" + attributes +
        '}';
  }
} public class FileUtils {

  public static String getRootPath() {
    File projectDir = new File(".");

    try {
      int index = projectDir.getCanonicalPath().indexOf(AskConfig.DEFAULT_ASK_APP_NAME);

      if (index > 0) {
        return projectDir.getCanonicalPath().substring(0, index - 1);
      }
      return projectDir.getCanonicalPath();
    } catch (IOException e) {
      e.printStackTrace();
    }
    return null;
  }

  public static String linkPathWithSlash(String... args) {
    String path = "";
    for (int i = 0, li = args.length; i < li; i++) {
      path += args[i];

      if (i != li - 1) {
        path += "/";
      }
    }
    return path;
  }

  public static void writeFile(File file, List<String> lineList) {
    writeFile(file, toString(lineList));
  }

  public static void writeFile(File file, String content) {
    if (!file.getParentFile().exists() && !file.getParentFile().mkdirs()) {
      return;
    }

    FileWriter fileWriter;
    try {
      fileWriter = new FileWriter(file);
      BufferedWriter bw = new BufferedWriter(fileWriter);
      bw.write(content);
      bw.close();
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

  public static void writeFile(String pathName, String fileName, String content) {
    File destDir = new File(pathName);
    if (!destDir.exists() && !destDir.mkdirs()) {
      return;
    }

    writeFile(FileUtils.linkPathWithSlash(pathName, fileName), content);
  }

  public static void writeFile(String filePath, String content) {
    File file = new File(filePath);

    try {
      if (!file.exists()) {
        file.createNewFile();
      }

      writeFile(file, content);
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

  public static List<String> readFileAsString(File file) {
    Scanner scanner;
    List<String> stringList = new ArrayList<>();

    try {
      scanner = new Scanner(file);

      while (scanner.hasNextLine()) {
        String e = scanner.nextLine();
        stringList.add(e);
      }
    } catch (FileNotFoundException e) {
      throw new RuntimeException("Failed to find : " + file.getPath());
    }

    return stringList;
  }

  public static void copyFile(File moduleFile,
                              String sourceFilePath) throws IOException {
    File destDir = new File(sourceFilePath);
    if (!destDir.exists() && !destDir.mkdirs()) {
      return;
    }

    File sourceFile = moduleFile;
    File destFile = new File(linkPathWithSlash(sourceFilePath, moduleFile.getName()));

    if (!sourceFile.exists()) {
      return;
    }

    if (!destFile.exists()) {
      destFile.createNewFile();
    }

    FileChannel sourceChannel;
    FileChannel destinationChannel;

    sourceChannel = new FileInputStream(sourceFile).getChannel();
    destinationChannel = new FileOutputStream(destFile).getChannel();

    if (destinationChannel != null && sourceChannel != null) {
      destinationChannel.transferFrom(sourceChannel, 0, sourceChannel.size());
    }

    if (sourceChannel != null) {
      sourceChannel.close();
    }

    if (destinationChannel != null) {
      destinationChannel.close();
    }
  }

  public static void copyDirectory(File src, File dest) throws IOException{
    if (src.isDirectory()) {
      if (!dest.exists()) {
        dest.mkdirs();
      }

      String files[] = src.list();

      for (String file : files) {
        File srcFile = new File(src, file);
        File destFile = new File(dest, file);
        copyDirectory(srcFile,destFile);
      }

    } else {
      InputStream in = new FileInputStream(src);
      OutputStream out = new FileOutputStream(dest);

      byte[] buffer = new byte[1024];

      int length;
      while ((length = in.read(buffer)) > 0) {
        out.write(buffer, 0, length);
      }

      in.close();
      out.close();
    }
  }

  public static String changeDotToSlash(String str) {
    return str.replaceAll("\\.", "/");
  }

  public static String getStringBetweenQuotes(String str) {
    Pattern pattern = Pattern.compile("\"([^\"]*)\"");
    Matcher matcher = pattern.matcher(str);
    while (matcher.find()) {
      return matcher.group(1);
    }
    return null;
  }

  public static String getFilenameFromDotPath(String pathname) {
    int index = pathname.lastIndexOf(".");
    if (index < 0) {
      index = 0;
    } else {
      index += 1;
    }
    return pathname.substring(index, pathname.length());
  }

  public static String getFilenameFromSlashPath(String pathname) {
    int index = pathname.lastIndexOf("/");
    if (index < 0) {
      index = 0;
    } else {
      index += 1;
    }
    return pathname.substring(index, pathname.length());
  }

  public static String removeExtension(String filename) {
    return filename.substring(0, filename.lastIndexOf('.'));
  }

  public static String removeFirstSlash(String path) {
    if (path.length() > 0 && path.charAt(0) == '/') {
      path = path.substring(1);
    }

    return path;
  }

  public static String extractIndentInLine(String line) {
    String intent = "";
    for (int i = 0, li = line.length(); i < li; i++) {
      if (line.toCharArray()[i] == ' ') {
        intent += " ";
      } else {
        return intent;
      }
    }
    return intent;
  }

  public static String toString(List<String> strList) {
    final String EoL = System.getProperty("line.separator");

    StringBuilder sb = new StringBuilder();
    for (String line : strList) {
      sb.append(line).append(EoL);
    }

    return sb.toString();
  }

  public static String getStringWithRemovedComment(String line) {
    return line.replaceAll("//.*", "");
  }

  public static int getOpenCurlyBracketCount(String line) {
    int count = 0;
    for ( int i = 0; i < line.length(); i++ ) {
      if (line.charAt(i) == '{') {
        count++;
      }
    }
    return count;
  }

  public static int getCloseCurlyBracketCount(String line) {
    int count = 0;
    for ( int i = 0; i < line.length(); i++ ) {
      if (line.charAt(i) == '}') {
        count++;
      }
    }
    return count;
  }
}
import com.androidstarterkit.android.api.ElementConstraints;
import com.androidstarterkit.android.api.Extension;
import com.androidstarterkit.android.api.IntentConstraints;
import com.androidstarterkit.android.api.manifest.Permission;
import com.androidstarterkit.android.api.resource.AttributeContraints;
import com.androidstarterkit.constraints.SyntaxConstraints;
import com.androidstarterkit.exception.ActivityNotFoundException;
import com.androidstarterkit.exception.PackageNotFoundException;
import com.androidstarterkit.injection.file.android.InjectionXmlFile;
import com.androidstarterkit.injection.model.ManifestConfig;
import com.androidstarterkit.injection.model.ManifestElement;
import com.androidstarterkit.util.FileUtils;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
package com.androidstarterkit.file;




public class AndroidManifest extends InjectionXmlFile {
  private static final String TAG = AndroidManifest.class.getSimpleName();

  public static final String FILE_NAME = "AndroidManifest.xml";

  private Node applicationNode;
  private Node mainActivityNode;

  private String mainActivityName;
  private String packageName;

  public AndroidManifest(String pathname) {
    super(pathname + "/" + FILE_NAME);

    packageName = rootElement.getAttribute(SyntaxConstraints.IDENTIFIER_PACKAGE);

    if (packageName == null) {
      throw new PackageNotFoundException();
    }

    applicationNode = rootElement.getElementsByTagName(ElementConstraints.APPLICATION).item(0);
    mainActivityNode = getMainActivityNode();

    if (mainActivityNode == null) {
      throw new ActivityNotFoundException();
    }

    mainActivityName = FileUtils.getFilenameFromDotPath(((Element) mainActivityNode).getAttribute(AttributeContraints.NAME));
  }

  public void addPermissions(Permission... permissions) {
    if (permissions == null || permissions.length <= 0) {
      return;
    }

    for (Permission permission : permissions) {
      addUsesPermissionNode(permission.toString());
    }
  }

  public String getMainActivityName() {
    return mainActivityName;
  }

  public String getMainActivityNameEx() {
    return mainActivityName + Extension.JAVA;
  }

  public String getPackageName() {
    return packageName;
  }

  public String getApplicationRelativePathname() {
    NamedNodeMap applicationAttributeNodeMap = applicationNode.getAttributes();

    for (int i = 0, size = applicationAttributeNodeMap.getLength(); i < size; i++) {
      Node attributeNode = applicationAttributeNodeMap.item(i);
      if (attributeNode.getNodeName().equals(AttributeContraints.NAME)) {
        return attributeNode.getNodeValue();
      }
    }
    return null;
  }

  public void addApplicationAttribute(String key, String value) {
    Element applicationElement = (Element) applicationNode;
    applicationElement.setAttribute(key, value);
  }

  public void addMainActivityAttribute(String key, String value) {
    Element activityElement = (Element) mainActivityNode;
    activityElement.setAttribute(key, value);
  }

  private void addUsesPermissionNode(String value) {
    if (!getUsesPermissionNames().contains(value)) {
      Element usesPermissionElement = document.createElement(ElementConstraints.USES_PERMISSION);
      usesPermissionElement.setAttribute(AttributeContraints.NAME, value);
      rootElement.appendChild(usesPermissionElement);
    }
  }

  public Map<String, String> getMainActivityAttributes() {
    NamedNodeMap activityAttributeNodeMap = mainActivityNode.getAttributes();

    Map<String, String> attributes = new HashMap<>();
    if (activityAttributeNodeMap != null) {
      for (int i = 0, size = activityAttributeNodeMap.getLength(); i < size; i++) {
        Node attributeNode = activityAttributeNodeMap.item(i);
        attributes.put(attributeNode.getNodeName(), attributeNode.getNodeValue());
      }
    }

    return attributes;
  }

  @Override
  public void apply() {
    for (ManifestConfig config : configs) {
      for (ManifestElement element : config.getManifestElements()) {