/*
 * 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.car.radio;

import android.content.Context;
import android.hardware.radio.ProgramSelector;
import android.view.View;
import android.widget.TextView;

import androidx.annotation.NonNull;

import com.android.car.radio.bands.ProgramType;
import com.android.car.radio.bands.RegionConfig;
import com.android.car.radio.widget.BandSelectorFlat;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

public class ManualTunerController {
    private final Object mLock = new Object();

    private final List<View> mDigitButtons = new ArrayList<>();
    private final View mEnterButton;
    private final TextView mChannelDisplay;
    private BandSelectorFlat mBandSelector;

    private ProgramType mProgramType;
    private final RegionConfig mRegionConfig;
    private final TuningDoneListener mDoneListener;
    private int mEnteredDigits;

    /**
     * Listener for manual tuning done event.
     */
    public interface TuningDoneListener {
        /**
         * Called when the user accepted channel selection.
         */
        void onDone(@NonNull ProgramSelector sel);
    }

    public ManualTunerController(Context context, View container,
            @NonNull RegionConfig regionConfig, @NonNull TuningDoneListener doneListener) {
        mRegionConfig = Objects.requireNonNull(regionConfig);
        mDoneListener = Objects.requireNonNull(doneListener);

        mChannelDisplay = Objects.requireNonNull(container.findViewById(R.id.manual_tuner_channel));
        mEnterButton = container.findViewById(R.id.manual_tuner_done_button);
        mBandSelector = container.findViewById(R.id.manual_tuner_band_selector);

        mEnterButton.setOnClickListener(this::onDoneClick);
        mBandSelector.setCallback(this::switchProgramType);
        mBandSelector.setSupportedProgramTypes(regionConfig.getSupportedProgramTypes());

        View dialpad = container.findViewById(R.id.dialpad_layout);
        View.OnClickListener digitClickListener = this::onDigitClick;
        for (int i = 0; i <= 9; i++) {
            View btn = dialpad.findViewWithTag(Integer.toString(i));
            btn.setOnClickListener(digitClickListener);
            mDigitButtons.add(i, btn);
        }
        View backspace = dialpad.findViewById(R.id.manual_tuner_backspace);
        backspace.setOnClickListener(this::onBackspaceClick);

        switchProgramType(ProgramType.FM);
    }

    private void updateDisplay() {
        synchronized (mLock) {
            mChannelDisplay.setText(mProgramType.format(mEnteredDigits));
            mEnterButton.setEnabled(mProgramType.isComplete(mRegionConfig, mEnteredDigits));
            boolean[] valid = mProgramType.getValidAppendices(mRegionConfig, mEnteredDigits);
            for (int i = 0; i < 10; i++) {
                mDigitButtons.get(i).setEnabled(valid[i]);
            }
        }
    }

    private void onDigitClick(View btn) {
        int digit = Integer.parseInt((String) btn.getTag());
        synchronized (mLock) {
            mEnteredDigits *= 10;
            mEnteredDigits += digit;
        }
        updateDisplay();
    }

    private void onBackspaceClick(View btn) {
        synchronized (mLock) {
            mEnteredDigits /= 10;
        }
        updateDisplay();
    }

    private void onDoneClick(View btn) {
        synchronized (mLock) {
            mDoneListener.onDone(mProgramType.parseDigits(mEnteredDigits));
            mEnteredDigits = 0;
        }
        updateDisplay();
    }

    /**
     * Switches program type (band).
     */
    public void switchProgramType(@NonNull ProgramType pt) {
        Objects.requireNonNull(pt);
        synchronized (mLock) {
            if (mProgramType == pt) return;
            mProgramType = pt;
            mEnteredDigits = 0;
            mBandSelector.setType(pt);
        }
        updateDisplay();
    }
}
