// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package org.chromium.android_webview;

import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.webkit.ConsoleMessage;
import android.webkit.ValueCallback;

import org.chromium.base.ThreadUtils;
import org.chromium.content.browser.ContentViewCore;

/**
 * Adapts the AwWebContentsDelegate interface to the AwContentsClient interface.
 * This class also serves a secondary function of routing certain callbacks from the content layer
 * to specific listener interfaces.
 */
class AwWebContentsDelegateAdapter extends AwWebContentsDelegate {
    private static final String TAG = "AwWebContentsDelegateAdapter";

    final AwContentsClient mContentsClient;
    final View mContainerView;

    public AwWebContentsDelegateAdapter(AwContentsClient contentsClient,
            View containerView) {
        mContentsClient = contentsClient;
        mContainerView = containerView;
    }

    @Override
    public void onLoadProgressChanged(int progress) {
        mContentsClient.onProgressChanged(progress);
    }

    @Override
    public void handleKeyboardEvent(KeyEvent event) {
        if (event.getAction() == KeyEvent.ACTION_DOWN) {
            int direction;
            switch (event.getKeyCode()) {
                case KeyEvent.KEYCODE_DPAD_DOWN:
                    direction = View.FOCUS_DOWN;
                    break;
                case KeyEvent.KEYCODE_DPAD_UP:
                    direction = View.FOCUS_UP;
                    break;
                case KeyEvent.KEYCODE_DPAD_LEFT:
                    direction = View.FOCUS_LEFT;
                    break;
                case KeyEvent.KEYCODE_DPAD_RIGHT:
                    direction = View.FOCUS_RIGHT;
                    break;
                default:
                    direction = 0;
                    break;
            }
            if (direction != 0 && tryToMoveFocus(direction)) return;
        }
        mContentsClient.onUnhandledKeyEvent(event);
    }

    @Override
    public boolean takeFocus(boolean reverse) {
        int direction =
            (reverse == (mContainerView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL)) ?
            View.FOCUS_RIGHT : View.FOCUS_LEFT;
        if (tryToMoveFocus(direction)) return true;
        direction = reverse ? View.FOCUS_UP : View.FOCUS_DOWN;
        return tryToMoveFocus(direction);
    }

    private boolean tryToMoveFocus(int direction) {
        View focus = mContainerView.focusSearch(direction);
        return focus != null && focus != mContainerView && focus.requestFocus();
    }

    @Override
    public boolean addMessageToConsole(int level, String message, int lineNumber,
            String sourceId) {
        ConsoleMessage.MessageLevel messageLevel = ConsoleMessage.MessageLevel.DEBUG;
        switch(level) {
            case LOG_LEVEL_TIP:
                messageLevel = ConsoleMessage.MessageLevel.TIP;
                break;
            case LOG_LEVEL_LOG:
                messageLevel = ConsoleMessage.MessageLevel.LOG;
                break;
            case LOG_LEVEL_WARNING:
                messageLevel = ConsoleMessage.MessageLevel.WARNING;
                break;
            case LOG_LEVEL_ERROR:
                messageLevel = ConsoleMessage.MessageLevel.ERROR;
                break;
            default:
                Log.w(TAG, "Unknown message level, defaulting to DEBUG");
                break;
        }

        return mContentsClient.onConsoleMessage(
                new ConsoleMessage(message, sourceId, lineNumber, messageLevel));
    }

    @Override
    public void onUpdateUrl(String url) {
        // TODO: implement
    }

    @Override
    public void openNewTab(String url, String extraHeaders, byte[] postData, int disposition) {
        // This is only called in chrome layers.
        assert false;
    }

    @Override
    public void closeContents() {
        mContentsClient.onCloseWindow();
    }

    @Override
    public void showRepostFormWarningDialog(final ContentViewCore contentViewCore) {
        // TODO(mkosiba) We should be using something akin to the JsResultReceiver as the
        // callback parameter (instead of ContentViewCore) and implement a way of converting
        // that to a pair of messages.
        final int MSG_CONTINUE_PENDING_RELOAD = 1;
        final int MSG_CANCEL_PENDING_RELOAD = 2;

        // TODO(sgurun) Remember the URL to cancel the reload behavior
        // if it is different than the most recent NavigationController entry.
        final Handler handler = new Handler(ThreadUtils.getUiThreadLooper()) {
            @Override
            public void handleMessage(Message msg) {
                switch(msg.what) {
                    case MSG_CONTINUE_PENDING_RELOAD: {
                        contentViewCore.continuePendingReload();
                        break;
                    }
                    case MSG_CANCEL_PENDING_RELOAD: {
                        contentViewCore.cancelPendingReload();
                        break;
                    }
                    default:
                        throw new IllegalStateException(
                                "WebContentsDelegateAdapter: unhandled message " + msg.what);
                }
            }
        };

        Message resend = handler.obtainMessage(MSG_CONTINUE_PENDING_RELOAD);
        Message dontResend = handler.obtainMessage(MSG_CANCEL_PENDING_RELOAD);
        mContentsClient.onFormResubmission(dontResend, resend);
    }

    @Override
    public void runFileChooser(final int processId, final int renderId, final int mode_flags,
            String acceptTypes, String title, String defaultFilename, boolean capture) {
        AwContentsClient.FileChooserParams params = new AwContentsClient.FileChooserParams();
        params.mode = mode_flags;
        params.acceptTypes = acceptTypes;
        params.title = title;
        params.defaultFilename = defaultFilename;
        params.capture = capture;

        mContentsClient.showFileChooser(new ValueCallback<String[]>() {
            boolean completed = false;
            @Override
            public void onReceiveValue(String[] results) {
                if (completed) {
                    throw new IllegalStateException("Duplicate showFileChooser result");
                }
                completed = true;
                nativeFilesSelectedInChooser(processId, renderId, mode_flags, results);
            }
        }, params);
    }

    @Override
    public boolean addNewContents(boolean isDialog, boolean isUserGesture) {
        return mContentsClient.onCreateWindow(isDialog, isUserGesture);
    }

    @Override
    public void activateContents() {
        mContentsClient.onRequestFocus();
    }
}
