/*
 * 版权所有 (c) 2010-2011，MiCode 开源社区 (www.micode.net)
 * 根据 Apache 许可证 2.0 版本（"许可证"）授权；
 * 除非符合许可证的规定，否则不得使用本文件。
 * 您可以从以下网址获取许可证副本：
 * http://www.apache.org/licenses/LICENSE-2.0
 * 除非适用法律要求或书面同意，本软件按"原样"分发，
 * 没有任何明示或暗示的保证或条件。
 * 详见许可证中规定的权限和限制。
 * （注：这是一份标准的Apache许可证2.0版本的开源声明）
 */

// 定义当前类的包路径，指明该类属于net.micode.notes.ui 包
package net.micode.notes.ui;

/* 导入Android基础类 */
// Context类提供应用环境信息访问接口
import android.content.Context;
// Rect类表示一个矩形区域，用于处理视图边界
import android.graphics.Rect;
// Layout类用于管理文本布局和测量
import android.text.Layout;
// Selection类用于处理文本选择操作
import android.text.Selection;
// Spanned接口表示带有样式的文本
import android.text.Spanned;
// TextUtils类提供文本处理工具方法
import android.text.TextUtils;
// URLSpan类用于标记文本中的超链接
import android.text.style.URLSpan;
// AttributeSet接口表示XML属性集合
import android.util.AttributeSet;
// Log类提供日志记录功能
import android.util.Log;

/* 导入Android视图相关类 */
// ContextMenu类表示上下文菜单
import android.view.ContextMenu;
// KeyEvent类表示按键事件
import android.view.KeyEvent;
// MenuItem类表示菜单项
import android.view.MenuItem;
// OnMenuItemClickListener接口定义菜单项点击回调
import android.view.MenuItem.OnMenuItemClickListener;
// MotionEvent类表示触摸事件
import android.view.MotionEvent;
// EditText类是基础文本编辑框
import android.widget.EditText;

/* 导入项目资源 */
// 导入项目R类，用于访问资源ID
import net.micode.notes.R;

/* 导入Java集合类 */
// HashMap类实现哈希表结构的Map接口
import java.util.HashMap;
// Map接口表示键值对映射集合
import java.util.Map;

// 继承自AppCompatEditText的支持兼容的编辑文本框
public class NoteEditText extends androidx.appcompat.widget.AppCompatEditText  {
    private static final String TAG = "NoteEditText";  // 日志标签
    private int mIndex;  // 当前编辑框在列表中的索引
    private int mSelectionStartBeforeDelete;  // 删除操作前的选择开始位置

    // 定义支持的URL协议常量
    private static final String SCHEME_TEL = "tel:";
    private static final String SCHEME_HTTP = "http:";
    private static final String SCHEME_EMAIL = "mailto:";

    // 创建协议到资源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 {
        /**
         * 当删除键按下且文本为空时删除当前编辑框
         * @param index 当前编辑框索引
         * @param text 当前编辑框文本内容
         */
        void onEditTextDelete(int index, String text);

        /**
         * 当回车键按下时在当前编辑框后添加新编辑框
         * @param index 新编辑框的索引
         * @param text 新编辑框的初始文本
         */
        void onEditTextEnter(int index, String text);

        /**
         * 当文本变化时隐藏或显示选项
         * @param index 当前编辑框索引
         * @param hasText 是否有文本内容
         */
        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);
        // TODO: 待实现的构造函数
    }

    // 触摸事件处理
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // 按下事件处理
        if (event.getAction()  == 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);  // 设置文本选择位置
        }

        return super.onTouchEvent(event);   // 调用父类处理方法
    }

    // 按键按下事件处理
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        switch (keyCode) {
            case KeyEvent.KEYCODE_ENTER:  // 回车键
                if (mOnTextViewChangeListener != null) {
                    return false;  // 交给onKeyUp处理
                }
                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, "OnTextViewChangeListener was not seted");
                }
                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, "OnTextViewChangeListener was not seted");
                }
                break;
            default:
                break;
        }
        return super.onKeyUp(keyCode,  event);  // 调用父类处理方法
    }

    // 焦点变化处理
    @Override
    protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
        // 通知监听器文本变化状态
        if (mOnTextViewChangeListener != null) {
            mOnTextViewChangeListener.onTextChange(mIndex,  focused || !TextUtils.isEmpty(getText()));
        }
        super.onFocusChanged(focused,  direction, previouslyFocusedRect);  // 调用父类方法
    }

    // 创建上下文菜单
    @Override
    protected void onCreateContextMenu(ContextMenu menu) {
        if (getText() != null) {
            // 获取当前选择的起止位置
            int selStart = getSelectionStart();
            int selEnd = getSelectionEnd();

            // 计算最小和最大位置
            int min = Math.min(selStart,  selEnd);
            int max = Math.max(selStart,  selEnd);

            // 获取选择范围内的URLSpan对象
            final URLSpan[] urls = ((Spanned) getText()).getSpans(min, max, URLSpan.class);
            if (urls.length  == 1) {  // 如果选中了一个URL
                int defaultResId = 0;
                // 根据URL协议类型获取对应的资源ID
                for(String schema: sSchemaActionResMap.keySet())  {
                    if(urls[0].getURL().contains(schema)) {
                        defaultResId = sSchemaActionResMap.get(schema);
                        break;
                    }
                }

                // 如果没有匹配的协议，使用默认资源
                if (defaultResId == 0) {
                    defaultResId = R.string.note_link_other;
                }

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