/*
 * 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.
 */

// GENERATED CODE - PLEASE DO NOT EDIT

${generatedPackage}

public final class ${generatedClassName}${genericTypes} implements ${interfaceFullName} {

    private final com.github.dm.jrt.android.core.ServiceContext mContext;

    @SuppressWarnings("ConstantConditions")
    public ${generatedClassName}(@javax.annotation.Nonnull final com.github.dm.jrt.android.core.ServiceContext context,
            @javax.annotation.Nonnull final com.github.dm.jrt.android.core.ContextInvocationTarget target,
            @javax.annotation.Nonnull final com.github.dm.jrt.builder.InvocationConfiguration invocationConfiguration,
            @javax.annotation.Nonnull final com.github.dm.jrt.builder.ProxyConfiguration proxyConfiguration,
            @javax.annotation.Nonnull final com.github.dm.jrt.android.builder.ServiceConfiguration serviceConfiguration) {

        if (context == null) {

            throw new NullPointerException("the service context must not be null");
        }

        if (target.getTargetClass().isPrimitive()) {

            // The parceling of primitive classes is broken...
            throw new IllegalArgumentException("the target class cannot be primitive");
        }

        if (!${classErasure}.class.isAssignableFrom(target.getTargetClass())) {

            throw new IllegalArgumentException("the invocation target must be the class or an instance of " +
                    "${classFullName}");
        }

        mContext = context;
        ${routineFieldsInit}
    }

    @javax.annotation.Nonnull
    public static ${genericTypes} com.github.dm.jrt.android.proxy.builder.ServiceProxyBuilder<${interfaceFullName}> on(
            @javax.annotation.Nonnull final com.github.dm.jrt.android.core.ServiceContext context,
            @javax.annotation.Nonnull final com.github.dm.jrt.android.core.ContextInvocationTarget target) {

        return new ServiceProxyBuilder${genericTypes}(context, target);
    }

    @javax.annotation.Nonnull
    public static ContextBuilder on(@javax.annotation.Nonnull final com.github.dm.jrt.android.core.ServiceContext context) {

        return new ContextBuilder(context);
    }

    @javax.annotation.Nonnull
    private static <OUT> com.github.dm.jrt.android.builder.ServiceRoutineBuilder<Object, OUT> getBuilder(
            @javax.annotation.Nonnull final com.github.dm.jrt.android.core.ServiceContext context,
            @javax.annotation.Nonnull final com.github.dm.jrt.android.core.InvocationFactoryTarget<Object, OUT> target) {

        return com.github.dm.jrt.android.core.JRoutine.on(context).with(target);
    }

    public static class ContextBuilder {

        private final com.github.dm.jrt.android.core.ServiceContext mContext;

        @SuppressWarnings("ConstantConditions")
        private ContextBuilder(@javax.annotation.Nonnull final com.github.dm.jrt.android.core.ServiceContext context) {

            if (context == null) {

                throw new NullPointerException("the context must not be null");
            }

            mContext = context;
        }

        @javax.annotation.Nonnull
        public ${genericTypes} com.github.dm.jrt.android.proxy.builder.ServiceProxyBuilder<${interfaceFullName}> with(
                @javax.annotation.Nonnull final com.github.dm.jrt.android.core.ContextInvocationTarget target) {

            return new ServiceProxyBuilder${genericTypes}(mContext, target);
        }
    }

    private static class ServiceProxyBuilder${genericTypes} extends com.github.dm.jrt.android.proxy.builder.AbstractServiceProxyBuilder<${interfaceFullName}> {

        private final com.github.dm.jrt.android.core.ServiceContext mContext;

        private final com.github.dm.jrt.android.core.ContextInvocationTarget mTarget;

        private final com.github.dm.jrt.util.ClassToken<${interfaceFullName}> mToken = new com.github.dm.jrt.util.ClassToken<${interfaceFullName}>() {};

        @SuppressWarnings("ConstantConditions")
        private ServiceProxyBuilder(@javax.annotation.Nonnull final com.github.dm.jrt.android.core.ServiceContext context,
                @javax.annotation.Nonnull final com.github.dm.jrt.android.core.ContextInvocationTarget target) {

            if (context == null) {

                throw new NullPointerException("the service context must not be null");
            }

            if (target.getTargetClass().isPrimitive()) {

                // The parceling of primitive classes is broken...
                throw new IllegalArgumentException("the target class cannot be primitive");
            }

            mContext = context;
            mTarget = target;
        }

        @Override
        @javax.annotation.Nonnull
        protected com.github.dm.jrt.util.ClassToken<${interfaceFullName}> getInterfaceToken() {

            return mToken;
        }

        @Override
        @javax.annotation.Nullable
        protected android.content.Context getInvocationContext() {

            return mContext.getServiceContext();
        }

        @Override
        @javax.annotation.Nonnull
        protected Class<?> getTargetClass() {

            return mTarget.getTargetClass();
        }

        @Override
        @javax.annotation.Nonnull
        protected ${interfaceFullName} newProxy(
                @javax.annotation.Nonnull final com.github.dm.jrt.builder.InvocationConfiguration invocationConfiguration,
                @javax.annotation.Nonnull final com.github.dm.jrt.builder.ProxyConfiguration proxyConfiguration,
                @javax.annotation.Nonnull final com.github.dm.jrt.android.builder.ServiceConfiguration serviceConfiguration) {

            return new ${generatedClassName}${genericTypes}(mContext, mTarget, invocationConfiguration, proxyConfiguration, serviceConfiguration);
        }
    }
