/*
* Copyright 2017 WalmartLabs
* 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 {{package}};

import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import java.util.List;

import com.walmartlabs.electrode.reactnative.bridge.Bridgeable;

import static com.walmartlabs.electrode.reactnative.bridge.util.BridgeArguments.*;
{{#models}}
{{#model}}
{{#description}}
/**
* {{description}}
**/{{/description}}
public class {{classname}} implements Parcelable, Bridgeable {

    {{#vars}}
    private {{{datatype}}} {{name}};
    {{/vars}}

    private {{classname}}() {}

    private {{classname}}(Builder builder) {
    {{#vars}}
        this.{{name}} = builder.{{name}};
    {{/vars}}
    }

    private {{classname}}(Parcel in) {
        this(in.readBundle());
    }

    public {{classname}}(@NonNull Bundle bundle) {
    {{#requiredVars}}
        if(!bundle.containsKey("{{name}}")){
            throw new IllegalArgumentException("{{name}} property is required");
        }

    {{/requiredVars}}
    {{#allVars}}
        {{#isListContainer}}
        {{#items}}
        {{#isString}}
        this.{{baseName}} = bundle.containsKey("{{baseName}}") ? getList(bundle.getStringArray("{{baseName}}"), String.class) : null;
        {{/isString}}
        {{#isInteger}}
        this.{{baseName}} = bundle.containsKey("{{baseName}}") ? getList(bundle.getIntArray("{{baseName}}"), Integer.class) : null;
        {{/isInteger}}
        {{#isBoolean}}
        this.{{baseName}} = bundle.containsKey("{{baseName}}") ? getList(bundle.getBooleanArray("{{baseName}}"), Boolean.class) : null;
        {{/isBoolean}}
        {{#isLong}}
        this.{{baseName}} = bundle.containsKey("{{baseName}}") ? getList(bundle.getLongArray("{{baseName}}"), Long.class) : null;
        {{/isLong}}
        {{#isDouble}}
        this.{{baseName}} = bundle.containsKey("{{baseName}}") ? getList(bundle.getDoubleArray("{{baseName}}"), Double.class) : null;
        {{/isDouble}}
        {{#isFloat}}
        this.{{baseName}} = bundle.containsKey("{{baseName}}") ? getList(bundle.getFloatArray("{{baseName}}"), Float.class) : null;
        {{/isFloat}}
        {{^isPrimitiveType}}
        this.{{baseName}} = bundle.containsKey("{{baseName}}") ? getList(bundle.getParcelableArray("{{baseName}}"), {{{datatype}}}.class) : null;
        {{/isPrimitiveType}}
        {{/items}}
        {{/isListContainer}}
        {{^isListContainer}}
        {{#isString}}
        this.{{name}} = bundle.getString("{{name}}");
        {{/isString}}
        {{#isInteger}}
        this.{{name}} = getNumberValue(bundle, "{{name}}") == null ? null : getNumberValue(bundle, "{{name}}").intValue();
        {{/isInteger}}
        {{#isBoolean}}
        this.{{name}} = bundle.containsKey("{{name}}") ? bundle.getBoolean("{{name}}") : null;
        {{/isBoolean}}
        {{#isLong}}
        this.{{name}} = getNumberValue(bundle, "{{name}}") == null ? null : getNumberValue(bundle, "{{name}}").longValue();
        {{/isLong}}
        {{#isDouble}}
        this.{{name}} = bundle.getDouble("{{name}}");
        {{/isDouble}}
        {{#isFloat}}
        this.{{name}} = getNumberValue(bundle, "{{name}}") == null ? null : getNumberValue(bundle, "{{name}}").floatValue();
        {{/isFloat}}
        {{^isPrimitiveType}}
        this.{{name}} = bundle.containsKey("{{name}}") ? new {{{datatype}}}(bundle.getBundle("{{name}}")) : null;
        {{/isPrimitiveType}}
        {{/isListContainer}}
    {{/allVars}}
    }

{{#classname}}
    public static final Creator<{{classname}}> CREATOR = new Creator<{{classname}}>() {
        @Override
        public {{classname}} createFromParcel(Parcel in) {
            return new {{classname}}(in);
        }

        @Override
        public {{classname}}[] newArray(int size) {
            return new {{classname}}[size];
        }
    };
{{/classname}}

    {{#vars}}
    {{#description}}
    /**
    * {{description}}
    *
    * @return {{{datatype}}}
    */
    {{/description}}
    {{#required}}
    @NonNull
    {{/required}}
    {{^required}}
    @Nullable
    {{/required}}
    public {{{datatype}}} {{getter}}() {
        return {{name}};
    }

    {{/vars}}

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeBundle(toBundle());
    }

    @NonNull
    @Override
    public Bundle toBundle() {
        Bundle bundle = new Bundle();
        {{#requiredVars}}
        {{#isListContainer}}
        updateBundleWithList(this.{{name}}, bundle, "{{name}}");
        {{/isListContainer}}
        {{^isListContainer}}
        {{#isString}}
        bundle.putString("{{name}}", this.{{name}});
        {{/isString}}
        {{#isInteger}}
        bundle.putInt("{{name}}", this.{{name}});
        {{/isInteger}}
        {{#isLong}}
        bundle.putLong("{{name}}", this.{{name}});
        {{/isLong}}
        {{#isDouble}}
        bundle.putDouble("{{name}}", this.{{name}});
        {{/isDouble}}
        {{#isFloat}}
        bundle.putFloat("{{name}}", this.{{name}});
        {{/isFloat}}
        {{#isBoolean}}
        bundle.putBoolean("{{name}}", this.{{name}});
        {{/isBoolean}}
        {{^isPrimitiveType}}
        bundle.putBundle("{{name}}", this.{{name}}.toBundle());
        {{/isPrimitiveType}}
        {{/isListContainer}}
        {{/requiredVars}}
        {{#optionalVars}}
        {{#isListContainer}}
        if(this.{{name}} != null) {
            updateBundleWithList(this.{{name}}, bundle, "{{name}}");
        }
        {{/isListContainer}}
        {{^isListContainer}}
        {{#isString}}
        if({{name}} != null) {
            bundle.putString("{{name}}", this.{{name}} );
        }
        {{/isString}}
        {{#isInteger}}
        if(this.{{name}} != null) {
            bundle.putInt("{{name}}", this.{{name}});
        }
        {{/isInteger}}
        {{#isLong}}
        if(this.{{name}} != null) {
            bundle.putLong("{{name}}", this.{{name}});
        }
        {{/isLong}}
        {{#isDouble}}
        if(this.{{name}} != null) {
            bundle.putDouble("{{name}}", this.{{name}});
         }
        {{/isDouble}}
        {{#isFloat}}
        if(this.{{name}} != null) {
           bundle.putFloat("{{name}}", this.{{name}});
        }
        {{/isFloat}}
        {{#isBoolean}}
        if(this.{{name}} != null) {
            bundle.putBoolean("{{name}}", this.{{name}});
        }
        {{/isBoolean}}
        {{^isPrimitiveType}}
        if(this.{{name}} != null) {
            bundle.putBundle("{{name}}", this.{{name}}.toBundle());
        }
        {{/isPrimitiveType}}
        {{/isListContainer}}
        {{/optionalVars}}
        return bundle;
    }

    @Override
    public String toString() {
        return "{"
        {{#allVars}}
        {{#isListContainer}}
        + "{{name}}:" + ({{name}} != null ? {{name}}.toString() : null){{^-last}}+ ","{{/-last}}
        {{/isListContainer}}
        {{#isString}}
        + "{{name}}:" + ({{name}} != null ? "\"" + {{name}} + "\"" : null){{^-last}}+ ","{{/-last}}
        {{/isString}}
        {{^isListContainer}}
        {{^isString}}
        {{#isPrimitiveType}}
        + "{{name}}:" + {{name}}{{^-last}}+ ","{{/-last}}
        {{/isPrimitiveType}}
        {{/isString}}
        {{^isPrimitiveType}}
        + "{{name}}:" + ({{name}} != null ? {{name}}.toString() : null){{^-last}}+ ","{{/-last}}
        {{/isPrimitiveType}}
        {{/isListContainer}}
        {{/allVars}}
        + "}";
    }

    public static class Builder {
        {{#requiredVars}}
        private final {{{datatype}}} {{name}};
        {{/requiredVars}}
        {{#optionalVars}}
        private {{{datatype}}} {{name}};
        {{/optionalVars}}

        public Builder({{#requiredVars}}@NonNull {{{datatype}}} {{name}}{{^-last}}, {{/-last}}{{/requiredVars}}) {
        {{#requiredVars}}
            this.{{name}} = {{name}};
        {{/requiredVars}}
        }

        {{#optionalVars}}
        @NonNull
        public Builder {{name}}(@Nullable {{{datatype}}} {{name}}) {
            this.{{name}} = {{name}};
            return this;
        }
        {{/optionalVars}}

        @NonNull
        public {{classname}} build() {
            return new {{classname}}(this);
        }
    }
}
{{/model}}
{{/models}}
