/*
 * 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.data;

//引入必要的类

// 用于封装一组键值对
import android.content.ContentValues;
// 上下文类
import android.content.Context;
// SQLite数据库类
import android.database.sqlite.SQLiteDatabase;
// SQLite数据库助手类
import android.database.sqlite.SQLiteOpenHelper;
// 日志类
import android.util.Log;

// 导入数据列相关常量
import net.micode.notes.data.Notes.DataColumns;
// 导入数据相关常量
import net.micode.notes.data.Notes.DataConstants;
// 导入笔记列相关常量
import net.micode.notes.data.Notes.NoteColumns;

//创建 NotesDatabaseHelper 类 ，继承 SQLiteOpenHelper
public class NotesDatabaseHelper extends SQLiteOpenHelper {
    // 定义数据库名称，只能在 NotesDatabaseHelper 类内部访问，并且在程序运行过程中无法修改。
    private static final String DB_NAME = "note.db";
    // 数据库版本
    private static final int DB_VERSION = 4;
    // 定义表名 TABLE 接口
    public interface TABLE {
        // 笔记表名
        public static final String NOTE = "note";

        // 数据表名
        public static final String DATA = "data";
    }

    //日志标签
    private static final String TAG = "NotesDatabaseHelper";

    // 单例模式实例
    private static NotesDatabaseHelper mInstance;

    // 在数据库创建笔记表
    private static final String CREATE_NOTE_TABLE_SQL =
        "CREATE TABLE " + TABLE.NOTE + "(" +
            NoteColumns.ID + " INTEGER PRIMARY KEY," +                 // 笔记 id，主键
            NoteColumns.PARENT_ID + " INTEGER NOT NULL DEFAULT 0," +       // 笔记的父级id，默认为 0
            NoteColumns.ALERTED_DATE + " INTEGER NOT NULL DEFAULT 0," +        // 警告日期，默认为 0
            NoteColumns.BG_COLOR_ID + " INTEGER NOT NULL DEFAULT 0," +         // 背景颜色 id ，默认为0
            // 笔记创建日期，默认为当前时间，单位是毫秒
            NoteColumns.CREATED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," +
            // 是否有附件，默认为 0
            NoteColumns.HAS_ATTACHMENT + " INTEGER NOT NULL DEFAULT 0," +
            // 修改日期，默认为当前时间，单位是毫秒
            NoteColumns.MODIFIED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," +
            // 笔记的数量，默认为 0
            NoteColumns.NOTES_COUNT + " INTEGER NOT NULL DEFAULT 0," +
            // 摘要，默认为空字符串
            NoteColumns.SNIPPET + " TEXT NOT NULL DEFAULT ''," +
            NoteColumns.TYPE + " INTEGER NOT NULL DEFAULT 0," +          //笔记类型，默认为 0
            NoteColumns.WIDGET_ID + " INTEGER NOT NULL DEFAULT 0," +     // 小部件 id，默认为 0
            NoteColumns.WIDGET_TYPE + " INTEGER NOT NULL DEFAULT -1," +     // 小部件类型，默认为 -1
            NoteColumns.SYNC_ID + " INTEGER NOT NULL DEFAULT 0," +          // 同步 id ，默认为0
            NoteColumns.LOCAL_MODIFIED + " INTEGER NOT NULL DEFAULT 0," +       // 本地修改标识，默认为 0
            NoteColumns.ORIGIN_PARENT_ID + " INTEGER NOT NULL DEFAULT 0," +     // 原始父级 id ，默认为 0
            NoteColumns.GTASK_ID + " TEXT NOT NULL DEFAULT ''," +           // GTASK ID,默认为空字符串
            NoteColumns.VERSION + " INTEGER NOT NULL DEFAULT 0" +           // 版本，默认为 0
        ")";

    // 在数据库创建数据表
    private static final String CREATE_DATA_TABLE_SQL =
        "CREATE TABLE " + TABLE.DATA + "(" +
            DataColumns.ID + " INTEGER PRIMARY KEY," +          // 数据 id，主键
            DataColumns.MIME_TYPE + " TEXT NOT NULL," +         // MIME 类型，不能为空
            DataColumns.NOTE_ID + " INTEGER NOT NULL DEFAULT 0," +          // 笔记 id，默认为0
            // 创建日期，默认为当前时间（毫秒）
            NoteColumns.CREATED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," +
            // 修改日期，默认为当前时间（毫秒）
            NoteColumns.MODIFIED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," +
            DataColumns.CONTENT + " TEXT NOT NULL DEFAULT ''," +            // 内容，默认为空字符串
            DataColumns.DATA1 + " INTEGER," +           // 自定义数据 1
            DataColumns.DATA2 + " INTEGER," +           // 自定义数据 2
            DataColumns.DATA3 + " TEXT NOT NULL DEFAULT ''," +          // 自定义数据 3，默认为空字符串
            DataColumns.DATA4 + " TEXT NOT NULL DEFAULT ''," +          // 自定义数据 4，默认为空字符串
            DataColumns.DATA5 + " TEXT NOT NULL DEFAULT ''" +           // 自定义数据 5，默认为空字符串
        ")";

    // 创建索引以加速根据 NOTE_ID 查询的数据表
    private static final String CREATE_DATA_NOTE_ID_INDEX_SQL =
        "CREATE INDEX IF NOT EXISTS note_id_index ON " +
        TABLE.DATA + "(" + DataColumns.NOTE_ID + ");";

    /**
     * Increase folder's note count when move note to the folder
     */
    // 增加文件夹中的笔记计数，当笔记移动到该文件夹时
    private static final String NOTE_INCREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER =
        "CREATE TRIGGER increase_folder_count_on_update "+
        " AFTER UPDATE OF " + NoteColumns.PARENT_ID + " ON " + TABLE.NOTE +
        " BEGIN " +
        "  UPDATE " + TABLE.NOTE +
        "   SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + " + 1" +  // 更新笔记数量
        "  WHERE " + NoteColumns.ID + "=new." + NoteColumns.PARENT_ID + ";" +   // 按照新父级 id 更新
        " END";     // 结束触发器

    /**
     * Decrease folder's note count when move note from folder
     */
    // 创建一个触发器，该触发器在更新笔记的父 id 字段后执行
    private static final String NOTE_DECREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER =
        "CREATE TRIGGER decrease_folder_count_on_update " +
        // 在更新父 id 字段时触发
        " AFTER UPDATE OF " + NoteColumns.PARENT_ID + " ON " + TABLE.NOTE +
        " BEGIN " +
        // 更新目标笔记的子笔记数量，减少 1
        "  UPDATE " + TABLE.NOTE +
        "   SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + "-1" +
        // 条件：只在旧的父 id 等于当前笔记 id 时进行更新，且子笔记数量大于 0
        "  WHERE " + NoteColumns.ID + "=old." + NoteColumns.PARENT_ID +
        "  AND " + NoteColumns.NOTES_COUNT + ">0" + ";" +
        " END";

    /**
     * Increase folder's note count when insert new note to the folder
     */
    // 创建一个触发器，该触发器在向笔记表插入新笔记后执行
    private static final String NOTE_INCREASE_FOLDER_COUNT_ON_INSERT_TRIGGER =
        "CREATE TRIGGER increase_folder_count_on_insert " +
        // 在插入操作后触发
        " AFTER INSERT ON " + TABLE.NOTE +
        " BEGIN " +
        // 更新目标笔记的子笔记数量，增加 1
        "  UPDATE " + TABLE.NOTE +
        "   SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + " + 1" +
        // 条件: 通过新插入笔记的父 id 找到对应的笔记并更新
        "  WHERE " + NoteColumns.ID + "=new." + NoteColumns.PARENT_ID + ";" +
        " END";

    /**
     * Decrease folder's note count when delete note from the folder
     */
    // 创建一个触发器，该触发器在从笔记删除笔记后执行
    private static final String NOTE_DECREASE_FOLDER_COUNT_ON_DELETE_TRIGGER =
        "CREATE TRIGGER decrease_folder_count_on_delete " +
        // 在删除操作后触发
        " AFTER DELETE ON " + TABLE.NOTE +
        " BEGIN " +
        // 更新目标笔记的子笔记数量，数量减 1
        "  UPDATE " + TABLE.NOTE +
        "   SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + "-1" +
        // 条件：当前笔记 id 等于 旧的父 id，并且子笔记数量大于 0
        "  WHERE " + NoteColumns.ID + "=old." + NoteColumns.PARENT_ID +
        "  AND " + NoteColumns.NOTES_COUNT + ">0;" +
        " END";

    /**
     * Update note's content when insert data with type {@link DataConstants#NOTE}
     */
    // 创建一个触发器，该触发器在向数据表插入新数据时执行
    private static final String DATA_UPDATE_NOTE_CONTENT_ON_INSERT_TRIGGER =
        "CREATE TRIGGER update_note_content_on_insert " +
        // 在插入操作后触发
        " AFTER INSERT ON " + TABLE.DATA +
        // 当新插入的数据类型为 NOTE 时触发
        " WHEN new." + DataColumns.MIME_TYPE + "='" + DataConstants.NOTE + "'" +
        " BEGIN" +
        // 更新目标笔记的内容快照为新插入数据的内容
        "  UPDATE " + TABLE.NOTE +
        "   SET " + NoteColumns.SNIPPET + "=new." + DataColumns.CONTENT +
        // 条件：通过新插入数据的 NOTE_ID 找到对应的笔记进行更新
        "  WHERE " + NoteColumns.ID + "=new." + DataColumns.NOTE_ID + ";" +
        " END";

    /**
     * Update note's content when data with {@link DataConstants#NOTE} type has changed
     */
    // 创建一个触发器，该触发器在更新数据表中的数据时执行
    private static final String DATA_UPDATE_NOTE_CONTENT_ON_UPDATE_TRIGGER =
        "CREATE TRIGGER update_note_content_on_update " +
        // 在更新操作后触发
        " AFTER UPDATE ON " + TABLE.DATA +
        // 当旧数据类型为 NOTE 时触发
        " WHEN old." + DataColumns.MIME_TYPE + "='" + DataConstants.NOTE + "'" +
        " BEGIN" +
        // 更新目标笔记的内容快照为新更新数据的内容
        "  UPDATE " + TABLE.NOTE +
        "   SET " + NoteColumns.SNIPPET + "=new." + DataColumns.CONTENT +
        // 条件：通过新更新数据的 NOTE_ID 找到对应的笔记进行更新
        "  WHERE " + NoteColumns.ID + "=new." + DataColumns.NOTE_ID + ";" +
        " END";

    /**
     * Update note's content when data with {@link DataConstants#NOTE} type has deleted
     */
    // 创建一个触发器，该触发器在删除数据表中的数据时执行。
    private static final String DATA_UPDATE_NOTE_CONTENT_ON_DELETE_TRIGGER =
        "CREATE TRIGGER update_note_content_on_delete " +
        // 在删除操作后触发
        " AFTER delete ON " + TABLE.DATA +
        // 当旧数据类型为NOTE时触发
        " WHEN old." + DataColumns.MIME_TYPE + "='" + DataConstants.NOTE + "'" +
        " BEGIN" +
        // 将目标笔记的内容快照更新为空字符串
        "  UPDATE " + TABLE.NOTE +
        "   SET " + NoteColumns.SNIPPET + "=''" +
        // 条件：通过旧数据的NOTE_ID找到对应的笔记进行更新
        "  WHERE " + NoteColumns.ID + "=old." + DataColumns.NOTE_ID + ";" +
        " END";

    /**
     * Delete datas belong to note which has been deleted
     */
    // 创建一个触发器，该触发器在删除笔记时执行。
    private static final String NOTE_DELETE_DATA_ON_DELETE_TRIGGER =
        "CREATE TRIGGER delete_data_on_delete " +
        // 在删除操作后触发
        " AFTER DELETE ON " + TABLE.NOTE +
        " BEGIN" +
        // 删除与被删除笔记相关联的所有数据
        "  DELETE FROM " + TABLE.DATA +
        "   WHERE " + DataColumns.NOTE_ID + "=old." + NoteColumns.ID + ";" +
        " END";

    /**
     * Delete notes belong to folder which has been deleted
     */
    // 创建一个触发器，当删除笔记时执行
    private static final String FOLDER_DELETE_NOTES_ON_DELETE_TRIGGER =
        "CREATE TRIGGER folder_delete_notes_on_delete " +
                // 在删除操作后触发
        " AFTER DELETE ON " + TABLE.NOTE +
        " BEGIN" +
                // 在删除操作后触发
        "  DELETE FROM " + TABLE.NOTE +
        "   WHERE " + NoteColumns.PARENT_ID + "=old." + NoteColumns.ID + ";" +
        " END";

    /**
     * Move notes belong to folder which has been moved to trash folder
     */
    // 创建一个触发器，用于移动到垃圾箱文件夹的笔记
    private static final String FOLDER_MOVE_NOTES_ON_TRASH_TRIGGER =
        "CREATE TRIGGER folder_move_notes_on_trash " +
        " AFTER UPDATE ON " + TABLE.NOTE +              // 在更新操作后触发
                // 当新父ID为垃圾箱文件夹时触发
        " WHEN new." + NoteColumns.PARENT_ID + "=" + Notes.ID_TRASH_FOLER +
        " BEGIN" +
        "  UPDATE " + TABLE.NOTE +          // 更新所有子笔记的父ID为垃圾箱文件夹ID
        "   SET " + NoteColumns.PARENT_ID + "=" + Notes.ID_TRASH_FOLER +
        "  WHERE " + NoteColumns.PARENT_ID + "=old." + NoteColumns.ID + ";" +
        " END";

    // NotesDatabaseHelper类的构造函数，初始化数据库
    public NotesDatabaseHelper(Context context) {
        super(context, DB_NAME, null, DB_VERSION);
    }

    // 创建笔记表
    public void createNoteTable(SQLiteDatabase db) {
        db.execSQL(CREATE_NOTE_TABLE_SQL);      // 执行创建笔记表的SQL语句
        reCreateNoteTableTriggers(db);           // 重新创建与笔记表相关的触发器
        createSystemFolder(db);                      // 创建系统文件夹
        Log.d(TAG, "note table has been created");       // 打印日志，指示笔记表已创建
    }

    // 重新创建笔记表的触发器
    private void reCreateNoteTableTriggers(SQLiteDatabase db) {
        // 删除已存在的触发器，防止重复创建
        db.execSQL("DROP TRIGGER IF EXISTS increase_folder_count_on_update");
        db.execSQL("DROP TRIGGER IF EXISTS decrease_folder_count_on_update");
        db.execSQL("DROP TRIGGER IF EXISTS decrease_folder_count_on_delete");
        db.execSQL("DROP TRIGGER IF EXISTS delete_data_on_delete");
        db.execSQL("DROP TRIGGER IF EXISTS increase_folder_count_on_insert");
        db.execSQL("DROP TRIGGER IF EXISTS folder_delete_notes_on_delete");
        db.execSQL("DROP TRIGGER IF EXISTS folder_move_notes_on_trash");

        // 创建新的触发器
        db.execSQL(NOTE_INCREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER);
        db.execSQL(NOTE_DECREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER);
        db.execSQL(NOTE_DECREASE_FOLDER_COUNT_ON_DELETE_TRIGGER);
        db.execSQL(NOTE_DELETE_DATA_ON_DELETE_TRIGGER);
        db.execSQL(NOTE_INCREASE_FOLDER_COUNT_ON_INSERT_TRIGGER);
        db.execSQL(FOLDER_DELETE_NOTES_ON_DELETE_TRIGGER);
        db.execSQL(FOLDER_MOVE_NOTES_ON_TRASH_TRIGGER);
    }

    // 创建系统文件夹
    private void createSystemFolder(SQLiteDatabase db) {
        ContentValues values = new ContentValues();

        /**
         * call record foler for call notes
         */
        //创建通话记录文件夹用于存储通话笔记
        values.put(NoteColumns.ID, Notes.ID_CALL_RECORD_FOLDER);        // 设置文件夹ID
        values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);                 // 设置文件夹类型为系统
        db.insert(TABLE.NOTE, null, values);                    // 插入文件夹记录

        /**
         * root folder which is default folder
         */
        // 创建根文件夹，作为默认文件夹
        values.clear();         // 清空上次插入的内容
        values.put(NoteColumns.ID, Notes.ID_ROOT_FOLDER);        // 设置根文件夹ID
        values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);        // 设置文件夹类型为系统
        db.insert(TABLE.NOTE, null, values);        // 插入根文件夹记录

        /**
         * temporary folder which is used for moving note
         */
        // 创建临时文件夹，用于移动笔记
        values.clear();     // 清空内容
        values.put(NoteColumns.ID, Notes.ID_TEMPARAY_FOLDER);        // 设置临时文件夹ID
        values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);            // 设置文件夹类型为系统
        db.insert(TABLE.NOTE, null, values);        // 插入临时文件夹记录

        /**
         * create trash folder
         */
        // 创建垃圾箱文件夹
        values.clear();     // 清空内容
        values.put(NoteColumns.ID, Notes.ID_TRASH_FOLER);              //设置垃圾箱文件夹ID
        values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);                //设置文件夹类型为系统
        db.insert(TABLE.NOTE, null, values);                      // 插入垃圾箱文件夹记录
    }

    //创建数据表的方法
    public void createDataTable(SQLiteDatabase db) {
        db.execSQL(CREATE_DATA_TABLE_SQL);      // 执行创建数据表的SQL语句
        reCreateDataTableTriggers(db);      // 重新创建数据表的触发器
        db.execSQL(CREATE_DATA_NOTE_ID_INDEX_SQL);  // 创建数据表的索引
        Log.d(TAG, "data table has been created");  // 打印日志，指示数据表已创建
    }

    // 重新创建数据表的触发器的方法
    private void reCreateDataTableTriggers(SQLiteDatabase db) {
        // 如果触发器存在，则删除触发器
        db.execSQL("DROP TRIGGER IF EXISTS update_note_content_on_insert");
        db.execSQL("DROP TRIGGER IF EXISTS update_note_content_on_update");
        db.execSQL("DROP TRIGGER IF EXISTS update_note_content_on_delete");

        // 创建新的插入触发器
        db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_INSERT_TRIGGER);
        // 创建新的更新触发器
        db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_UPDATE_TRIGGER);
        // 创建新的删除触发器
        db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_DELETE_TRIGGER);
    }

    // 获取NotesDatabaseHelper实例的静态同步方法
    static synchronized NotesDatabaseHelper getInstance(Context context) {
        // 如果实例尚未创建，则创建一个新的实例
        if (mInstance == null) {
            mInstance = new NotesDatabaseHelper(context);
        }
        return mInstance;       // 返回现有或新创建的实例
    }

    // 数据库创建时调用的方法
    @Override
    public void onCreate(SQLiteDatabase db) {
        createNoteTable(db);        //创建笔记表
        createDataTable(db);        // 创建数据表
    }

    // 数据库升级时调用的方法
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        boolean reCreateTriggers = false;   // 标识是否需要重新创建触发器
        boolean skipV2 = false;     // 标识是否跳过v2的升级

        // 从版本1升级到版本2
        if (oldVersion == 1) {
            upgradeToV2(db);    // 执行升级到v2的方法
            // 设置跳过v2的标志，因为此升级包含了从v2到v3的升级
            skipV2 = true; // this upgrade including the upgrade from v2 to v3
            oldVersion++;   // 版本号自增
        }

        // 从版本2升级到版本3，如果没有跳过v2
        if (oldVersion == 2 && !skipV2) {
            upgradeToV3(db);        // 执行升级到v3的方法
            reCreateTriggers = true;        // 设置需要重新创建触发器的标志
            oldVersion++;       // 版本号自增
        }

        // 从版本3升级到版本4
        if (oldVersion == 3) {
            upgradeToV4(db);         // 执行升级到v4的方法
            oldVersion++;           // 版本号自增
        }

        // 如果需要重新创建触发器，则执行相关方法
        if (reCreateTriggers) {
            reCreateNoteTableTriggers(db);      // 重新创建笔记表的触发器
            reCreateDataTableTriggers(db);      // 重新创建数据表的触发器
        }

        // 检查最终的版本号是否与目标版本一致
        if (oldVersion != newVersion) {
            throw new IllegalStateException("Upgrade notes database to version " + newVersion
                    + "fails");     // 抛出异常，表示升级失败
        }
    }

    // 升级到版本2的方法
    private void upgradeToV2(SQLiteDatabase db) {
        // 如果存在，则删除笔记表
        db.execSQL("DROP TABLE IF EXISTS " + TABLE.NOTE);
        // 如果存在，则删除数据表
        db.execSQL("DROP TABLE IF EXISTS " + TABLE.DATA);
        // 创建新的笔记表
        createNoteTable(db);
        // 创建新的数据表
        createDataTable(db);
    }

    // 升级到版本3的方法
    private void upgradeToV3(SQLiteDatabase db) {
        // drop unused triggers  删除不再使用的触发器
        db.execSQL("DROP TRIGGER IF EXISTS update_note_modified_date_on_insert");
        db.execSQL("DROP TRIGGER IF EXISTS update_note_modified_date_on_delete");
        db.execSQL("DROP TRIGGER IF EXISTS update_note_modified_date_on_update");
        // add a column for gtask id    在笔记表中添加用于谷歌任务的id列
        db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.GTASK_ID
                + " TEXT NOT NULL DEFAULT ''");
        // add a trash system folder    添加一个垃圾箱系统文件
        ContentValues values = new ContentValues();     // 创建ContentValues对象
        values.put(NoteColumns.ID, Notes.ID_TRASH_FOLER);       // 设置垃圾箱文件夹的ID
        values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);        // 设置类型为系统文件夹
        db.insert(TABLE.NOTE, null, values);        // 将垃圾箱文件夹插入到笔记表中
    }

    // 升级到版本4的方法
    private void upgradeToV4(SQLiteDatabase db) {
        // 在笔记表中添加版本列
        //这行代码执行一个 SQL 命令，使用 ALTER TABLE 语句来修改 TABLE.NOTE 表
        //ADD COLUMN 指令用于添加新列
        //NoteColumns.VERSION 是新列的名称，应该是一个整型（INTEGER）
        //NOT NULL 约束确保该列不能为空
        //DEFAULT 0 表示新列的默认值为0，这意味着如果未提供值，则该列会自动设置为0
        db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.VERSION
                + " INTEGER NOT NULL DEFAULT 0");
    }
}
