/*
 * 版权声明： MiCode 开源社区 版权所有
 * 本文件遵循 Apache License, Version 2.0 许可协议
 */

package net.micode.notes.ui;

import android.content.Context;
import android.graphics.Rect;
import android.text.Layout;
import android.text.Selection;
import android.text.Spanned;
import android.text.TextUtils;
import android.text.style.URLSpan;
import android.util.AttributeSet;
import android.util.Log;
import android.view.ContextMenu;
import android.view.KeyEvent;
import android.view.MenuItem;
import android.view.MenuItem.OnMenuItemClickListener;
import android.view.MotionEvent;
import android.widget.EditText;

import net.micode.notes.R;

import java.util.HashMap;
import java.util.Map;

// 定义 NoteEditText 类，继承自 EditText，用于笔记编辑文本框
public class NoteEditText extends EditText {
    private static final String TAG = "NoteEditText"; // 日志标签
    private int mIndex; // 当前编辑文本的索引
    private int mSelectionStartBeforeDelete; // 删除前的光标起始位置

    private static final String SCHEME_TEL = "tel:"; // 电话 URI scheme
    private static final String SCHEME_HTTP = "http:"; // HTTP URI scheme
    private static final String SCHEME_EMAIL = "mailto:"; // 邮件 URI scheme

    // 定义 URI scheme 和对应操作资源 ID 的映射关系
    private static final Map<String, Integer> sSchemaActionResMap = new HashMap<String, Integer>();
    static {
        sSchemaActionResMap.put(SCHEME_TEL, R.string.note_link_tel);
        sSchemaActionResMap.put(SCHEME_HTTP, R.string.note_link_web);
        sSchemaActionResMap.put(SCHEME_EMAIL, R.string.note_link_email);
    }

    /**
     * 由 NoteEditActivity 调用，用于删除或添加编辑文本
     */
    public interface OnTextViewChangeListener {
        /**
         * 当按下删除键且文本为空时，删除当前编辑文本
         */
        void onEditTextDelete(int index, String text);

        /**
         * 当按下回车键时，添加新的编辑文本
         */
        void onEditTextEnter(int index, String text);

        /**
         * 当文本变化时，隐藏或显示选项菜单项
         */
        void onTextChange(int index, boolean hasText);
    }

    private OnTextViewChangeListener mOnTextViewChangeListener; // 编辑文本变化监听器

    // 构造函数
    public NoteEditText(Context context) {
        super(context, null);
        mIndex = 0; // 默认索引为 0
    }

    // 设置编辑文本的索引
    public void setIndex(int index) {
        mIndex = index;
    }

    // 设置编辑文本变化监听器
    public void setOnTextViewChangeListener(OnTextViewChangeListener listener) {
        mOnTextViewChangeListener = listener;
    }

    // 构造函数
    public NoteEditText(Context context, AttributeSet attrs) {
        super(context, attrs, android.R.attr.editTextStyle);
    }

    // 构造函数
    public NoteEditText(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    // 处理触摸事件，用于设置文本选择
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                // 计算触摸位置相对于文本的偏移量
                int x = (int) event.getX();
                int y = (int) event.getY();
                x -= getTotalPaddingLeft();
                y -= getTotalPaddingTop();
                x += getScrollX();
                y += getScrollY();

                Layout layout = getLayout();
                int line = layout.getLineForVertical(y); // 获取垂直位置对应的行号
                int off = layout.getOffsetForHorizontal(line, x); // 获取水平位置对应的偏移量
                Selection.setSelection(getText(), off); // 设置文本选择
                break;
        }

        return super.onTouchEvent(event); // 调用父类的触摸事件处理方法
    }

    // 处理键盘按下事件
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        switch (keyCode) {
            case KeyEvent.KEYCODE_ENTER:
                // 如果设置了编辑文本变化监听器，则不允许处理回车键事件
                if (mOnTextViewChangeListener != null) {
                    return false;
                }
                break;
            case KeyEvent.KEYCODE_DEL:
                mSelectionStartBeforeDelete = getSelectionStart(); // 保存删除前的光标起始位置
                break;
            default:
                break;
        }
        return super.onKeyDown(keyCode, event); // 调用父类的键盘按下事件处理方法
    }

    // 处理键盘弹起事件
    @Override
    public boolean onKeyUp(int keyCode, KeyEvent event) {
        switch (keyCode) {
            case KeyEvent.KEYCODE_DEL:
                // 如果设置了编辑文本变化监听器，则处理删除事件
                if (mOnTextViewChangeListener != null) {
                    if (0 == mSelectionStartBeforeDelete && mIndex != 0) { // 如果光标在起始位置且不是第一个编辑文本
                        mOnTextViewChangeListener.onEditTextDelete(mIndex, getText().toString()); // 删除当前编辑文本
                        return true;
                    }
                } else {
                    Log.d(TAG, "未设置编辑文本变化监听器");
                }
                break;
            case KeyEvent.KEYCODE_ENTER:
                // 如果设置了编辑文本变化监听器，则处理回车键事件
                if (mOnTextViewChangeListener != null) {
                    int selectionStart = getSelectionStart(); // 获取光标起始位置
                    String text = getText().subSequence(selectionStart, length()).toString(); // 获取当前选择的文本
                    setText(getText().subSequence(0, selectionStart)); // 设置文本为选择位置之前的内容
                    mOnTextViewChangeListener.onEditTextEnter(mIndex + 1, text); // 添加新的编辑文本
                } else {
                    Log.d(TAG, "未设置编辑文本变化监听器");
                }
                break;
            default:
                break;
        }
        return super.onKeyUp(keyCode, event); // 调用父类的键盘弹起事件处理方法
    }

    // 处理焦点变化事件
    @Override
    protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
        // 如果设置了编辑文本变化监听器，则通知文本变化
        if (mOnTextViewChangeListener != null) {
            if (!focused && TextUtils.isEmpty(getText())) { // 如果失去焦点且文本为空
                mOnTextViewChangeListener.onTextChange(mIndex, false); // 通知文本为空
            } else {
                mOnTextViewChangeListener.onTextChange(mIndex, true); // 通知文本不为空
            }
        }
        super.onFocusChanged(focused, direction, previouslyFocusedRect); // 调用父类的焦点变化事件处理方法
    }

    // 创建上下文菜单
    @Override
    protected void onCreateContextMenu(ContextMenu menu) {
        // 如果文本是 Spanned 类型，则处理 URLSpan
        if (getText() instanceof Spanned) {
            int selStart = getSelectionStart();
            int selEnd = getSelectionEnd();

            int min = Math.min(selStart, selEnd);
            int max = Math.max(selStart, selEnd);

            final URLSpan[] urls = ((Spanned) getText()).getSpans(min, max, URLSpan.class); // 获取选中文本中的 URLSpan
            if (urls.length == 1) { // 如果只有一个 URLSpan
                int defaultResId = 0;
                // 遍历 URI scheme 和操作资源 ID 的映射关系，找到对应的资源 ID
                for (String schema : sSchemaActionResMap.keySet()) {
                    if (urls[0].getURL().indexOf(schema) >= 0) {
                        defaultResId = sSchemaActionResMap.get(schema);
                        break;
                    }
                }

                if (defaultResId == 0) { // 如果未找到对应的资源 ID，则使用默认资源 ID
                    defaultResId = R.string.note_link_other;
                }

                // 添加菜单项并设置点击监听器
                menu.add(0, 0, 0, defaultResId).setOnMenuItemClickListener(
                        new OnMenuItemClickListener() {
                            public boolean onMenuItemClick(MenuItem item) {
                                urls[0].onClick(NoteEditText.this); // 跳转到对应链接
                                return true;
                            }
                        });
            }
        }
        super.onCreateContextMenu(menu); // 调用父类的上下文菜单创建方法
    }
}