/*
 * 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;
import android.database.sqlite.SQLiteDatabase;
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;


public class NotesDatabaseHelper extends SQLiteOpenHelper {
    //    数据库帮助类，用于管理名为 note.db 的 SQLite 数据库。
//    它继承自 SQLiteOpenHelper 类，这是 Android提供的一个方便的工具类，用于管理数据库的创建和版本更新.
    // 数据库的基本信息；数据库名称和版本信息（在创建实例对象时会用到）
    private static final String DB_NAME = "note.db";

    private static final int DB_VERSION = 4;

    //内部接口：个人理解为两个表名，一个note，一个data
    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;

    /* 以下都是一些SQL语句，辅助我们来对数据库进行操作 */
    //创建note表的语句，这里的NoteColumns就是我们刚刚在Notes中定义的一个接口，里面定义了一系列静态的数据库表中的列名
    private static final String CREATE_NOTE_TABLE_SQL =
            "CREATE TABLE " + TABLE.NOTE + "(" +
                    NoteColumns.ID + " INTEGER PRIMARY KEY," +
                    NoteColumns.PARENT_ID + " INTEGER NOT NULL DEFAULT 0," +
                    NoteColumns.ALERTED_DATE + " INTEGER NOT NULL DEFAULT 0," +
                    NoteColumns.BG_COLOR_ID + " INTEGER NOT NULL DEFAULT 0," +
                    NoteColumns.CREATED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," +
                    NoteColumns.HAS_ATTACHMENT + " INTEGER NOT NULL DEFAULT 0," +
                    NoteColumns.MODIFIED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," +
                    NoteColumns.NOTES_COUNT + " INTEGER NOT NULL DEFAULT 0," +
                    NoteColumns.SNIPPET + " TEXT NOT NULL DEFAULT ''," +
                    NoteColumns.TYPE + " INTEGER NOT NULL DEFAULT 0," +
                    NoteColumns.WIDGET_ID + " INTEGER NOT NULL DEFAULT 0," +
                    NoteColumns.WIDGET_TYPE + " INTEGER NOT NULL DEFAULT -1," +
                    NoteColumns.SYNC_ID + " INTEGER NOT NULL DEFAULT 0," +
                    NoteColumns.LOCAL_MODIFIED + " INTEGER NOT NULL DEFAULT 0," +
                    NoteColumns.ORIGIN_PARENT_ID + " INTEGER NOT NULL DEFAULT 0," +
                    NoteColumns.GTASK_ID + " TEXT NOT NULL DEFAULT ''," +
                    NoteColumns.VERSION + " INTEGER NOT NULL DEFAULT 0" +
                    ")";

    //同上，创建data表的语句，这里的DataColumns就是我们刚刚在Notes中定义的一个接口，里面定义了一系列静态的数据库表中的列名
    private static final String CREATE_DATA_TABLE_SQL =
            "CREATE TABLE " + TABLE.DATA + "(" +
                    DataColumns.ID + " INTEGER PRIMARY KEY," +
                    DataColumns.MIME_TYPE + " TEXT NOT NULL," +
                    DataColumns.NOTE_ID + " INTEGER NOT NULL DEFAULT 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," +
                    DataColumns.DATA2 + " INTEGER," +
                    DataColumns.DATA3 + " TEXT NOT NULL DEFAULT ''," +
                    DataColumns.DATA4 + " TEXT NOT NULL DEFAULT ''," +
                    DataColumns.DATA5 + " TEXT NOT NULL DEFAULT ''" +
                    ")";

    // 功能简介：
    // 创建一个以note的ID为索引
    // 解读：
    // 用于在TABLE.DATA表上创建一个名为note_id_index的索引。
    // 这个索引是基于DataColumns.NOTE_ID列的。IF NOT EXISTS确保了如果索引已经存在，那么就不会尝试重新创建它，避免了可能的错误。
    // 索引通常用于提高查询性能，特别是在对某个字段进行频繁查询时。
    private static final String CREATE_DATA_NOTE_ID_INDEX_SQL =
            "CREATE INDEX IF NOT EXISTS note_id_index ON " +
                    TABLE.DATA + "(" + DataColumns.NOTE_ID + ");";

    /* 以下是一些对便签增删改定义的触发器 */
    /* 总结
     * 这些触发器都是用来维护NOTE表和与之相关联的DATA表之间数据一致性的。
     * 当在NOTE表中发生删除或更新操作时，这些触发器会自动执行相应的数据清理或更新操作，确保数据库中的数据保持正确和一致。
     * 特别是在处理文件夹和回收站等逻辑时，这些触发器起到了非常重要的作用，可以自动管理数据的移动和删除。*/
    /**
     * Increase folder's note count when move note to the folder
     */
    // 功能简介：
    // 添加触发器：增加文件夹的便签个数记录（因为我们会移动便签进入文件夹，这时候文件夹的计数要进行更新）
    // 解读：
    // 定义了一个SQL触发器increase_folder_count_on_update。
    // 触发器是一种特殊的存储过程，它会在指定表上的指定事件（如INSERT、UPDATE、DELETE）发生时自动执行。
    // 这个触发器会在TABLE.NOTE表的NoteColumns.PARENT_ID字段更新后执行。
    // 触发器的逻辑是：当某个笔记的PARENT_ID（即父文件夹ID）被更新时，它会找到对应的文件夹（通过新的PARENT_ID），并将该文件夹的NOTES_COUNT（即笔记数）增加1。
    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 + ";" +
                    " END";

    /**
     * Decrease folder's note count when move note from folder
     */
    // 功能简介：（触发器和上面的 “增加文件夹的便签个数记录” 同理，就不细节解读了）
    // 添加触发器：减少文件夹的便签个数记录（因为我们会移动便签移出文件夹，这时候文件夹的计数要进行更新）
    private static final String NOTE_DECREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER =
            "CREATE TRIGGER decrease_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 + "=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 " +
                    "  UPDATE " + TABLE.NOTE +
                    "   SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + " + 1" +
                    "  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 " +
                    "  UPDATE " + TABLE.NOTE +
                    "   SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + "-1" +
                    "  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}
     */
    // 功能简介：
    // 添加触发器：当向DATA表中插入类型为NOTE（便签）的数据时，更新note表对应的笔记内容。
    // 解读：
    // 在DATA表上进行INSERT操作后，如果新插入的数据的MIME_TYPE为NOTE，则触发此操作。
    // 它会更新NOTE表，将与新插入数据相关联的标签的SNIPPET（摘要）字段设置为新插入数据的CONTENT字段的值
    private static final String DATA_UPDATE_NOTE_CONTENT_ON_INSERT_TRIGGER =
            "CREATE TRIGGER update_note_content_on_insert " +
                    " AFTER INSERT ON " + TABLE.DATA +
                    " WHEN new." + DataColumns.MIME_TYPE + "='" + DataConstants.NOTE + "'" +
                    " BEGIN" +
                    "  UPDATE " + TABLE.NOTE +
                    "   SET " + NoteColumns.SNIPPET + "=new." + DataColumns.CONTENT +
                    "  WHERE " + NoteColumns.ID + "=new." + DataColumns.NOTE_ID + ";" +
                    " END";

    /**
     * Update note's content when data with {@link DataConstants#NOTE} type has changed
     */
    // 功能简介：
    // 添加触发器：当DATA表中，类型为NOTE（便签）的数据更改时，更新note表对应的笔记内容。
    // 解读：
    // 在DATA表上进行UPDATE操作后，如果更新前的数据的MIME_TYPE为NOTE，则触发此操作。
    // 它会更新NOTE表，将与更新后的数据相关联的笔记的SNIPPET字段设置为新数据的CONTENT字段的值
    private static final String DATA_UPDATE_NOTE_CONTENT_ON_UPDATE_TRIGGER =
            "CREATE TRIGGER update_note_content_on_update " +
                    " AFTER UPDATE ON " + TABLE.DATA +
                    " WHEN old." + DataColumns.MIME_TYPE + "='" + DataConstants.NOTE + "'" +
                    " BEGIN" +
                    "  UPDATE " + TABLE.NOTE +
                    "   SET " + NoteColumns.SNIPPET + "=new." + DataColumns.CONTENT +
                    "  WHERE " + NoteColumns.ID + "=new." + DataColumns.NOTE_ID + ";" +
                    " END";

    /**
     * Update note's content when data with {@link DataConstants#NOTE} type has deleted
     */
    // 功能简介：
    // 添加触发器：当DATA表中，类型为NOTE（便签）的数据删除时，更新note表对应的笔记内容（置空）。
    // 解读：
    // 在DATA表上进行DELETE操作后，如果删除的数据的MIME_TYPE为NOTE，则触发此操作。
    // 它会更新NOTE表，将与删除的数据相关联的笔记的SNIPPET字段设置为空字符串。
    private static final String DATA_UPDATE_NOTE_CONTENT_ON_DELETE_TRIGGER =
            "CREATE TRIGGER update_note_content_on_delete " +
                    " AFTER delete ON " + TABLE.DATA +
                    " WHEN old." + DataColumns.MIME_TYPE + "='" + DataConstants.NOTE + "'" +
                    " BEGIN" +
                    "  UPDATE " + TABLE.NOTE +
                    "   SET " + NoteColumns.SNIPPET + "=''" +
                    "  WHERE " + NoteColumns.ID + "=old." + DataColumns.NOTE_ID + ";" +
                    " END";

    /**
     * Delete datas belong to note which has been deleted
     */
    // 功能简介：
    // 添加触发器：当从NOTE表中删除笔记时，删除与该笔记相关联的数据（就是删除data表中为该note的数据）
    // 解读：
    // 在NOTE表上进行DELETE操作后，此触发器被激活。
    // 它会从DATA表中删除所有与已删除的笔记（由old.ID表示）相关联的数据行（通过比较DATA表中的NOTE_ID字段与已删除笔记的ID来实现）
    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
     */
    // 功能简介：
    // 添加触发器：当从NOTE表中删除一个文件夹时，删除该文件夹下的所有笔记。
    // 解读：
    // 在NOTE表上进行DELETE操作后，如果删除的是一个文件夹（由old.ID表示）
    // 触发器会删除所有以该文件夹为父级（PARENT_ID）的笔记（通过比较NOTE表中的PARENT_ID字段与已删除文件夹的ID来实现）
    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
     */
    // 功能简介：
    // 添加触发器：当某个文件夹被移动到回收站时，移动该文件夹下的所有笔记到回收站
    // 解读：
    // 在NOTE表上进行UPDATE操作后，如果某个文件夹的新PARENT_ID字段值等于回收站的ID（Notes.ID_TRASH_FOLER）
    // 触发器会更新所有以该文件夹为父级（PARENT_ID）的笔记，将它们也移动到回收站。
    private static final String FOLDER_MOVE_NOTES_ON_TRASH_TRIGGER =
            "CREATE TRIGGER folder_move_notes_on_trash " +
                    " AFTER UPDATE ON " + TABLE.NOTE +
                    " WHEN new." + NoteColumns.PARENT_ID + "=" + Notes.ID_TRASH_FOLER +
                    " BEGIN" +
                    "  UPDATE " + TABLE.NOTE +
                    "   SET " + NoteColumns.PARENT_ID + "=" + Notes.ID_TRASH_FOLER +
                    "  WHERE " + NoteColumns.PARENT_ID + "=old." + NoteColumns.ID + ";" +
                    " END";

    // 构造器
    public NotesDatabaseHelper(Context context) {
        super(context, DB_NAME, null, DB_VERSION);
    }

    // 创建note（标签）表
    public void createNoteTable(SQLiteDatabase db) {
        db.execSQL(CREATE_NOTE_TABLE_SQL);
        reCreateNoteTableTriggers(db);
        createSystemFolder(db);
        Log.d(TAG, "note table has been created");
    }

    // 重新创建或更新与笔记表相关的触发器。
    // 首先，使用DROP TRIGGER IF EXISTS语句删除已存在的触发器。确保在重新创建触发器之前，不存在同名的触发器。
    // 然后，使用db.execSQL()方法执行预定义的SQL语句，这些语句用于创建新的触发器。
    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);
    }

    /* 以下部分是操作SQLite数据库部分 */
    // 功能简介：
    // 创建通话记录文件夹、默认文件夹、临时文件夹和回收站，并插入相关数据
    // 具体解读：
    // ContentValues是一个用于存储键值对的类，常用于SQLite数据库的插入操作
    // values.put方法可以向ContentValues对象中添加数据。
    // NoteColumns.ID是存储文件夹ID的列名，Notes.ID_CALL_RECORD_FOLDER是通话记录文件夹的ID。
    // NoteColumns.TYPE是存储文件夹类型的列名，Notes.TYPE_SYSTEM表示这是一个系统文件夹。
    // 使用db.insert方法将values中的数据插入到TABLE.NOTE（即标签表）中。
    // 每次插入新数据前，都使用values.clear()方法清除ContentValues对象中的旧数据，确保不会重复插入旧数据。
    // 然后分别创建默认文件夹、临时文件夹和回收站，并以同样的方法插入数据。
    private void createSystemFolder(SQLiteDatabase db) {
        ContentValues values = new ContentValues();

        /**
         * call record foler for call notes
         */
        values.put(NoteColumns.ID, Notes.ID_CALL_RECORD_FOLDER);
        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);
        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);
        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);
        values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);
        db.insert(TABLE.NOTE, null, values);
    }

    //功能简介：
    //创建data（数据）表
    //解读：
    //这个方法用于创建数据表，以及与之相关的触发器。
    //创建数据表：使用db.execSQL方法执行预定义的SQL语句CREATE_DATA_TABLE_SQL，用于创建数据表。
    //重新创建数据表触发器：调用reCreateDataTableTriggers方法，用于删除并重新创建与数据表相关的触发器。
    //创建索引：使用db.execSQL方法执行CREATE_DATA_NOTE_ID_INDEX_SQL语句，为数据表创建索引。
    //记录日志：使用Log.d方法记录一条调试级别的日志，表示数据表已经创建。
    public void createDataTable(SQLiteDatabase db) {
        db.execSQL(CREATE_DATA_TABLE_SQL);
        reCreateDataTableTriggers(db);
        db.execSQL(CREATE_DATA_NOTE_ID_INDEX_SQL);
        Log.d(TAG, "data table has been created");
    }

    //和上面的note表的reCreate...同理
    //重新创建或更新与笔记表相关的触发器。
    //首先，使用DROP TRIGGER IF EXISTS语句删除已存在的触发器。确保在重新创建触发器之前，不存在同名的触发器。
    //然后，使用db.execSQL()方法执行预定义的SQL语句，这些语句用于创建新的触发器。
    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);
    }

    //解读：
    //synchronized关键字确保在多线程环境下，只有一个线程能够进入这个方法，防止了同时创建多个实例的情况
    //getInstance(Context context)方法使用了单例模式来确保整个应用程序中只有一个NotesDatabaseHelper实例。
    //它首先检查mInstance（类的静态成员变量，没有在代码片段中显示）是否为null。
    //如果是null，则创建一个新的NotesDatabaseHelper实例，并将其赋值给mInstance。最后返回mInstance。
    static synchronized NotesDatabaseHelper getInstance(Context context) {
        if (mInstance == null) {
            mInstance = new NotesDatabaseHelper(context);
        }
        return mInstance;
    }

    //功能简介：
    //当数据库首次创建时，onCreate方法会被调用。
    //这里重写onCreate方法，它调用了上述createNoteTable(db)和createDataTable(db)两个方法
    //这样首次创建数据库时就多出了两张表。
    @Override
    public void onCreate(SQLiteDatabase db) {
        createNoteTable(db);
        createDataTable(db);
    }

    //功能简介：
    //当数据库需要升级时（即数据库的版本号改变），onUpgrade方法会被调用。
    //该方法会根据当前的oldVersion和新的newVersion来执行相应的升级操作
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        boolean reCreateTriggers = false;
        boolean skipV2 = false;

        if (oldVersion == 1) {
            upgradeToV2(db);
            skipV2 = true; // this upgrade including the upgrade from v2 to v3
            oldVersion++;
        }

        if (oldVersion == 2 && !skipV2) {
            upgradeToV3(db);
            reCreateTriggers = true;
            oldVersion++;
        }

        if (oldVersion == 3) {
            upgradeToV4(db);
            oldVersion++;
        }

        if (reCreateTriggers) {
            reCreateNoteTableTriggers(db);
            reCreateDataTableTriggers(db);
        }

        if (oldVersion != newVersion) { //数据库升级失败，抛出一个异常，表示数据库升级失败
            throw new IllegalStateException("Upgrade notes database to version " + newVersion
                    + "fails");
        }
    }

    //功能简介：
    // 将数据库从版本1升级到版本2。
    //解读：
    // 首先，它删除了已经存在的NOTE和DATA表（如果存在的话）。DROP TABLE IF EXISTS语句确保了即使这些表不存在，也不会抛出错误。
    // 然后，它调用了createNoteTable(db)和createDataTable(db)方法来重新创建这两个表。这意味着在升级到版本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);
    }

    //功能简介：
    // 将数据库从版本2（或可能是跳过版本2的某个状态）升级到版本3。
    //解读：
    // 首先，删除了三个不再使用的触发器（如果存在的话）。触发器是数据库中的一种对象，可以在插入、更新或删除记录时自动执行某些操作。
    // 然后，使用ALTER TABLE语句修改表结构，向NOTE表中添加了一个名为GTASK_ID的新列，并设置默认值为空字符串。
    // 最后，向NOTE表中插入了一条新的系统文件夹记录，表示一个名为“trash folder”的系统文件夹。这可能是用于存储已删除笔记的回收站功能。
    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
        db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.GTASK_ID
                + " TEXT NOT NULL DEFAULT ''");
        // add a trash system folder
        ContentValues values = new ContentValues();
        values.put(NoteColumns.ID, Notes.ID_TRASH_FOLER);
        values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);
        db.insert(TABLE.NOTE, null, values);
    }

    //功能简介：
    // 这个方法负责将数据库从版本3升级到版本4。
    //解读：
    // 它向NOTE表中添加了一个名为VERSION的新列，并设置了默认值为0。这个新列用于记录标签版本信息。
    private void upgradeToV4(SQLiteDatabase db) {
        db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.VERSION
                + " INTEGER NOT NULL DEFAULT 0");
    }
}