/*
 * Copyright (C) 2014 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.server.hdmi;

import android.hardware.hdmi.HdmiCec;
import android.hardware.hdmi.HdmiCecMessage;

/**
 * Base feature action class for SystemAudioActionFromTv and SystemAudioActionFromAvr.
 */
abstract class SystemAudioAction extends FeatureAction {
    private static final String TAG = "SystemAudioAction";

    // State in which waits for <SetSystemAudioMode>.
    private static final int STATE_WAIT_FOR_SET_SYSTEM_AUDIO_MODE = 1;

    // State in which waits for <ReportAudioStatus>.
    private static final int STATE_WAIT_FOR_REPORT_AUDIO_STATUS = 2;

    private static final int MAX_SEND_RETRY_COUNT = 2;

    private static final int ON_TIMEOUT_MS = 5000;
    private static final int OFF_TIMEOUT_MS = TIMEOUT_MS;

    // Logical address of AV Receiver.
    protected final int mAvrLogicalAddress;

    // The target audio status of the action, whether to enable the system audio mode or not.
    protected boolean mTargetAudioStatus;

    private int mSendRetryCount = 0;

    /**
     * Constructor
     *
     * @param service {@link HdmiControlService} instance
     * @param sourceAddress logical address of source device (TV or STB).
     * @param avrAddress logical address of AVR device
     * @param targetStatus Whether to enable the system audio mode or not
     * @throw IllegalArugmentException if device type of sourceAddress and avrAddress is invalid
     */
    SystemAudioAction(HdmiControlService service, int sourceAddress, int avrAddress,
            boolean targetStatus) {
        super(service, sourceAddress);
        HdmiUtils.verifyAddressType(avrAddress, HdmiCec.DEVICE_AUDIO_SYSTEM);
        mAvrLogicalAddress = avrAddress;
        mTargetAudioStatus = targetStatus;
    }

    protected void sendSystemAudioModeRequest() {
        int avrPhysicalAddress = mService.getAvrDeviceInfo().getPhysicalAddress();
        HdmiCecMessage command = HdmiCecMessageBuilder.buildSystemAudioModeRequest(mSourceAddress,
                mAvrLogicalAddress, avrPhysicalAddress, mTargetAudioStatus);
        sendCommand(command, new HdmiControlService.SendMessageCallback() {
            @Override
            public void onSendCompleted(int error) {
                if (error == HdmiControlService.SEND_RESULT_SUCCESS) {
                    mState = STATE_WAIT_FOR_SET_SYSTEM_AUDIO_MODE;
                    addTimer(mState, mTargetAudioStatus ? ON_TIMEOUT_MS : OFF_TIMEOUT_MS);
                } else {
                    setSystemAudioMode(false);
                    finish();
                }
            }
        });
    }

    private void handleSendSystemAudioModeRequestTimeout() {
        if (!mTargetAudioStatus  // Don't retry for Off case.
                || mSendRetryCount++ >= MAX_SEND_RETRY_COUNT) {
            setSystemAudioMode(false);
            finish();
            return;
        }
        sendSystemAudioModeRequest();
    }

    protected void setSystemAudioMode(boolean mode) {
        mService.setSystemAudioMode(mode);
    }

    protected void sendGiveAudioStatus() {
        HdmiCecMessage command = HdmiCecMessageBuilder.buildGiveAudioStatus(mSourceAddress,
                mAvrLogicalAddress);
        sendCommand(command, new HdmiControlService.SendMessageCallback() {
            @Override
            public void onSendCompleted(int error) {
                if (error == HdmiControlService.SEND_RESULT_SUCCESS) {
                    mState = STATE_WAIT_FOR_REPORT_AUDIO_STATUS;
                    addTimer(mState, TIMEOUT_MS);
                } else {
                    handleSendGiveAudioStatusFailure();
                }
            }
        });
    }

    private void handleSendGiveAudioStatusFailure() {
        // TODO: Notify the failure status.

        int uiCommand = mService.getSystemAudioMode()
                ? HdmiConstants.UI_COMMAND_RESTORE_VOLUME_FUNCTION  // SystemAudioMode: ON
                : HdmiConstants.UI_COMMAND_MUTE_FUNCTION;           // SystemAudioMode: OFF
        sendUserControlPressedAndReleased(uiCommand);
        finish();
    }

    private void sendUserControlPressedAndReleased(int uiCommand) {
        sendCommand(HdmiCecMessageBuilder.buildUserControlPressed(
                mSourceAddress, mAvrLogicalAddress, uiCommand));
        sendCommand(HdmiCecMessageBuilder.buildUserControlReleased(
                mSourceAddress, mAvrLogicalAddress));
    }

    @Override
    final boolean processCommand(HdmiCecMessage cmd) {
        switch (mState) {
            case STATE_WAIT_FOR_SET_SYSTEM_AUDIO_MODE:
                // TODO: Handle <FeatureAbort> of <SystemAudioModeRequest>
                if (cmd.getOpcode() != HdmiCec.MESSAGE_SET_SYSTEM_AUDIO_MODE
                        || !HdmiUtils.checkCommandSource(cmd, mAvrLogicalAddress, TAG)) {
                    return false;
                }
                boolean receivedStatus = HdmiUtils.parseCommandParamSystemAudioStatus(cmd);
                if (receivedStatus == mTargetAudioStatus) {
                    setSystemAudioMode(receivedStatus);
                    sendGiveAudioStatus();
                } else {
                    // Unexpected response, consider the request is newly initiated by AVR.
                    // To return 'false' will initiate new SystemAudioActionFromAvr by the control
                    // service.
                    finish();
                    return false;
                }
                return true;

            case STATE_WAIT_FOR_REPORT_AUDIO_STATUS:
                // TODO: Handle <FeatureAbort> of <GiveAudioStatus>
                if (cmd.getOpcode() != HdmiCec.MESSAGE_REPORT_AUDIO_STATUS
                        || !HdmiUtils.checkCommandSource(cmd, mAvrLogicalAddress, TAG)) {
                    return false;
                }
                byte[] params = cmd.getParams();
                if (params.length > 0) {
                    boolean mute = (params[0] & 0x80) == 0x80;
                    int volume = params[0] & 0x7F;
                    mService.setAudioStatus(mute, volume);
                    if (mTargetAudioStatus && mute || !mTargetAudioStatus && !mute) {
                        // Toggle AVR's mute status to match with the system audio status.
                        sendUserControlPressedAndReleased(HdmiConstants.UI_COMMAND_MUTE);
                    }
                }
                finish();
                return true;
        }
        return false;
    }

    protected void removeSystemAudioActionInProgress() {
        mService.removeActionExcept(SystemAudioActionFromTv.class, this);
        mService.removeActionExcept(SystemAudioActionFromAvr.class, this);
    }

    @Override
    final void handleTimerEvent(int state) {
        if (mState != state) {
            return;
        }
        switch (mState) {
            case STATE_WAIT_FOR_SET_SYSTEM_AUDIO_MODE:
                handleSendSystemAudioModeRequestTimeout();
                return;
            case STATE_WAIT_FOR_REPORT_AUDIO_STATUS:
                handleSendGiveAudioStatusFailure();
                return;
        }
    }
}
