/*
 * Copyright (C) 2019 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.settings.widget;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.TextView;

import androidx.core.content.res.TypedArrayUtils;
import androidx.preference.PreferenceViewHolder;

import com.android.internal.util.Preconditions;
import com.android.settings.R;
import com.android.settings.Utils;

/**
 * A labeled {@link SeekBarPreference} with left and right text label, icon label, or both.
 *
 * <p>
 * The component provides the attribute usage below.
 * <attr name="textStart" format="reference" />
 * <attr name="textEnd" format="reference" />
 * <attr name="tickMark" format="reference" />
 * <attr name="iconStart" format="reference" />
 * <attr name="iconEnd" format="reference" />
 * <attr name="iconStartContentDescription" format="reference" />
 * <attr name="iconEndContentDescription" format="reference" />
 * </p>
 *
 * <p> If you set the attribute values {@code iconStartContentDescription} or {@code
 * iconEndContentDescription} from XML, you must also set the corresponding attributes {@code
 * iconStart} or {@code iconEnd}, otherwise throws an {@link IllegalArgumentException}.</p>
 */
public class LabeledSeekBarPreference extends SeekBarPreference {

    private final int mTextStartId;
    private final int mTextEndId;
    private final int mTickMarkId;
    private int mIconStartId;
    private int mIconEndId;
    private int mIconStartContentDescriptionId;
    private int mIconEndContentDescriptionId;
    private OnPreferenceChangeListener mStopListener;
    private SeekBar.OnSeekBarChangeListener mSeekBarChangeListener;

    private SeekBar mSeekBar;

    public LabeledSeekBarPreference(Context context, AttributeSet attrs, int defStyleAttr,
            int defStyleRes) {

        super(context, attrs, defStyleAttr, defStyleRes);
        setLayoutResource(R.layout.preference_labeled_slider);

        final TypedArray styledAttrs = context.obtainStyledAttributes(attrs,
                R.styleable.LabeledSeekBarPreference);
        mTextStartId = styledAttrs.getResourceId(
                R.styleable.LabeledSeekBarPreference_textStart, /* defValue= */ 0);
        mTextEndId = styledAttrs.getResourceId(
                R.styleable.LabeledSeekBarPreference_textEnd, /* defValue= */ 0);
        mTickMarkId = styledAttrs.getResourceId(
                R.styleable.LabeledSeekBarPreference_tickMark, /* defValue= */ 0);
        mIconStartId = styledAttrs.getResourceId(
                R.styleable.LabeledSeekBarPreference_iconStart, /* defValue= */ 0);
        mIconEndId = styledAttrs.getResourceId(
                R.styleable.LabeledSeekBarPreference_iconEnd, /* defValue= */ 0);

        mIconStartContentDescriptionId = styledAttrs.getResourceId(
                R.styleable.LabeledSeekBarPreference_iconStartContentDescription,
                /* defValue= */ 0);
        Preconditions.checkArgument(!(mIconStartContentDescriptionId != 0 && mIconStartId == 0),
                "The resource of the iconStart attribute may be invalid or not set, "
                        + "you should set the iconStart attribute and have the valid resource.");

        mIconEndContentDescriptionId = styledAttrs.getResourceId(
                R.styleable.LabeledSeekBarPreference_iconEndContentDescription,
                /* defValue= */ 0);
        Preconditions.checkArgument(!(mIconEndContentDescriptionId != 0 && mIconEndId == 0),
                "The resource of the iconEnd attribute may be invalid or not set, "
                        + "you should set the iconEnd attribute and have the valid resource.");
        styledAttrs.recycle();
    }

    public LabeledSeekBarPreference(Context context, AttributeSet attrs) {
        this(context, attrs, TypedArrayUtils.getAttr(context,
                androidx.preference.R.attr.seekBarPreferenceStyle,
                com.android.internal.R.attr.seekBarPreferenceStyle), 0);
    }

    public SeekBar getSeekbar() {
        return mSeekBar;
    }

    /** Set the start icon of the Seekbar. */
    public void setIconStart(int iconStartId) {
        if (mIconStartId != iconStartId) {
            mIconStartId = iconStartId;
            notifyChanged();
        }
    }

    /** Set the description resource id of the start icon. */
    public void setIconStartContentDescription(int iconStartContentDescriptionId) {
        if (mIconStartContentDescriptionId != iconStartContentDescriptionId) {
            mIconStartContentDescriptionId = iconStartContentDescriptionId;
            notifyChanged();
        }
    }

    /** Set the end icon of the Seekbar. */
    public void setIconEnd(int iconEndId) {
        if (mIconEndId != iconEndId) {
            mIconEndId = iconEndId;
            notifyChanged();
        }
    }

    /** Set the description resource id of the end icon. */
    public void setIconEndContentDescription(int iconEndContentDescriptionId) {
        if (mIconEndContentDescriptionId != iconEndContentDescriptionId) {
            mIconEndContentDescriptionId = iconEndContentDescriptionId;
            notifyChanged();
        }
    }

    @Override
    public void onBindViewHolder(PreferenceViewHolder holder) {
        super.onBindViewHolder(holder);

        final TextView summaryView = (TextView) holder.findViewById(android.R.id.summary);
        boolean isSummaryVisible = false;
        if (summaryView != null) {
            isSummaryVisible = (summaryView.getVisibility() == View.VISIBLE);
        }
        final TextView titleView = (TextView) holder.findViewById(android.R.id.title);
        if (titleView != null && !isSelectable() && isEnabled() && isSummaryVisible) {
            titleView.setTextColor(
                    Utils.getColorAttr(getContext(), android.R.attr.textColorPrimary));
        }

        final TextView startText = (TextView) holder.findViewById(android.R.id.text1);
        if (mTextStartId > 0) {
            startText.setText(mTextStartId);
        }

        final TextView endText = (TextView) holder.findViewById(android.R.id.text2);
        if (mTextEndId > 0) {
            endText.setText(mTextEndId);
        }

        final View labelFrame = holder.findViewById(R.id.label_frame);
        final boolean isValidTextResIdExist = mTextStartId > 0 || mTextEndId > 0;
        labelFrame.setVisibility(isValidTextResIdExist ? View.VISIBLE : View.GONE);

        mSeekBar = (SeekBar) holder.findViewById(com.android.internal.R.id.seekbar);
        if (mTickMarkId != 0) {
            final Drawable tickMark = getContext().getDrawable(mTickMarkId);
            mSeekBar.setTickMark(tickMark);
        }

        final ViewGroup iconStartFrame = (ViewGroup) holder.findViewById(R.id.icon_start_frame);
        final ImageView iconStartView = (ImageView) holder.findViewById(R.id.icon_start);
        updateIconStartIfNeeded(iconStartFrame, iconStartView, mSeekBar);

        final ViewGroup iconEndFrame = (ViewGroup) holder.findViewById(R.id.icon_end_frame);
        final ImageView iconEndView = (ImageView) holder.findViewById(R.id.icon_end);
        updateIconEndIfNeeded(iconEndFrame, iconEndView, mSeekBar);
    }

    public void setOnPreferenceChangeStopListener(OnPreferenceChangeListener listener) {
        mStopListener = listener;
    }

    @Override
    public void onStartTrackingTouch(SeekBar seekBar) {
        super.onStartTrackingTouch(seekBar);

        if (mSeekBarChangeListener != null) {
            mSeekBarChangeListener.onStartTrackingTouch(seekBar);
        }
    }

    @Override
    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
        super.onProgressChanged(seekBar, progress, fromUser);

        if (mSeekBarChangeListener != null) {
            mSeekBarChangeListener.onProgressChanged(seekBar, progress, fromUser);
        }
    }

    @Override
    public void onStopTrackingTouch(SeekBar seekBar) {
        super.onStopTrackingTouch(seekBar);

        if (mSeekBarChangeListener != null) {
            mSeekBarChangeListener.onStopTrackingTouch(seekBar);
        }

        if (mStopListener != null) {
            mStopListener.onPreferenceChange(this, seekBar.getProgress());
        }

        // Need to update the icon enabled status
        notifyChanged();
    }

    public void setOnSeekBarChangeListener(SeekBar.OnSeekBarChangeListener seekBarChangeListener) {
        mSeekBarChangeListener = seekBarChangeListener;
    }

    private void updateIconStartIfNeeded(ViewGroup iconFrame, ImageView iconStart,
            SeekBar seekBar) {
        if (mIconStartId == 0) {
            return;
        }

        if (iconStart.getDrawable() == null) {
            iconStart.setImageResource(mIconStartId);
        }

        if (mIconStartContentDescriptionId != 0) {
            final String contentDescription =
                    iconFrame.getContext().getString(mIconStartContentDescriptionId);
            iconFrame.setContentDescription(contentDescription);
        }

        iconFrame.setOnClickListener((view) -> {
            final int progress = getProgress();
            if (progress > 0) {
                setProgress(progress - 1);
            }
        });

        iconFrame.setVisibility(View.VISIBLE);
        setIconViewAndFrameEnabled(iconStart, seekBar.getProgress() > 0);
    }

    private void updateIconEndIfNeeded(ViewGroup iconFrame, ImageView iconEnd, SeekBar seekBar) {
        if (mIconEndId == 0) {
            return;
        }

        if (iconEnd.getDrawable() == null) {
            iconEnd.setImageResource(mIconEndId);
        }

        if (mIconEndContentDescriptionId != 0) {
            final String contentDescription =
                    iconFrame.getContext().getString(mIconEndContentDescriptionId);
            iconFrame.setContentDescription(contentDescription);
        }

        iconFrame.setOnClickListener((view) -> {
            final int progress = getProgress();
            if (progress < getMax()) {
                setProgress(progress + 1);
            }
        });

        iconFrame.setVisibility(View.VISIBLE);
        setIconViewAndFrameEnabled(iconEnd, seekBar.getProgress() < seekBar.getMax());
    }

    private static void setIconViewAndFrameEnabled(View iconView, boolean enabled) {
        iconView.setEnabled(enabled);
        final ViewGroup iconFrame = (ViewGroup) iconView.getParent();
        iconFrame.setEnabled(enabled);
    }
}

