/*
 * 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;//表示在哪个包，依赖关系
//以下几个是导入Android自带的几个库文件
import android.content.Context;//Context类是Android自带的类，就用import android.content.Context;将它导入
import android.database.Cursor;//1.从数据库导入Cursor,Cursor 是一个随机的数据源,是 每行的集合。封装鼠标光标的位图表示形式的类。
import android.provider.ContactsContract.CommonDataKinds.Phone;//Android系统应用开发框架功能之一，提供访问Android内容提供者的类。导入里面的联系人的号码，这个是需要CommonDataKinds提供权限的。
import android.provider.ContactsContract.Data;//.导入data。（Data：存储通讯录中每个人的全部信息，什么名字，电话，E-mail等）
import android.telephony.PhoneNumberUtils;//Telephony 服务为电话应用程序编程接口 (TAPI) 提供支持。通过使用此硬件，您可以通过直接连接到本地计算机、电话线、LAN、WAN 和 Internet 以进行通信。提供处理Phone Number的各种应用工具
import android.util.Log;//安卓日志输出工具类

import java.util.HashMap;//引用了STL里面的HashMap，用来映射联系人和电话号码

public class Contact {//该类用于创建联系人信息，主要用于增加联系人信息
    private static HashMap<String, String> sContactCache;//存储联系人及对应的电话号码，作为缓存用的
    private static final String TAG = "Contact";//私有的字符串常量；.java自定义标签TAG指向Contact； 这个变量可以用在Log打印日志时表明由哪个类打印的日志

    private static final String CALLER_ID_SELECTION = "PHONE_NUMBERS_EQUAL(" + Phone.NUMBER
    + ",?) AND " + Data.MIMETYPE + "='" + Phone.CONTENT_ITEM_TYPE + "'"//定义字符串CALLER_ID_SELECTION，用于匹配查找联系人；定义字符串CALLER_ID_SELECTION。id选择器，包括号码，数据类型，对应联系人
    + " AND " + Data.RAW_CONTACT_ID + " IN "//RawContact表每行为每个用户存储了联系信息，当插入一个raw contact或当一个raw contact所属的一个data改变时，系统会检查这个raw contact跟其他的raw contact是否可以匹配（比如，如果两个raw contact的data包含相同的电话号码或名字），如果匹配他们就会被综合到一起，也就是说他们会属于同一个cantact，表现为在RawContact表中他们引用的cantact_id是一样的
            + "(SELECT raw_contact_id "
            + " FROM phone_lookup"
            + " WHERE min_match = '+')";

    public static String getContact(Context context, String phoneNumber) {//获取联系人
        if(sContactCache == null) {//如果联系人缓存为空，重新从HashMap载入，包括数据类型
            sContactCache = new HashMap<String, String>();//初始化哈希表，对联系人缓存表进行初始化
        }

        if(sContactCache.containsKey(phoneNumber)) {//查找HashMap中是否已有phoneNumber信息,直接返回
            return sContactCache.get(phoneNumber);//没找到需要在数据库中进一步查找；查找数据库中phoneNumber的信息
        }
        //缓存中没有找到，就到数据库中去找。下面代码就是执行到数据库中查找的操作
        String selection = CALLER_ID_SELECTION.replace("+",//作为下面函数的一个参数， 为返回的内容设置条件
                PhoneNumberUtils.toCallerIDMinMatch(phoneNumber));
        Cursor cursor = context.getContentResolver().query(//从数据库中读取数据。cursor类是对数据库的操作，获取整行的数据.Ressolver是对联系人内容的读取，其中provider提供了联系人数据
                Data.CONTENT_URI,//Contacts.CONTENT_URI就是提供联系人的内容的地址
                new String [] { Phone.DISPLAY_NAME },//这个参数告诉查询要返回的列（Column），Contacts Provider提供了联系人的ID和联系人的NAME等内容，在这里，我们只需要NAME，所以提供这个参数DISPLAY_NAME
                selection,//selection，设置条件，相当于SQL语句中的where
                new String[] { phoneNumber },// 配合上一个参数使用，若上一个参数里有‘？’则替换掉‘？’符号，但是在这里，由于上一个参数没有设置，所以在这里就是依据phoneNumber作为参数
                null);//判断查询结果，然后执行movtoFirst

        if (cursor != null && cursor.moveToFirst()) {//.找到对应的信息
            try {//联系人姓名，并将相关信息存入cache中
                String name = cursor.getString(0);//从内容中获取联系人姓名
                sContactCache.put(phoneNumber, name);//把名字和号码存到联系人缓存中
                return name;//返回名字
            } catch (IndexOutOfBoundsException e) {//参数越界异常
                Log.e(TAG, " Cursor get string error " + e.toString());//引入的util.log就是java自带的日志输出工具，而log.e则代表error，显示的颜色为红色
                return null;
            } finally {//finally块通常用于try内，无论是否发生异常都会执行finally模块，因此多使用 finally 代码块执行关闭连接、关闭文件和释放线程的的操作。
                cursor.close();//关闭数据库访问；关闭cursor游标
            }
        } else {//在数据库和HashMap中都没有找到 返回空指针
            Log.d(TAG, "No contact matched with number:" + phoneNumber);//联系人中没有匹配到该手机号码的主人
            return null;//返回空
        }
    }
}
