/*
 * Copyright (C) 2016 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.android.storagemanager.deletionhelper;

import android.content.Context;
import android.os.Parcel;
import android.os.Parcelable;
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
import androidx.preference.Preference;
import androidx.preference.PreferenceGroup;
import androidx.preference.PreferenceViewHolder;
import android.util.AttributeSet;

import android.view.View;
import android.view.ViewGroup;
import android.widget.Checkable;

import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.android.internal.annotations.VisibleForTesting;
import com.android.storagemanager.R;
import com.android.storagemanager.deletionhelper.DeletionType.LoadingStatus;

/**
 * CollapsibleCheckboxPreferenceGroup is a preference group that can be expanded or collapsed and
 * also has a checkbox.
 */
public class CollapsibleCheckboxPreferenceGroup extends PreferenceGroup implements
        View.OnClickListener {
    private boolean mCollapsed;
    private boolean mChecked;
    private TextView mTextView;
    private ProgressBar mProgressBar;
    private View mWidget;
    private boolean mLoaded;

    public CollapsibleCheckboxPreferenceGroup(Context context) {
        this(context, null);
    }

    public CollapsibleCheckboxPreferenceGroup(Context context, AttributeSet attrs) {
        super(context, attrs);
        setLayoutResource(R.layout.deletion_preference);
        setWidgetLayoutResource(androidx.preference.R.layout.preference_widget_checkbox);
    }

    @Override
    public void onBindViewHolder(PreferenceViewHolder holder) {
        super.onBindViewHolder(holder);
        View checkbox = holder.findViewById(com.android.internal.R.id.checkbox);
        mTextView = (TextView) holder.findViewById(android.R.id.summary);
        // Ensures that the color of the text is consistent with the checkbox having a tick or not
        mTextView.setActivated(mChecked);
        if (checkbox != null && checkbox instanceof Checkable) {
            ((Checkable) checkbox).setChecked(mChecked);

            // Expand the touch target by making the parent the touch target.
            View parent = (View) checkbox.getParent();
            parent.setClickable(true);
            parent.setFocusable(true);
            parent.setOnClickListener(this);
        }
        mProgressBar = (ProgressBar) holder.findViewById(R.id.progress_bar);
        mProgressBar.setVisibility(mLoaded ? View.GONE : View.VISIBLE);
        mWidget = holder.findViewById(android.R.id.widget_frame);
        mWidget.setVisibility(mLoaded ? View.VISIBLE : View.GONE);

        // CollapsibleCheckboxPreferenceGroup considers expansion to be its "longer-term
        // (activation) state."
        final ImageView imageView = (ImageView) holder.findViewById(android.R.id.icon);
        imageView.setActivated(!mCollapsed);
    }

    @Override
    public boolean addPreference(Preference p) {
        super.addPreference(p);
        p.setVisible(!isCollapsed());
        return true;
    }

    // The preference click handler.
    @Override
    protected void onClick() {
        super.onClick();
        setCollapse(!isCollapsed());
    }

    // The checkbox view click handler.
    @Override
    public void onClick(View v) {
        super.onClick();
        setChecked(!isChecked());

        // We need to find the CheckBox in the parent view that we are using as a touch target.
        // If we don't update it before onClick finishes, the accessibility gives invalid
        // responses.
        ViewGroup parent = (ViewGroup) v;
        View child =  parent.findViewById(com.android.internal.R.id.checkbox);
        Checkable checkable = (Checkable) child;
        checkable.setChecked(mChecked);
        // Causes text color change when activated to differentiate selected elements from
        // unselected elements.
        mTextView.setActivated(mChecked);
    }

    /**
     * Return if the view is collapsed.
     */
    public boolean isCollapsed() {
        return mCollapsed;
    }

    /**
     * Returns the checked state of the preference.
     */
    public boolean isChecked() {
        return mChecked;
    }

    /**
     * Sets the checked state and notifies listeners of the state change.
     */
    public void setChecked(boolean checked) {
        if (mChecked != checked) {
            mChecked = checked;

            callChangeListener(checked);
            notifyDependencyChange(shouldDisableDependents());
            notifyChanged();
        }
    }

    @Override
    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfoCompat info) {
        super.onInitializeAccessibilityNodeInfo(info);
        info.setCheckable(true);
        info.setChecked(isChecked());
    }

    @Override
    protected Parcelable onSaveInstanceState() {
        final Parcelable superState = super.onSaveInstanceState();

        final SavedState myState = new SavedState(superState);
        myState.checked = isChecked();
        myState.collapsed = isCollapsed();
        return myState;
    }

    @Override
    protected void onRestoreInstanceState(Parcelable state) {
        // Only restore the state if it is valid and our saved state.
        if (state == null || !SavedState.class.equals(state.getClass())) {
            super.onRestoreInstanceState(state);
            return;
        }

        SavedState myState = (SavedState) state;
        super.onRestoreInstanceState(myState.getSuperState());
        setChecked(myState.checked);
        setCollapse(myState.collapsed);
    }

    private void setCollapse(boolean isCollapsed) {
        if (mCollapsed == isCollapsed) {
            return;
        }

        mCollapsed = isCollapsed;
        setAllPreferencesVisibility(!isCollapsed);
        notifyChanged();
    }

    private void setAllPreferencesVisibility(boolean visible) {
        for (int i = 0; i < getPreferenceCount(); i++) {
            Preference p = getPreference(i);
            p.setVisible(visible);
        }
    }

    private static class SavedState extends BaseSavedState {
        boolean checked;
        boolean collapsed;

        public SavedState(Parcel source) {
            super(source);
            checked = source.readInt() != 0;
            collapsed = source.readInt() != 0;
        }

        public SavedState(Parcelable superState) {
            super(superState);
        }

        @Override
        public void writeToParcel(Parcel dest, int flags) {
            super.writeToParcel(dest, flags);
            dest.writeInt(checked ? 1 : 0);
            dest.writeInt(collapsed ? 1 : 0);
        }

        public static final Parcelable.Creator<SavedState> CREATOR =
                new Parcelable.Creator<SavedState>() {
                    public SavedState createFromParcel(Parcel in) {
                        return new SavedState(in);
                    }

                    public SavedState[] newArray(int size) {
                        return new SavedState[size];
                    }
                };
    }

    @VisibleForTesting
    void switchSpinnerToCheckboxOrDisablePreference(long freeableBytes, int loadingStatus) {
        mLoaded = loadingStatus != LoadingStatus.LOADING;
        setEnabled(loadingStatus != LoadingStatus.EMPTY);
        if (!isEnabled()) {
            setChecked(false);
        }
        if (mProgressBar != null) {
            mProgressBar.setVisibility(View.GONE);
        }
        if (mWidget != null) {
            mWidget.setVisibility(View.VISIBLE);
        }
    }
}
