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

// 导入Android内容提供者相关类
import android.content.ContentProviderOperation;     // 内容提供者操作
import android.content.ContentProviderResult;      // 内容提供者操作结果
import android.content.ContentResolver;            // 内容解析器
import android.content.ContentUris;                // URI工具
import android.content.ContentValues;               // 内容值对象
import android.content.OperationApplicationException;  // 操作应用异常
// 导入数据库相关类
import android.database.Cursor;                    // 数据库游标
// 导入远程异常类
import android.os.RemoteException;                 // 远程调用异常
// 导入日志工具
import android.util.Log;                           // 日志工具

// 导入项目数据类
import net.micode.notes.data.Notes;                // 笔记常量定义
import net.micode.notes.data.Notes.CallNote;       // 通话笔记类型
import net.micode.notes.data.Notes.NoteColumns;    // 笔记列定义
// 导入小部件属性类
import net.micode.notes.ui.NotesListAdapter.AppWidgetAttribute;  // 小部件属性

// 导入集合类
import java.util.ArrayList;                         // 动态数组
import java.util.HashSet;                          // 哈希集合

/**
 * 数据工具类，提供批量操作数据库的方法
 */
public class DataUtils {
    // 日志标签
    public static final String TAG = "DataUtils";

    /**
     * 批量删除笔记
     * @param resolver 内容解析器
     * @param ids 要删除的笔记ID集合
     * @return 是否删除成功
     */
    public static boolean batchDeleteNotes(ContentResolver resolver, HashSet<Long> ids) {
        // 参数校验
        if (ids == null) {
            Log.d(TAG, "the ids is null");
            return true;  // 没有要删除的笔记视为成功
        }
        if (ids.size()  == 0) {
            Log.d(TAG, "no id is in the hashset");
            return true;  // 空集合视为成功
        }

        // 创建批量操作列表
        ArrayList<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>();
        // 遍历要删除的笔记ID
        for (long id : ids) {
            if(id == Notes.ID_ROOT_FOLDER) {  // 防止删除系统根文件夹
                Log.e(TAG, "Don't delete system folder root");
                continue;
            }
            // 创建删除操作
            ContentProviderOperation.Builder builder = ContentProviderOperation
                    .newDelete(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI,  id));
            operationList.add(builder.build());   // 添加到操作列表
        }
        try {
            // 执行批量操作
            ContentProviderResult[] results = resolver.applyBatch(Notes.AUTHORITY,  operationList);
            // 检查操作结果
            if (results == null || results.length  == 0 || results[0] == null) {
                Log.d(TAG, "delete notes failed, ids:" + ids.toString());
                return false;
            }
            return true;
        } catch (RemoteException e) {
            Log.e(TAG, String.format("%s:  %s", e.toString(),  e.getMessage()));
        } catch (OperationApplicationException e) {
            Log.e(TAG, String.format("%s:  %s", e.toString(),  e.getMessage()));
        }
        return false;
    }

    /**
     * 移动笔记到指定文件夹
     * @param resolver 内容解析器
     * @param id 笔记ID
     * @param srcFolderId 源文件夹ID
     * @param desFolderId 目标文件夹ID
     */
    public static void moveNoteToFoler(ContentResolver resolver, long id, long srcFolderId, long desFolderId) {
        // 创建要更新的内容值
        ContentValues values = new ContentValues();
        values.put(NoteColumns.PARENT_ID,  desFolderId);      // 设置新父文件夹ID
        values.put(NoteColumns.ORIGIN_PARENT_ID,  srcFolderId); // 记录原父文件夹ID
        values.put(NoteColumns.LOCAL_MODIFIED,  1);           // 标记为已修改
        // 执行更新
        resolver.update(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI,  id), values, null, null);
    }

    /**
     * 批量移动笔记到指定文件夹
     * @param resolver 内容解析器
     * @param ids 要移动的笔记ID集合
     * @param folderId 目标文件夹ID
     * @return 是否移动成功
     */
    public static boolean batchMoveToFolder(ContentResolver resolver, HashSet<Long> ids,
                                            long folderId) {
        // 参数校验
        if (ids == null) {
            Log.d(TAG, "the ids is null");
            return true;  // 没有要移动的笔记视为成功
        }

        // 创建批量操作列表
        ArrayList<ContentProviderOperation> operationList = new ArrayList<>();
        // 遍历要移动的笔记ID
        for (long id : ids) {
            // 创建更新操作
            ContentProviderOperation.Builder builder = ContentProviderOperation
                    .newUpdate(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI,  id));
            builder.withValue(NoteColumns.PARENT_ID,  folderId);  // 设置新父文件夹ID
            builder.withValue(NoteColumns.LOCAL_MODIFIED,  1);     // 标记为已修改
            operationList.add(builder.build());   // 添加到操作列表
        }

        try {
            // 执行批量操作
            ContentProviderResult[] results = resolver.applyBatch(Notes.AUTHORITY,  operationList);
            // 检查操作结果
            if (results == null || results.length  == 0 || results[0] == null) {
                Log.d(TAG, "delete notes failed, ids:" + ids.toString());
                return false;
            }
            return true;
        } catch (RemoteException e) {
            Log.e(TAG, String.format("%s:  %s", e.toString(),  e.getMessage()));
        } catch (OperationApplicationException e) {
            Log.e(TAG, String.format("%s:  %s", e.toString(),  e.getMessage()));
        }
        return false;
    }

    /**
     * 获取用户文件夹数量（排除系统文件夹）
     * @param resolver 内容解析器
     * @return 用户文件夹数量
     */
    public static int getUserFolderCount(ContentResolver resolver) {
        // 查询符合条件的文件夹数量
        Cursor cursor =resolver.query(Notes.CONTENT_NOTE_URI,
                new String[] { "COUNT(*)" },  // 只查询计数
                NoteColumns.TYPE + "=? AND " + NoteColumns.PARENT_ID + "<>?",  // 查询条件
                new String[] { String.valueOf(Notes.TYPE_FOLDER),  String.valueOf(Notes.ID_TRASH_FOLER)},   // 参数值
                null);  // 无排序

        int count = 0;
        if(cursor != null) {
            if(cursor.moveToFirst())  {
                try {
                    count = cursor.getInt(0);   // 获取计数结果
                } catch (IndexOutOfBoundsException e) {
                    Log.e(TAG, "get folder count failed:" + e.toString());
                } finally {
                    cursor.close();   // 确保关闭游标
                }
            }
        }
        return count;
    }

    /**
     * 检查指定类型笔记是否在数据库中可见（不在回收站）
     * @param resolver 内容解析器
     * @param noteId 笔记ID
     * @param type 笔记类型
     * @return 是否可见
     */
    public static boolean visibleInNoteDatabase(ContentResolver resolver, long noteId, int type) {
        // 查询指定条件的笔记
        Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI,  noteId),
                null,  // 查询所有列
                NoteColumns.TYPE + "=? AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER,  // 条件
                new String [] {String.valueOf(type)},   // 参数值
                null);  // 无排序

        boolean exist = false;
        if (cursor != null) {
            if (cursor.getCount()  > 0) {  // 如果有记录
                exist = true;
            }
            cursor.close();   // 关闭游标
        }
        return exist;
    }

    /**
     * 检查笔记是否存在于笔记数据库中
     * @param resolver 内容解析器
     * @param noteId 笔记ID
     * @return 是否存在
     */
    public static boolean existInNoteDatabase(ContentResolver resolver, long noteId) {
        // 查询指定ID的笔记
        Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI,  noteId),
                null, null, null, null);  // 无条件查询

        boolean exist = false;
        if (cursor != null) {
            if (cursor.getCount()  > 0) {  // 如果有记录
                exist = true;
            }
            cursor.close();   // 关闭游标
        }
        return exist;
    }

    /**
     * 检查数据项是否存在于数据数据库中
     * @param resolver 内容解析器
     * @param dataId 数据ID
     * @return 是否存在
     */
    public static boolean existInDataDatabase(ContentResolver resolver, long dataId) {
        // 查询指定ID的数据项
        Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_DATA_URI,  dataId),
                null, null, null, null);  // 无条件查询

        boolean exist = false;
        if (cursor != null) {
            if (cursor.getCount()  > 0) {  // 如果有记录
                exist = true;
            }
            cursor.close();   // 关闭游标
        }
        return exist;
    }

    /**
     * 检查指定名称的文件夹是否已存在
     * @param resolver 内容解析器
     * @param name 文件夹名称
     * @return 是否存在
     */
    public static boolean checkVisibleFolderName(ContentResolver resolver, String name) {
        // 查询指定名称的文件夹
        Cursor cursor = resolver.query(Notes.CONTENT_NOTE_URI,  null,
                NoteColumns.TYPE + "=" + Notes.TYPE_FOLDER +  // 文件夹类型
                        " AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER +  // 不在回收站
                        " AND " + NoteColumns.SNIPPET + "=?",  // 名称匹配
                new String[] { name }, null);  // 参数值

        boolean exist = false;
        if(cursor != null) {
            if(cursor.getCount()  > 0) {  // 如果有记录
                exist = true;
            }
            cursor.close();   // 关闭游标
        }
        return exist;
    }

    /**
     * 获取文件夹关联的小部件集合
     * @param resolver 内容解析器
     * @param folderId 文件夹ID
     * @return 小部件属性集合
     */
    public static HashSet<AppWidgetAttribute> getFolderNoteWidget(ContentResolver resolver, long folderId) {
        // 查询文件夹下笔记的小部件信息
        Cursor c = resolver.query(Notes.CONTENT_NOTE_URI,
                new String[] { NoteColumns.WIDGET_ID, NoteColumns.WIDGET_TYPE },  // 查询小部件ID和类型
                NoteColumns.PARENT_ID + "=?",  // 指定父文件夹
                new String[] { String.valueOf(folderId)  },  // 参数值
                null);  // 无排序

        HashSet<AppWidgetAttribute> set = null;
        if (c != null) {
            if (c.moveToFirst())  {
                set = new HashSet<>();  // 创建集合
                do {
                    try {
                        // 创建小部件属性对象并添加到集合
                        AppWidgetAttribute widget = new AppWidgetAttribute();
                        widget.widgetId  = c.getInt(0);       // 小部件ID
                        widget.widgetType.set(c.getInt(1));     // 小部件类型
                        set.add(widget);
                    } catch (IndexOutOfBoundsException e) {
                        Log.e(TAG, e.toString());
                    }
                } while (c.moveToNext());
            }
            c.close();   // 关闭游标
        }
        return set;
    }

    /**
     * 根据笔记ID获取通话号码
     * @param resolver 内容解析器
     * @param noteId 笔记ID
     * @return 通话号码
     */
    public static String getCallNumberByNoteId(ContentResolver resolver, long noteId) {
        // 查询指定笔记的通话数据
        Cursor cursor = resolver.query(Notes.CONTENT_DATA_URI,
                new String [] { CallNote.PHONE_NUMBER },  // 只查询电话号码
                CallNote.NOTE_ID + "=? AND " + CallNote.MIME_TYPE + "=?",  // 条件
                new String [] { String.valueOf(noteId),  CallNote.CONTENT_ITEM_TYPE },  // 参数值
                null);  // 无排序

        if (cursor != null && cursor.moveToFirst())  {
            try (cursor) {
                return cursor.getString(0);   // 返回电话号码
            } catch (IndexOutOfBoundsException e) {
                Log.e(TAG, "Get call number fails " + e.toString());
            }
            // 确保关闭游标
        }
        return "";  // 未找到返回空字符串
    }

    /**
     * 根据电话号码和通话日期获取笔记ID
     * @param resolver 内容解析器
     * @param phoneNumber 电话号码
     * @param callDate 通话日期
     * @return 笔记ID
     */
    public static long getNoteIdByPhoneNumberAndCallDate(ContentResolver resolver, String phoneNumber, long callDate) {
        // 查询符合条件的数据项
        Cursor cursor = resolver.query(Notes.CONTENT_DATA_URI,
                new String [] { CallNote.NOTE_ID },  // 只查询笔记ID
                CallNote.CALL_DATE + "=? AND " + CallNote.MIME_TYPE + "=? AND PHONE_NUMBERS_EQUAL("
                        + CallNote.PHONE_NUMBER + ",?)",  // 条件
                new String [] { String.valueOf(callDate),  CallNote.CONTENT_ITEM_TYPE, phoneNumber },  // 参数值
                null);  // 无排序

        if (cursor != null) {
            if (cursor.moveToFirst())  {
                try {
                    return cursor.getLong(0);   // 返回笔记ID
                } catch (IndexOutOfBoundsException e) {
                    Log.e(TAG, "Get call note id fails " + e.toString());
                }
            }
            cursor.close();   // 关闭游标
        }
        return 0;  // 未找到返回0
    }

    /**
     * 根据笔记ID获取摘要内容
     * @param resolver 内容解析器
     * @param noteId 笔记ID
     * @return 笔记摘要
     */
    public static String getSnippetById(ContentResolver resolver, long noteId) {
        // 查询指定笔记的摘要
        Cursor cursor = resolver.query(Notes.CONTENT_NOTE_URI,
                new String [] { NoteColumns.SNIPPET },  // 只查询摘要
                NoteColumns.ID + "=?",  // 条件
                new String [] { String.valueOf(noteId)},   // 参数值
                null);  // 无排序

        if (cursor != null) {
            String snippet = "";
            if (cursor.moveToFirst())  {
                snippet = cursor.getString(0);   // 获取摘要
            }
            cursor.close();   // 关闭游标
            return snippet;
        }
        throw new IllegalArgumentException("Note is not found with id: " + noteId);  // 未找到抛出异常
    }

    /**
     * 格式化摘要内容（去除首尾空格和换行）
     * @param snippet 原始摘要
     * @return 格式化后的摘要
     */
    public static String getFormattedSnippet(String snippet) {
        if (snippet != null) {
            snippet = snippet.trim();   // 去除首尾空格
            int index = snippet.indexOf('\n');   // 查找第一个换行符
            if (index != -1) {
                snippet = snippet.substring(0,  index);  // 截取到第一个换行符前的内容
            }
        }
        return snippet;
    }
}
