/*
 * 版权所有 (c) 2010-2011，The MiCode Open Source Community (www.micode.net)
 *
 * 本软件根据 Apache 许可证 2.0 版（"许可证"）发布；
 * 除非符合许可证，否则不得使用此文件。
 * 您可以在以下网址获取许可证副本：
 *
 *        http://www.apache.org/licenses/LICENSE-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;

/**
 * 自定义笔记编辑文本组件（继承自EditText）
 * 功能：
 * 1. 处理文本输入时的特殊按键事件（删除、换行）
 * 2. 支持文本变化监听，通知上层组件更新
 * 3. 识别文本中的链接（电话、网址、邮箱），并提供上下文菜单操作
 * 4. 优化触摸事件处理，确保光标位置准确
 */
public class NoteEditText extends EditText {
    private static final String TAG = "NoteEditText";
    private int mIndex;                          // 当前编辑文本在列表中的索引
    private int mSelectionStartBeforeDelete;     // 删除操作前的光标位置

    // 支持的链接协议及对应的菜单文本资源
    private static final String SCHEME_TEL = "tel:";
    private static final String SCHEME_HTTP = "http:";
    private static final String SCHEME_EMAIL = "mailto:";
    private static final Map<String, Integer> sSchemaActionResMap = new HashMap<String, Integer>() {{
        put(SCHEME_TEL, R.string.note_link_tel);    // 电话链接
        put(SCHEME_HTTP, R.string.note_link_web);    // 网页链接
        put(SCHEME_EMAIL, R.string.note_link_email);  // 邮箱链接
    }};

    // 文本变化监听器接口
    public interface OnTextViewChangeListener {
        /**
         * 当按下删除键且文本为空时触发（删除当前编辑项）
         * @param index 当前编辑项索引
         * @param text  当前文本内容
         */
        void onEditTextDelete(int index, String text);

        /**
         * 当按下回车键时触发（添加新编辑项）
         * @param index 当前编辑项索引+1
         * @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
    }

    /**
     * 设置编辑项索引（用于标识在列表中的位置）
     * @param index 索引值
     */
    public void setIndex(int index) {
        mIndex = index;
    }

    /**
     * 设置文本变化监听器
     * @param listener 监听器实例
     */
    public void setOnTextViewChangeListener(OnTextViewChangeListener listener) {
        mOnTextViewChangeListener = listener;
    }

    // 构造方法（支持XML布局初始化）
    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);
    }

    /**
     * 触摸事件处理：确保点击位置正确设置光标
     * @param event 触摸事件
     * @return 事件处理结果
     */
    @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);
    }

    /**
     * 按键按下事件处理
     * @param keyCode 按键码
     * @param event 按键事件
     * @return 事件处理结果
     */
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        switch (keyCode) {
            case KeyEvent.KEYCODE_ENTER:
                // 回车键由onKeyUp处理，此处返回false以便后续处理
                if (mOnTextViewChangeListener != null) return false;
                break;
            case KeyEvent.KEYCODE_DEL:
                // 记录删除前的光标位置
                mSelectionStartBeforeDelete = getSelectionStart();
                break;
        }
        return super.onKeyDown(keyCode, event);
    }

    /**
     * 按键释放事件处理
     * @param keyCode 按键码
     * @param event 按键事件
     * @return 事件处理结果
     */
    @Override
    public boolean onKeyUp(int keyCode, KeyEvent event) {
        switch (keyCode) {
            case KeyEvent.KEYCODE_DEL:
                // 删除键处理：文本为空且光标在开头时，通知删除当前编辑项
                if (mOnTextViewChangeListener != null) {
                    if (mSelectionStartBeforeDelete == 0 && getText().length() == 0 && mIndex != 0) {
                        mOnTextViewChangeListener.onEditTextDelete(mIndex, getText().toString());
                        return true; // 消费事件，阻止默认删除行为
                    }
                }
                break;
            case KeyEvent.KEYCODE_ENTER:
                // 回车键处理：分割文本并通知添加新编辑项
                if (mOnTextViewChangeListener != null) {
                    int selectionStart = getSelectionStart();
                    String newText = getText().subSequence(selectionStart, length()).toString();
                    setText(getText().subSequence(0, selectionStart)); // 保留当前行文本
                    mOnTextViewChangeListener.onEditTextEnter(mIndex + 1, newText); // 通知添加新项
                    return true; // 消费事件，阻止默认换行行为
                }
                break;
        }
        return super.onKeyUp(keyCode, event);
    }

    /**
     * 焦点变化处理：通知文本状态变化
     * @param focused 是否获得焦点
     * @param direction 焦点移动方向
     * @param previouslyFocusedRect 前一个焦点位置
     */
    @Override
    protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
        if (mOnTextViewChangeListener != null) {
            boolean hasText = !TextUtils.isEmpty(getText());
            mOnTextViewChangeListener.onTextChange(mIndex, hasText); // 通知文本是否有内容
        }
        super.onFocusChanged(focused, direction, previouslyFocusedRect);
    }

    /**
     * 创建上下文菜单：处理链接点击
     * @param menu 上下文菜单
     */
    @Override
    protected void onCreateContextMenu(ContextMenu menu) {
        super.onCreateContextMenu(menu);
        Spanned text = (Spanned) getText();
        int selStart = getSelectionStart();
        int selEnd = getSelectionEnd();
        int min = Math.min(selStart, selEnd);
        int max = Math.max(selStart, selEnd);

        // 获取选中区域内的URLSpan
        URLSpan[] urls = text.getSpans(min, max, URLSpan.class);
        if (urls.length == 1) {
            String url = urls[0].getURL();
            int menuTextResId = R.string.note_link_other; // 默认菜单文本

            // 根据链接协议设置对应的菜单文本
            for (Map.Entry<String, Integer> entry : sSchemaActionResMap.entrySet()) {
                if (url.startsWith(entry.getKey())) {
                    menuTextResId = entry.getValue();
                    break;
                }
            }

            // 添加菜单选项：点击时触发链接点击事件
            menu.add(0, 0, 0, menuTextResId).setOnMenuItemClickListener(item -> {
                urls[0].onClick(NoteEditText.this); // 调用URLSpan的点击处理
                return true;
            });
        }
    }
}