/*
 * Copyright 2016 Square Inc.
 *
 * 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 flow.sample.orientation;

import android.app.Activity;
import android.support.annotation.NonNull;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import flowless.Traversal;
import flowless.TraversalCallback;
import flowless.preset.SingleRootDispatcher;

import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;

public class OrientationSampleDispatcher
        extends SingleRootDispatcher {
    /**
     * Using a static for this is a fragile hack for demo purposes. In
     * real life you'd want something hanging off of a custom application
     * class--perhaps a Mortar activity scope.
     */
    private static TraversalCallback hangingCallback;

    public static void finishPendingTraversal() {
        if(hangingCallback != null) {
            // The previous dispatcher was unable to finish its traversal because it
            // required a configuration change. Let flow know that we're awake again
            // in our new orientation and that traversal is done.

            TraversalCallback ref = hangingCallback;
            hangingCallback = null;
            ref.onTraversalCompleted(); // TODO: check if this contradicts with Flow.executePendingTraversal() on `onDestroy()`
        }
    }

    protected final Activity activity;

    public OrientationSampleDispatcher(Activity activity) {
        this.activity = activity;
    }

    @Override
    public void dispatch(@NonNull Traversal traversal, @NonNull TraversalCallback callback) {
        Log.d("BasicDispatcher", "dispatching " + traversal);

        final OrientationSampleScreen destScreen = traversal.destination.top();
        final boolean incomingNeedsLock = destScreen.requiresLandscape();
        final boolean waitForOrientationChange = incomingNeedsLock && requestLandscapeLock();

        if(waitForOrientationChange) {
            // There is about to be an orientation change, which means there will
            // soon be a new activity and a new dispatcher. Let them complete
            // this traversal, so that we don't try to show a landscape-only screen
            // in portrait.
            hangingCallback = callback;
        } else {
            ViewGroup frame = (ViewGroup) activity.findViewById(R.id.basic_activity_frame);
            View destView = LayoutInflater.from(traversal.createContext(destScreen, activity)) //
                    .inflate(destScreen.getLayoutId(), frame, false);

            frame.removeAllViews();
            frame.addView(destView);

            if(!incomingNeedsLock) {
                requestUnlock();
            }
            callback.onTraversalCompleted();
        }
    }

    /**
     * Returns true if we've requested a lock and are expecting an orientation change
     * as a result.
     */
    boolean requestLandscapeLock() {
        int requestedOrientation = activity.getRequestedOrientation();

        if(requestedOrientation == SCREEN_ORIENTATION_SENSOR_LANDSCAPE) {
            // We're already locked.
            return false;
        }

        activity.setRequestedOrientation(SCREEN_ORIENTATION_SENSOR_LANDSCAPE);

        // We've requested a lock, but there will only be an orientation change
        // if we're not already landscape.
        return isPortrait();
    }

    void requestUnlock() {
        activity.setRequestedOrientation(SCREEN_ORIENTATION_UNSPECIFIED);
    }

    boolean isPortrait() {
        return activity.getResources().getBoolean(R.bool.is_portrait);
    }
}
