/*
 * 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.systemui.doze;

import android.annotation.MainThread;
import android.hardware.display.AmbientDisplayConfiguration;
import android.os.Trace;
import android.os.UserHandle;
import android.util.Log;
import android.view.Display;

import com.android.internal.util.Preconditions;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.keyguard.WakefulnessLifecycle.Wakefulness;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.util.Assert;
import com.android.systemui.util.wakelock.WakeLock;

import java.io.PrintWriter;
import java.util.ArrayList;

/**
 * Orchestrates all things doze.
 *
 * DozeMachine implements a state machine that orchestrates how the UI and triggers work and
 * interfaces with the power and screen states.
 *
 * During state transitions and in certain states, DozeMachine holds a wake lock.
 */
public class DozeMachine {

    static final String TAG = "DozeMachine";
    static final boolean DEBUG = DozeService.DEBUG;
    private static final String REASON_CHANGE_STATE = "DozeMachine#requestState";
    private static final String REASON_HELD_FOR_STATE = "DozeMachine#heldForState";

    public enum State {
        /** Default state. Transition to INITIALIZED to get Doze going. */
        UNINITIALIZED,
        /** Doze components are set up. Followed by transition to DOZE or DOZE_AOD. */
        INITIALIZED,
        /** Regular doze. Device is asleep and listening for pulse triggers. */
        DOZE,
        /** Always-on doze. Device is asleep, showing UI and listening for pulse triggers. */
        DOZE_AOD,
        /** Pulse has been requested. Device is awake and preparing UI */
        DOZE_REQUEST_PULSE,
        /** Pulse is showing. Device is awake and showing UI. */
        DOZE_PULSING,
        /** Pulse is showing with bright wallpaper. Device is awake and showing UI. */
        DOZE_PULSING_BRIGHT,
        /** Pulse is done showing. Followed by transition to DOZE or DOZE_AOD. */
        DOZE_PULSE_DONE,
        /** Doze is done. DozeService is finished. */
        FINISH,
        /** AOD, but the display is temporarily off. */
        DOZE_AOD_PAUSED,
        /** AOD, prox is near, transitions to DOZE_AOD_PAUSED after a timeout. */
        DOZE_AOD_PAUSING;

        boolean canPulse() {
            switch (this) {
                case DOZE:
                case DOZE_AOD:
                case DOZE_AOD_PAUSED:
                case DOZE_AOD_PAUSING:
                    return true;
                default:
                    return false;
            }
        }

        boolean staysAwake() {
            switch (this) {
                case DOZE_REQUEST_PULSE:
                case DOZE_PULSING:
                case DOZE_PULSING_BRIGHT:
                    return true;
                default:
                    return false;
            }
        }

        int screenState(DozeParameters parameters) {
            switch (this) {
                case UNINITIALIZED:
                case INITIALIZED:
                case DOZE_REQUEST_PULSE:
                    return parameters.shouldControlScreenOff() ? Display.STATE_ON
                            : Display.STATE_OFF;
                case DOZE_AOD_PAUSED:
                case DOZE:
                    return Display.STATE_OFF;
                case DOZE_PULSING:
                case DOZE_PULSING_BRIGHT:
                    return Display.STATE_ON;
                case DOZE_AOD:
                case DOZE_AOD_PAUSING:
                    return Display.STATE_DOZE_SUSPEND;
                default:
                    return Display.STATE_UNKNOWN;
            }
        }
    }

    private final Service mDozeService;
    private final WakeLock mWakeLock;
    private final AmbientDisplayConfiguration mConfig;
    private final WakefulnessLifecycle mWakefulnessLifecycle;
    private final BatteryController mBatteryController;
    private Part[] mParts;

    private final ArrayList<State> mQueuedRequests = new ArrayList<>();
    private State mState = State.UNINITIALIZED;
    private int mPulseReason;
    private boolean mWakeLockHeldForCurrentState = false;

    public DozeMachine(Service service, AmbientDisplayConfiguration config,
            WakeLock wakeLock, WakefulnessLifecycle wakefulnessLifecycle,
            BatteryController batteryController) {
        mDozeService = service;
        mConfig = config;
        mWakefulnessLifecycle = wakefulnessLifecycle;
        mWakeLock = wakeLock;
        mBatteryController = batteryController;
    }

    /** Initializes the set of {@link Part}s. Must be called exactly once after construction. */
    public void setParts(Part[] parts) {
        Preconditions.checkState(mParts == null);
        mParts = parts;
    }

    /**
     * Requests transitioning to {@code requestedState}.
     *
     * This can be called during a state transition, in which case it will be queued until all
     * queued state transitions are done.
     *
     * A wake lock is held while the transition is happening.
     *
     * Note that {@link #transitionPolicy} can modify what state will be transitioned to.
     */
    @MainThread
    public void requestState(State requestedState) {
        Preconditions.checkArgument(requestedState != State.DOZE_REQUEST_PULSE);
        requestState(requestedState, DozeLog.PULSE_REASON_NONE);
    }

    @MainThread
    public void requestPulse(int pulseReason) {
        // Must not be called during a transition. There's no inherent problem with that,
        // but there's currently no need to execute from a transition and it simplifies the
        // code to not have to worry about keeping the pulseReason in mQueuedRequests.
        Preconditions.checkState(!isExecutingTransition());
        requestState(State.DOZE_REQUEST_PULSE, pulseReason);
    }

    private void requestState(State requestedState, int pulseReason) {
        Assert.isMainThread();
        if (DEBUG) {
            Log.i(TAG, "request: current=" + mState + " req=" + requestedState,
                    new Throwable("here"));
        }

        boolean runNow = !isExecutingTransition();
        mQueuedRequests.add(requestedState);
        if (runNow) {
            mWakeLock.acquire(REASON_CHANGE_STATE);
            for (int i = 0; i < mQueuedRequests.size(); i++) {
                // Transitions in Parts can call back into requestState, which will
                // cause mQueuedRequests to grow.
                transitionTo(mQueuedRequests.get(i), pulseReason);
            }
            mQueuedRequests.clear();
            mWakeLock.release(REASON_CHANGE_STATE);
        }
    }

    /**
     * @return the current state.
     *
     * This must not be called during a transition.
     */
    @MainThread
    public State getState() {
        Assert.isMainThread();
        if (isExecutingTransition()) {
            throw new IllegalStateException("Cannot get state because there were pending "
                    + "transitions: " + mQueuedRequests.toString());
        }
        return mState;
    }

    /**
     * @return the current pulse reason.
     *
     * This is only valid if the machine is currently in one of the pulse states.
     */
    @MainThread
    public int getPulseReason() {
        Assert.isMainThread();
        Preconditions.checkState(mState == State.DOZE_REQUEST_PULSE
                || mState == State.DOZE_PULSING
                || mState == State.DOZE_PULSING_BRIGHT
                || mState == State.DOZE_PULSE_DONE, "must be in pulsing state, but is " + mState);
        return mPulseReason;
    }

    /** Requests the PowerManager to wake up now. */
    public void wakeUp() {
        mDozeService.requestWakeUp();
    }

    public boolean isExecutingTransition() {
        return !mQueuedRequests.isEmpty();
    }

    private void transitionTo(State requestedState, int pulseReason) {
        State newState = transitionPolicy(requestedState);

        if (DEBUG) {
            Log.i(TAG, "transition: old=" + mState + " req=" + requestedState + " new=" + newState);
        }

        if (newState == mState) {
            return;
        }

        validateTransition(newState);

        State oldState = mState;
        mState = newState;

        DozeLog.traceState(newState);
        Trace.traceCounter(Trace.TRACE_TAG_APP, "doze_machine_state", newState.ordinal());

        updatePulseReason(newState, oldState, pulseReason);
        performTransitionOnComponents(oldState, newState);
        updateWakeLockState(newState);

        resolveIntermediateState(newState);
    }

    private void updatePulseReason(State newState, State oldState, int pulseReason) {
        if (newState == State.DOZE_REQUEST_PULSE) {
            mPulseReason = pulseReason;
        } else if (oldState == State.DOZE_PULSE_DONE) {
            mPulseReason = DozeLog.PULSE_REASON_NONE;
        }
    }

    private void performTransitionOnComponents(State oldState, State newState) {
        for (Part p : mParts) {
            p.transitionTo(oldState, newState);
        }

        switch (newState) {
            case FINISH:
                mDozeService.finish();
                break;
            default:
        }
    }

    private void validateTransition(State newState) {
        try {
            switch (mState) {
                case FINISH:
                    Preconditions.checkState(newState == State.FINISH);
                    break;
                case UNINITIALIZED:
                    Preconditions.checkState(newState == State.INITIALIZED);
                    break;
            }
            switch (newState) {
                case UNINITIALIZED:
                    throw new IllegalArgumentException("can't transition to UNINITIALIZED");
                case INITIALIZED:
                    Preconditions.checkState(mState == State.UNINITIALIZED);
                    break;
                case DOZE_PULSING:
                    Preconditions.checkState(mState == State.DOZE_REQUEST_PULSE);
                    break;
                case DOZE_PULSE_DONE:
                    Preconditions.checkState(
                            mState == State.DOZE_REQUEST_PULSE || mState == State.DOZE_PULSING
                                    || mState == State.DOZE_PULSING_BRIGHT);
                    break;
                default:
                    break;
            }
        } catch (RuntimeException e) {
            throw new IllegalStateException("Illegal Transition: " + mState + " -> " + newState, e);
        }
    }

    private State transitionPolicy(State requestedState) {
        if (mState == State.FINISH) {
            return State.FINISH;
        }
        if ((mState == State.DOZE_AOD_PAUSED || mState == State.DOZE_AOD_PAUSING
                || mState == State.DOZE_AOD || mState == State.DOZE)
                && requestedState == State.DOZE_PULSE_DONE) {
            Log.i(TAG, "Dropping pulse done because current state is already done: " + mState);
            return mState;
        }
        if (requestedState == State.DOZE_AOD && mBatteryController.isAodPowerSave()) {
            return State.DOZE;
        }
        if (requestedState == State.DOZE_REQUEST_PULSE && !mState.canPulse()) {
            Log.i(TAG, "Dropping pulse request because current state can't pulse: " + mState);
            return mState;
        }
        return requestedState;
    }

    private void updateWakeLockState(State newState) {
        boolean staysAwake = newState.staysAwake();
        if (mWakeLockHeldForCurrentState && !staysAwake) {
            mWakeLock.release(REASON_HELD_FOR_STATE);
            mWakeLockHeldForCurrentState = false;
        } else if (!mWakeLockHeldForCurrentState && staysAwake) {
            mWakeLock.acquire(REASON_HELD_FOR_STATE);
            mWakeLockHeldForCurrentState = true;
        }
    }

    private void resolveIntermediateState(State state) {
        switch (state) {
            case INITIALIZED:
            case DOZE_PULSE_DONE:
                final State nextState;
                @Wakefulness int wakefulness = mWakefulnessLifecycle.getWakefulness();
                if (wakefulness == WakefulnessLifecycle.WAKEFULNESS_AWAKE
                        || wakefulness == WakefulnessLifecycle.WAKEFULNESS_WAKING) {
                    nextState = State.FINISH;
                } else if (mConfig.alwaysOnEnabled(UserHandle.USER_CURRENT)) {
                    nextState = State.DOZE_AOD;
                } else {
                    nextState = State.DOZE;
                }

                transitionTo(nextState, DozeLog.PULSE_REASON_NONE);
                break;
            default:
                break;
        }
    }

    /** Dumps the current state */
    public void dump(PrintWriter pw) {
        pw.print(" state="); pw.println(mState);
        pw.print(" wakeLockHeldForCurrentState="); pw.println(mWakeLockHeldForCurrentState);
        pw.print(" wakeLock="); pw.println(mWakeLock);
        pw.println("Parts:");
        for (Part p : mParts) {
            p.dump(pw);
        }
    }

    /** A part of the DozeMachine that needs to be notified about state changes. */
    public interface Part {
        /**
         * Transition from {@code oldState} to {@code newState}.
         *
         * This method is guaranteed to only be called while a wake lock is held.
         */
        void transitionTo(State oldState, State newState);

        /** Dump current state. For debugging only. */
        default void dump(PrintWriter pw) {}
    }

    /** A wrapper interface for {@link android.service.dreams.DreamService} */
    public interface Service {
        /** Finish dreaming. */
        void finish();

        /** Request a display state. See {@link android.view.Display#STATE_DOZE}. */
        void setDozeScreenState(int state);

        /** Request waking up. */
        void requestWakeUp();

        /** Set screen brightness */
        void setDozeScreenBrightness(int brightness);

        class Delegate implements Service {
            private final Service mDelegate;

            public Delegate(Service delegate) {
                mDelegate = delegate;
            }

            @Override
            public void finish() {
                mDelegate.finish();
            }

            @Override
            public void setDozeScreenState(int state) {
                mDelegate.setDozeScreenState(state);
            }

            @Override
            public void requestWakeUp() {
                mDelegate.requestWakeUp();
            }

            @Override
            public void setDozeScreenBrightness(int brightness) {
                mDelegate.setDozeScreenBrightness(brightness);
            }
        }
    }
}
