package com.ionicframework.cordova.webview;

/*
 * Copyright (C) 2006 The Android Open Source Project
 *
 * 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.webviewlocalserver.third_party.android;

import android.net.Uri;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

public class UriMatcher {
  /**
   * Creates the root node of the URI tree.
   *
   * @param code the code to match for the root URI
   */
  public UriMatcher(Object code) {
    mCode = code;
    mWhich = -1;
    mChildren = new ArrayList<UriMatcher>();
    mText = null;
  }

  private UriMatcher() {
    mCode = null;
    mWhich = -1;
    mChildren = new ArrayList<UriMatcher>();
    mText = null;
  }

  /**
   * Add a URI to match, and the code to return when this URI is
   * matched. URI nodes may be exact match string, the token "*"
   * that matches any text, or the token "#" that matches only
   * numbers.
   * <p>
   * Starting from API level {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2},
   * this method will accept a leading slash in the path.
   *
   * @param authority the authority to match
   * @param path      the path to match. * may be used as a wild card for
   *                  any text, and # may be used as a wild card for numbers.
   * @param code      the code that is returned when a URI is matched
   *                  against the given components. Must be positive.
   */
  public void addURI(String scheme, String authority, String path, Object code) {
    if (code == null) {
      throw new IllegalArgumentException("Code can't be null");
    }

    String[] tokens = null;
    if (path != null) {
      String newPath = path;
      // Strip leading slash if present.
      if (path.length() > 0 && path.charAt(0) == '/') {
        newPath = path.substring(1);
      }
      tokens = PATH_SPLIT_PATTERN.split(newPath);
    }

    int numTokens = tokens != null ? tokens.length : 0;
    UriMatcher node = this;
    for (int i = -2; i < numTokens; i++) {
      String token;
      if (i == -2)
        token = scheme;
      else if (i == -1)
        token = authority;
      else
        token = tokens[i];
      ArrayList<UriMatcher> children = node.mChildren;
      int numChildren = children.size();
      UriMatcher child;
      int j;
      for (j = 0; j < numChildren; j++) {
        child = children.get(j);
        if (token.equals(child.mText)) {
          node = child;
          break;
        }
      }
      if (j == numChildren) {
        // Child not found, create it
        child = new UriMatcher();
        if (token.equals("**")) {
          child.mWhich = REST;
        } else if (token.equals("*")) {
          child.mWhich = TEXT;
        } else {
          child.mWhich = EXACT;
        }
        child.mText = token;
        node.mChildren.add(child);
        node = child;
      }
    }
    node.mCode = code;
  }

  static final Pattern PATH_SPLIT_PATTERN = Pattern.compile("/");

  /**
   * Try to match against the path in a url.
   *
   * @param uri The url whose path we will match against.
   * @return The code for the matched node (added using addURI),
   * or null if there is no matched node.
   */
  public Object match(Uri uri) {
    final List<String> pathSegments = uri.getPathSegments();
    final int li = pathSegments.size();

    UriMatcher node = this;

    if (li == 0 && uri.getAuthority() == null) {
      return this.mCode;
    }

    for (int i = -2; i < li; i++) {
      String u;
      if (i == -2)
        u = uri.getScheme();
      else if (i == -1)
        u = uri.getAuthority();
      else
        u = pathSegments.get(i);
      ArrayList<UriMatcher> list = node.mChildren;
      if (list == null) {
        break;
      }
      node = null;
      int lj = list.size();
      for (int j = 0; j < lj; j++) {
        UriMatcher n = list.get(j);
        which_switch:
        switch (n.mWhich) {
          case EXACT:
            if (n.mText.equals(u)) {
              node = n;
            }
            break;
          case TEXT:
            node = n;
            break;
          case REST:
            return n.mCode;
        }
        if (node != null) {
          break;
        }
      }
      if (node == null) {
        return null;
      }
    }

    return node.mCode;
  }

  private static final int EXACT = 0;
  private static final int TEXT = 1;
  private static final int REST = 2;

  private Object mCode;
  private int mWhich;
  private String mText;
  private ArrayList<UriMatcher> mChildren;
}
