/*
 * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
 *
 * 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 net.micode.notes.ui;

// 引入相关的 Android 和 Java 库
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; // 用于处理文本中的 URL 链接
import android.util.AttributeSet; // 用于解析 XML 布局文件中的自定义属性
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; // Android 中的编辑文本控件

// 引入项目中的资源文件
import net.micode.notes.R; // 自定义的资源文件，可能是图片、字符串或布局

// 引入 HashMap 和 Map，用于存储一些键值对数据
import java.util.HashMap;
import java.util.Map;


public class NoteEditText extends EditText {
    // 定义日志标签，用于调试时输出日志
    private static final String TAG = "NoteEditText";

    // 变量：当前光标所在的索引
    private int mIndex;

    // 变量：记录删除操作之前光标的起始位置
    private int mSelectionStartBeforeDelete;

    // 定义常量，表示不同的 URL scheme
    private static final String SCHEME_TEL = "tel:";   // 电话链接
    private static final String SCHEME_HTTP = "http:";  // HTTP链接
    private static final String SCHEME_EMAIL = "mailto:"; // 邮件链接

    // 创建一个映射，存储不同链接的处理方式
    private static final Map<String, Integer> sSchemaActionResMap = new HashMap<String, Integer>();

    // 静态初始化块，将不同的 URL scheme 与对应的字符串资源 ID 关联
    static {
        sSchemaActionResMap.put(SCHEME_TEL, R.string.note_link_tel);    // 电话链接的处理方式
        sSchemaActionResMap.put(SCHEME_HTTP, R.string.note_link_web);   // HTTP链接的处理方式
        sSchemaActionResMap.put(SCHEME_EMAIL, R.string.note_link_email); // 邮件链接的处理方式
    }

    /**
     * Call by the {@link NoteEditActivity} to delete or add edit text
     */
    public interface OnTextViewChangeListener {
        /**
         * Delete current edit text when {@link KeyEvent#KEYCODE_DEL} happens
         * and the text is null
         */
        void onEditTextDelete(int index, String text);

        /**
         * Add edit text after current edit text when {@link KeyEvent#KEYCODE_ENTER}
         * happen
         */
        void onEditTextEnter(int index, String text);

        /**
         * Hide or show item option when text change
         */
        void onTextChange(int index, boolean hasText);
    }

    private OnTextViewChangeListener mOnTextViewChangeListener;

   public class NoteEditText extends EditText {
    private int mIndex;  // 用于存储索引
    private int mSelectionStartBeforeDelete;  // 记录删除前的光标位置
    private OnTextViewChangeListener mOnTextViewChangeListener;  // 用于监听文本变动的接口
    private static final String TAG = "NoteEditText";  // 日志标签

    // 构造函数1：仅接受上下文作为参数
    public NoteEditText(Context context) {
        super(context, null);
        mIndex = 0;  // 默认索引为0
    }

    // 构造函数2：接受上下文和属性集作为参数
    public NoteEditText(Context context, AttributeSet attrs) {
        super(context, attrs, android.R.attr.editTextStyle);
    }

    // 构造函数3：接受上下文、属性集和样式作为参数
    public NoteEditText(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        // 可以根据需要添加初始化代码
    }

    // 设置索引值的方法
    public void setIndex(int index) {
        mIndex = index;
    }

    // 设置监听器的方法
    public void setOnTextViewChangeListener(OnTextViewChangeListener listener) {
        mOnTextViewChangeListener = listener;
    }

    // 处理触摸事件，主要是设置光标位置
    @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;  // 返回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) {
                    // 如果删除前光标位置为0并且索引不为0，调用删除监听器
                    if (0 == mSelectionStartBeforeDelete && mIndex != 0) {
                        mOnTextViewChangeListener.onEditTextDelete(mIndex, getText().toString());
                        return true;  // 返回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();
                    // 截取光标前的文本并设置回TextView
                    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) {
        // 如果文本框失去焦点并且文本为空
        if (!focused && TextUtils.isEmpty(getText())) {
            // 调用文本改变监听器，传入索引和一个布尔值 'false' 表示文本为空
            mOnTextViewChangeListener.onTextChange(mIndex, false);
        } else {
            // 否则，调用监听器，传入 'true' 表示文本不为空
            mOnTextViewChangeListener.onTextChange(mIndex, true);
        }
    }
    // 调用父类的 onFocusChanged 方法，以确保焦点改变时的默认行为（例如更新视觉效果）得到执行
    super.onFocusChanged(focused, direction, previouslyFocusedRect);
}

@Override
protected void onCreateContextMenu(ContextMenu menu) {
    // 检查当前文本是否是 Spanned 类型，Spanned 是一个支持富文本的接口（例如超链接）
    if (getText() instanceof Spanned) {
        // 获取选中的文本范围
        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);
        // 如果选中的区域包含一个 URLSpan（即只有一个超链接）
        if (urls.length == 1) {
            // 默认的资源 ID
            int defaultResId = 0;
            // 遍历所有已知的 URL schema 类型（如 http://, https:// 等），匹配 URL
            for(String schema: sSchemaActionResMap.keySet()) {
                // 如果 URL 中包含某个 schema 类型
                if(urls[0].getURL().indexOf(schema) >= 0) {
                    // 根据匹配的 schema 获取对应的资源 ID
                    defaultResId = sSchemaActionResMap.get(schema);
                    break;
                }
            }

            // 如果没有找到匹配的 schema，使用一个默认的字符串资源 ID
            if (defaultResId == 0) {
                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;
                        }
                    });
        }
    }
    // 调用父类的 onCreateContextMenu 方法，以确保默认的上下文菜单行为
    super.onCreateContextMenu(menu);
}
}
