/*
 * 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.app.SearchManager;
import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Intent;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.text.TextUtils;
import android.util.Log;

import net.micode.notes.R;
import net.micode.notes.data.Notes.DataColumns;
import net.micode.notes.data.Notes.NoteColumns;
import net.micode.notes.data.NotesDatabaseHelper.TABLE;

/**
 * 笔记内容提供者，提供标准ContentProvider接口管理笔记数据
 * 功能包括：基础CRUD操作、搜索建议支持、数据变更通知
 */
public class NotesProvider extends ContentProvider {
 // URI匹配器，用于路由不同数据请求
    private static final UriMatcher mMatcher;

    private NotesDatabaseHelper mHelper;// 数据库帮助类实例

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

    private static final int URI_NOTE            = 1;// 笔记集合操作
    private static final int URI_NOTE_ITEM       = 2; // 单个笔记操作
    private static final int URI_DATA            = 3;// 数据项集合操作
    private static final int URI_DATA_ITEM       = 4;// 单个数据项操作

    private static final int URI_SEARCH          = 5; // 全文搜索
    private static final int URI_SEARCH_SUGGEST  = 6;// 搜索建议
// 初始化URI匹配规则
    static {
        mMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        mMatcher.addURI(Notes.AUTHORITY, "note", URI_NOTE);
        mMatcher.addURI(Notes.AUTHORITY, "note/#", URI_NOTE_ITEM);
        mMatcher.addURI(Notes.AUTHORITY, "data", URI_DATA);
        mMatcher.addURI(Notes.AUTHORITY, "data/#", URI_DATA_ITEM);
        mMatcher.addURI(Notes.AUTHORITY, "search", URI_SEARCH);
         // 系统搜索建议标准URI
        mMatcher.addURI(Notes.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY, URI_SEARCH_SUGGEST);
        mMatcher.addURI(Notes.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY + "/*", URI_SEARCH_SUGGEST);
    }
 /**
     * 搜索建议投影映射：
     * - 将数据库字段映射到系统搜索建议需要的字段
     * - x'0A'代表SQLite中的换行符，去除换行和空格以优化显示
     */
    /**
     * x'0A' represents the '\n' character in sqlite. For title and content in the search result,
     * we will trim '\n' and white space in order to show more information.
     */
    private static final String NOTES_SEARCH_PROJECTION = NoteColumns.ID + ","// 原始ID
        + NoteColumns.ID + " AS " + SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA + ","// 建议项携带数据
        + "TRIM(REPLACE(" + NoteColumns.SNIPPET + ", x'0A','')) AS " + SearchManager.SUGGEST_COLUMN_TEXT_1 + ","// 主文本
        + "TRIM(REPLACE(" + NoteColumns.SNIPPET + ", x'0A','')) AS " + SearchManager.SUGGEST_COLUMN_TEXT_2 + "," // 副文本
        + R.drawable.search_result + " AS " + SearchManager.SUGGEST_COLUMN_ICON_1 + ","// 建议图标
        + "'" + Intent.ACTION_VIEW + "' AS " + SearchManager.SUGGEST_COLUMN_INTENT_ACTION + ","// 点击动作
        + "'" + Notes.TextNote.CONTENT_TYPE + "' AS " + SearchManager.SUGGEST_COLUMN_INTENT_DATA; // 数据类型
// 笔记片段搜索SQL查询（排除回收站且类型为普通笔记）
    private static String NOTES_SNIPPET_SEARCH_QUERY = "SELECT " + NOTES_SEARCH_PROJECTION
        + " FROM " + TABLE.NOTE
        + " WHERE " + NoteColumns.SNIPPET + " LIKE ?"// 模糊查询
        + " AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER// 过滤回收站
        + " AND " + NoteColumns.TYPE + "=" + Notes.TYPE_NOTE; // 仅普通笔记类型


    @Override
    public boolean onCreate() {
         // 初始化数据库帮助类（单例模式）
        mHelper = NotesDatabaseHelper.getInstance(getContext());
        return true;
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
            String sortOrder) {
        Cursor c = null;
        SQLiteDatabase db = mHelper.getReadableDatabase();
        String id = null;
         // 根据URI类型路由处理
        switch (mMatcher.match(uri)) {
            case URI_NOTE: // 查询所有笔记
                c = db.query(TABLE.NOTE, projection, selection, selectionArgs, null, null,
                        sortOrder);
                break;
            case URI_NOTE_ITEM:// 查询单个笔记
                id = uri.getPathSegments().get(1);
                c = db.query(TABLE.NOTE, projection, NoteColumns.ID + "=" + id// 从URI路径获取ID
                        + parseSelection(selection), selectionArgs, null, null, sortOrder);
                break;
            case URI_DATA:// 查询所有数据项
                c = db.query(TABLE.DATA, projection, selection, selectionArgs, null, null,
                        sortOrder);
                break;
            case URI_DATA_ITEM:// 查询单个数据项
                id = uri.getPathSegments().get(1);
                c = db.query(TABLE.DATA, projection, DataColumns.ID + "=" + id
                        + parseSelection(selection), selectionArgs, null, null, sortOrder);
                break;
            case URI_SEARCH:// 处理搜索请求
            case URI_SEARCH_SUGGEST: // 处理搜索建议请求
            // 验证参数完整性
                if (sortOrder != null || projection != null) {
                    throw new IllegalArgumentException(
                            "do not specify sortOrder, selection, selectionArgs, or projection" + "with this query");
                }
            // 解析搜索关键词
                String searchString = null;
                if (mMatcher.match(uri) == URI_SEARCH_SUGGEST) {
                     // 从建议URI路径获取：content://auth/search_suggest_query/关键词
                    if (uri.getPathSegments().size() > 1) {
                        searchString = uri.getPathSegments().get(1);
                    }
                } else {
                     // 从查询参数获取：content://auth/search?pattern=关键词
                    searchString = uri.getQueryParameter("pattern");
                }

                if (TextUtils.isEmpty(searchString)) {
                    return null; // 空搜索直接返回
                }

                try {
                     // 构造模糊查询参数（前后加%）
                    searchString = String.format("%%%s%%", searchString);
                     // 执行原始SQL查询（参数化防止注入）
                    c = db.rawQuery(NOTES_SNIPPET_SEARCH_QUERY,
                            new String[] { searchString });
                } catch (IllegalStateException ex) {
                    Log.e(TAG, "got exception: " + ex.toString());
                }
                break;
            default:
                throw new IllegalArgumentException("Unknown URI " + uri);
        }
         // 设置数据变更通知URI（重要：使CursorLoader能自动刷新）
        if (c != null) {
            c.setNotificationUri(getContext().getContentResolver(), uri);
        }
        return c;
    }
/**
     * 插入新数据项
     * @param uri 目标URI（note或data表）
     * @param values 要插入的数据值
     * @return 新创建项的URI
     */
    @Override
    public Uri insert(Uri uri, ContentValues values) {
        SQLiteDatabase db = mHelper.getWritableDatabase();
        long dataId = 0, noteId = 0, insertedId = 0;
        switch (mMatcher.match(uri)) {
            case URI_NOTE: // 插入新笔记
                insertedId = noteId = db.insert(TABLE.NOTE, null, values);
                break;
            case URI_DATA: // 插入笔记关联数据
                if (values.containsKey(DataColumns.NOTE_ID)) {
                    noteId = values.getAsLong(DataColumns.NOTE_ID);
                } else {
                    Log.d(TAG, "Wrong data format without note id:" + values.toString());
                }
                insertedId = dataId = db.insert(TABLE.DATA, null, values);
                break;
            default:
                throw new IllegalArgumentException("Unknown URI " + uri);
        }
        // Notify the note uri// 发送数据变更通知
        if (noteId > 0) {// 通知笔记URI变更（触发CursorLoader刷新）
            getContext().getContentResolver().notifyChange(
                    ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), null);
        }

        // Notify the data uri// 通知数据URI变更
        if (dataId > 0) {
            getContext().getContentResolver().notifyChange(
                    ContentUris.withAppendedId(Notes.CONTENT_DATA_URI, dataId), null);
        }
// 返回新创建项的完整URI（如content://auth/note/123）
        return ContentUris.withAppendedId(uri, insertedId);
    }
/**
     * 删除数据项
     * @param uri 目标URI（可指定单个项或集合）
     * @return 删除的行数
     */
    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        int count = 0;
        String id = null;
        SQLiteDatabase db = mHelper.getWritableDatabase();
        boolean deleteData = false;// 标记是否删除的是data表数据
        switch (mMatcher.match(uri)) {
            case URI_NOTE:// 删除多个笔记
                // 防止删除系统文件夹（ID>0的条件）
                selection = "(" + selection + ") AND " + NoteColumns.ID + ">0 ";
                count = db.delete(TABLE.NOTE, selection, selectionArgs);
                break;
            case URI_NOTE_ITEM:// 删除单个笔记
                id = uri.getPathSegments().get(1);
                /**
                 * ID that smaller than 0 is system folder which is not allowed to
                 * trash
                 */
                long noteId = Long.valueOf(id); // 系统文件夹（ID<=0）不允许删除
                if (noteId <= 0) {
                    break;
                }
                count = db.delete(TABLE.NOTE,
                        NoteColumns.ID + "=" + id + parseSelection(selection), selectionArgs);
                break;
            case URI_DATA:// 删除多个数据项
                count = db.delete(TABLE.DATA, selection, selectionArgs);
                deleteData = true;
                break;
            case URI_DATA_ITEM:// 删除单个数据项
                id = uri.getPathSegments().get(1);
                count = db.delete(TABLE.DATA,
                        DataColumns.ID + "=" + id + parseSelection(selection), selectionArgs);
                deleteData = true;
                break;
            default:
                throw new IllegalArgumentException("Unknown URI " + uri);
        }
        // 发送通知（数据变更可能影响笔记显示）
        if (count > 0) {
            if (deleteData) {
                // 数据变更需要通知笔记列表更新
                getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null);
            } // 通知当前URI对应的数据变更
            getContext().getContentResolver().notifyChange(uri, null);
        }
        return count;
    }
/**
     * 更新数据项
     * @param uri 目标URI
     * @param values 新数据值
     * @return 更新的行数
     */
    @Override
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
        int count = 0;
        String id = null;
        SQLiteDatabase db = mHelper.getWritableDatabase();
        boolean updateData = false;// 标记是否更新data表
        switch (mMatcher.match(uri)) {
            case URI_NOTE: // 批量更新笔记
                increaseNoteVersion(-1, selection, selectionArgs);
                count = db.update(TABLE.NOTE, values, selection, selectionArgs);
                break;
            case URI_NOTE_ITEM: // 更新单个笔记
                id = uri.getPathSegments().get(1);
                increaseNoteVersion(Long.valueOf(id), selection, selectionArgs);
                count = db.update(TABLE.NOTE, values, NoteColumns.ID + "=" + id
                        + parseSelection(selection), selectionArgs);
                break;
            case URI_DATA: // 更新多个数据项
                count = db.update(TABLE.DATA, values, selection, selectionArgs);
                updateData = true;
                break;
            case URI_DATA_ITEM:// 更新单个数据项
                id = uri.getPathSegments().get(1);
                count = db.update(TABLE.DATA, values, DataColumns.ID + "=" + id
                        + parseSelection(selection), selectionArgs);
                updateData = true;
                break;
            default:
                throw new IllegalArgumentException("Unknown URI " + uri);
        }
// 发送数据变更通知
        if (count > 0) {
            if (updateData) {
                // 数据变更需要更新关联笔记
                getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null);
            }
            getContext().getContentResolver().notifyChange(uri, null);
        }
        return count;
    }
/**
     * 合并基本选择条件
     * @param selection 原始选择条件
     * @return 格式化后的条件语句
     */
    private String parseSelection(String selection) {
        return (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : "");
    }

    /**
     * 增加笔记版本号（实现乐观锁机制）
     * @param id 笔记ID（-1表示批量更新）
     * @param selection 选择条件
     * @param selectionArgs 条件参数
     */
    private void increaseNoteVersion(long id, String selection, String[] selectionArgs) {
        StringBuilder sql = new StringBuilder(120);
        sql.append("UPDATE ");
        sql.append(TABLE.NOTE);
        sql.append(" SET ");
        sql.append(NoteColumns.VERSION);
        sql.append("=" + NoteColumns.VERSION + "+1 ");
 // 构造WHERE条件
        if (id > 0 || !TextUtils.isEmpty(selection)) {
            sql.append(" WHERE ");
        }
        if (id > 0) {
            sql.append(NoteColumns.ID + "=" + String.valueOf(id));
        } // 处理选择条件（手动替换参数防止注入）
        if (!TextUtils.isEmpty(selection)) {
            String selectString = id > 0 ? parseSelection(selection) : selection;
            for (String args : selectionArgs) {
                selectString = selectString.replaceFirst("\\?", args);
            }
            sql.append(selectString);
        }
 // 执行原生SQL更新（绕过常规更新流程）
        mHelper.getWritableDatabase().execSQL(sql.toString());
    }

    @Override
    public String getType(Uri uri) {
        // TODO Auto-generated method stub// 根据URI返回MIME类型（当前未实现）
        return null;
    }

}
