/*
 * Copyright 2016 requery.io
 *
 * 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 io.requery.processor;

import com.squareup.javapoet.ArrayTypeName;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.ParameterSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;

import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.Types;

/**
 * Handler for Android's Parcelable objects. If the target entity object implements Parcelable but
 * doesn't provide it's own implementation than a implementation will be provided in the generated
 * entity using {@link io.requery.android.EntityParceler}
 *
 * @author Nikhil Purushe
 */
@SuppressWarnings("JavadocReference")
class AndroidParcelableExtension implements TypeGenerationExtension {

    private static final String PACKAGE_ANDROID_OS = "android.os";
    private static final String PACKAGE_PARCELER = "io.requery.android";

    private final Types types;

    public AndroidParcelableExtension(Types types) {
        this.types = types;
    }

    @Override
    public void generate(EntityDescriptor entity, TypeSpec.Builder builder) {
        // if not parcelable or the class implements itself don't implement it
        TypeElement typeElement = entity.element();
        if (!Mirrors.isInstance(types, typeElement, PACKAGE_ANDROID_OS + ".Parcelable") ||
            Mirrors.overridesMethod(types, typeElement, "writeToParcel")) {
            return;
        }
        ClassName className = ClassName.bestGuess(entity.typeName().toString());
        // implement the parcelable interface
        TypeName creatorType = ParameterizedTypeName.get(
                ClassName.get(PACKAGE_ANDROID_OS, "Parcelable.Creator"), className);
        ClassName parcelName = ClassName.get(PACKAGE_ANDROID_OS, "Parcel");
        ClassName parcelableName = ClassName.get(PACKAGE_ANDROID_OS, "Parcelable");
        builder.addSuperinterface(parcelableName);

        TypeSpec.Builder creatorBuilder = TypeSpec.anonymousClassBuilder("")
            .addSuperinterface(creatorType)
            .addMethod(CodeGeneration.overridePublicMethod("createFromParcel")
                .addParameter(ParameterSpec.builder(parcelName, "source").build())
                .addStatement("return PARCELER.readFromParcel(source)")
                .returns(className).build())
            .addMethod(CodeGeneration.overridePublicMethod("newArray")
                .addParameter(TypeName.INT, "size")
                .addStatement("return new $T[size]", className)
                .returns(ArrayTypeName.of(className)).build());

        builder.addField(
            FieldSpec.builder(creatorType, "CREATOR",
                Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL)
                .initializer("$L", creatorBuilder.build()).build());

        builder.addMethod(
            CodeGeneration.overridePublicMethod("describeContents")
                .returns(TypeName.INT)
                .addStatement("return 0").build());

        builder.addMethod(
            CodeGeneration.overridePublicMethod("writeToParcel")
                .returns(TypeName.VOID)
                .addParameter(parcelName, "dest")
                .addParameter(TypeName.INT, "flags")
                .addStatement("PARCELER.writeToParcel(this, dest)").build());

        // add the parceler instance which uses the proxy to parcel the field data
        TypeName parcelerType = ParameterizedTypeName.get(
                ClassName.get(PACKAGE_PARCELER, "EntityParceler"), className);
        builder.addField(
                FieldSpec.builder(parcelerType, "PARCELER",
                    Modifier.PRIVATE, Modifier.STATIC, Modifier.FINAL)
                    .initializer("new $T($L)", parcelerType,
                            entity.staticTypeName()).build());
    }
}

@@ -1621,23 +1621,16 @@
 s;%0A%0A    
-public 
 AndroidP

fix constructor access warning