/*
 * Copyright (C) 2022 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.google.android.test.handwritingime;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.WindowMetrics;
import android.view.inputmethod.CursorAnchorInfo;

class InkView extends View {
    private static final long FINISH_TIMEOUT = 1500;
    private final HandwritingIme.HandwritingFinisher mHwCanceller;
    private final HandwritingIme.StylusConsumer mConsumer;
    private final Paint mPaint;
    private final Path mPath;
    private float mX, mY;
    private static final float STYLUS_MOVE_TOLERANCE = 1;
    private Runnable mFinishRunnable;

    private CursorAnchorInfo mCursorAnchorInfo;
    private int mBoundsInfoMode;

    InkView(Context context, HandwritingIme.HandwritingFinisher hwController,
            HandwritingIme.StylusConsumer consumer) {
        super(context);
        mHwCanceller = hwController;
        mConsumer = consumer;

        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setDither(true);
        mPaint.setColor(Color.GREEN);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeJoin(Paint.Join.ROUND);
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        mPaint.setStrokeWidth(14);

        mPath = new Path();

        WindowManager wm = context.getSystemService(WindowManager.class);
        WindowMetrics metrics =  wm.getCurrentWindowMetrics();
        setLayoutParams(new ViewGroup.LayoutParams(
                metrics.getBounds().width(), metrics.getBounds().height()));
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        canvas.drawPath(mPath, mPaint);
        canvas.drawARGB(20, 255, 50, 50);
        BoundsInfoDrawHelper.draw(canvas, this, mBoundsInfoMode, mCursorAnchorInfo);
    }

    private void stylusStart(float x, float y) {
        mPath.moveTo(x, y);
        mX = x;
        mY = y;
    }

    private void stylusMove(float x, float y) {
        float dx = Math.abs(x - mX);
        float dy = Math.abs(y - mY);
        if (mPath.isEmpty()) {
            stylusStart(x, y);
        }
        if (dx >= STYLUS_MOVE_TOLERANCE || dy >= STYLUS_MOVE_TOLERANCE) {
            mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
            mX = x;
            mY = y;
        }
    }

    private void stylusFinish() {
        mPath.lineTo(mX, mY);
        // TODO: support offscreen? e.g. mCanvas.drawPath(mPath, mPaint);
        mPath.reset();
        mX = 0;
        mY = 0;

    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getToolType(0) == MotionEvent.TOOL_TYPE_STYLUS) {
            mConsumer.onStylusEvent(event);
            android.util.Log.w(HandwritingIme.TAG, "INK touch onStylusEvent " + event);
            float x = event.getX();
            float y = event.getY();
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    cancelTimer();
                    stylusStart(x, y);
                    invalidate();
                    break;
                case MotionEvent.ACTION_MOVE:
                    stylusMove(x, y);
                    invalidate();
                    break;

                case MotionEvent.ACTION_UP:
                    scheduleTimer();
                    break;

            }
            return true;
        }
        return false;
    }

    private void cancelTimer() {
        if (mFinishRunnable != null) {
            if (getHandler() != null) {
                getHandler().removeCallbacks(mFinishRunnable);
            }
            mFinishRunnable = null;
        }
        if (getHandler() != null) {
            getHandler().removeCallbacksAndMessages(null);
        }
    }

    private void scheduleTimer() {
        cancelTimer();
        if (getHandler() != null) {
            postDelayed(getFinishRunnable(), FINISH_TIMEOUT);
        }
    }

    private Runnable getFinishRunnable() {
        mFinishRunnable = () -> {
            android.util.Log.e(HandwritingIme.TAG, "Hw view timer finishHandwriting ");
            mHwCanceller.finish();
            stylusFinish();
            mPath.reset();
            invalidate();
        };

        return mFinishRunnable;
    }

    void setCursorAnchorInfo(CursorAnchorInfo cursorAnchorInfo) {
        mCursorAnchorInfo = cursorAnchorInfo;
        invalidate();
    }

    void setBoundsInfoMode(int boundsInfoMode) {
        if (boundsInfoMode != mBoundsInfoMode) {
            invalidate();
        }
        mBoundsInfoMode = boundsInfoMode;
    }
}
