// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package io.flutter.plugin.common;

import java.util.Map;
import org.json.JSONObject;

/**
 * Command object representing a method call on a {@link MethodChannel}.
 */
public final class MethodCall {
    /**
     * The name of the called method.
     */
    public final String method;

    /**
     * Arguments for the call.
     *
     * Consider using {@link #arguments()} for cases where a particular run-time type is expected.
     * Consider using {@link #argument(String)} when that run-time type is a {@link Map}
     * or a {@link JSONObject}.
     */
    public final Object arguments;

    /**
     * Creates a {@link MethodCall} with the specified method name and arguments.
     *
     * @param method the method name String, not null.
     * @param arguments the arguments, a value supported by the channel's message codec.
     */
    public MethodCall(String method, Object arguments) {
        assert method != null;
        this.method = method;
        this.arguments = arguments;
    }

    /**
     * Returns the arguments of this method call with a static type determined by the call-site.
     *
     * @param <T> the intended type of the arguments.
     * @return the arguments with static type T
     */
    @SuppressWarnings("unchecked")
    public <T> T arguments() {
        return (T) arguments;
    }

    /**
     * Returns a String-keyed argument of this method call, assuming {@link #arguments} is a
     * {@link Map} or a {@link JSONObject}. The static type of the returned result is determined
     * by the call-site.
     *
     * @param <T> the intended type of the argument.
     * @param key the String key.
     * @return the argument value at the specified key, with static type T, or {@code null}, if
     * such an entry is not present.
     * @throws ClassCastException if {@link #arguments} can be cast to neither {@link Map} nor
     * {@link JSONObject}.
     */
    @SuppressWarnings("unchecked")
    public <T> T argument(String key) {
        if (arguments == null) {
            return null;
        } else if (arguments instanceof Map) {
            return (T) ((Map<?, ?>) arguments).get(key);
        } else if (arguments instanceof JSONObject) {
            return (T) ((JSONObject) arguments).opt(key);
        } else {
            throw new ClassCastException();
        }
    }
}

@@ -490,32 +490,35 @@
 .%0A     *%0A     * 
+%3Cp%3E
 Consider using %7B
@@ -668,18 +668,16 @@
 type is 
-a 
 %7B@link M
@@ -683,20 +683,18 @@
 Map%7D
+ or
 %0A     *
- or a
  %7B@l
@@ -701,32 +701,36 @@
 ink JSONObject%7D.
+%3C/p%3E
 %0A     */%0A    pub
@@ -2498,11 +2498,1026 @@
  %7D%0A    %7D
+%0A%0A    /**%0A     * Returns whether this method call involves a mapping for the given argument key,%0A     * assuming %7B@link #arguments%7D is a %7B@link Map%7D or a %7B@link JSONObject%7D. The value associated%0A     * with the key, as returned by %7B@link #argument(String)%7D, is not considered, and may be%0A     * %7B@code null%7D.%0A     *%0A     * @param key the String key.%0A     * @return %7B@code true%7D, if %7B@link #arguments%7D is a %7B@link Map%7D containing key, or a%0A     * %7B@link JSONObject%7D with a mapping for key.%0A     * @throws ClassCastException if %7B@link #arguments%7D can be cast to neither %7B@link Map%7D nor%0A     * %7B@link JSONObject%7D.%0A     */%0A    public boolean hasArgument(String key) %7B%0A        if (arguments == null) %7B%0A            return false;%0A        %7D else if (arguments instanceof Map) %7B%0A            return ((Map%3C?, ?%3E) arguments).containsKey(key);%0A        %7D else if (arguments instanceof JSONObject) %7B%0A            return ((JSONObject) arguments).has(key);%0A        %7D else %7B%0A            throw new ClassCastException();%0A        %7D%0A    %7D
 %0A%7D%0A

Add hasArgument convenience to MethodCall (#3612)