package com.imofan.android.basic.config;

import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.apache.http.HttpResponse;
import org.apache.http.ParseException;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.json.JSONException;
import org.json.JSONObject;

import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.util.Log;

import com.imofan.android.basic.config.MFConfigListener;

public class MFConfigService {
	/**
	 * 在线配置服务类，用于获取在魔方后台配置的各种参数,在Context对象的onCreate中调用
	 * {@link #updateConfig(Context, MFConfigListener)}方法，更新本地的在线配置参数,调用
	 * {@link #getConfig(String)}获取某一个key对象的配置参数
	 * 
	 * @author liuyx
	 */
		private static SharedPreferences pref = null;
		private static String PREF_NAME = "mofan.config";
		private static String baseUrl;
		private static Map<String, String> receiveMap = new HashMap<String, String>();
		private static Map<String, String> changeMap = new HashMap<String, String>();

		private MFConfigService() {
		}

		/**
		 * 
		 * @return 返回MFConfigService的实例，在多线程环境下也能保证单例
		 */
		public static MFConfigService getInstance() {

			return Instance.service;
		}

		private static class Instance {
			static MFConfigService service = new MFConfigService();
		}

		/**
		 * 更新在线配置参数，需要用户传入实现{@link com.imofan.android.basic.config.MFConfigListener}
		 * 接口的对象和Context对象，然后该方法将自动与网络连接，
		 * 比较网络上与本地的配置参数是否一致，若参数发生变化了，自动更新与网络上的配置参数一致，若用户想获取相应的Config值，可以查看
		 * {@link #getConfig(String)}
		 * 
		 * @param context
		 *            android.content.Context对象
		 * @param configListener
		 *            实现MFConfigListener接口的对象
		 */
		public void updateConfig(final Context context,
				final MFConfigListener configListener) {
			if (context == null){
				Log.e("MFConfigService", "请传入正确的Context对象");
			}
			initUrlAndAppKey(context);
			pref = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
			update(context, configListener);
		}

		private void update(final Context context,
				final MFConfigListener configListener) {
			ExecutorService exec = Executors.newCachedThreadPool();
			exec.execute(new Runnable() {

				@Override
				public void run() {
					try {
						Editor editor = pref.edit();
						String getStringFromServ = getRequest(baseUrl);
						
						if(onReceiveJson != null){
							onReceiveJson.onReceive(getStringFromServ);
						}
						
						JSONObject json = new JSONObject(getStringFromServ);
						getValueFromJSONObj(json);
						editor.commit();
						if (configListener != null) {
							configListener.onReceived(context, receiveMap);
							configListener.onChanged(context, changeMap);
						}
					} catch (Exception e) {
						e.printStackTrace();
						if (configListener != null) {
							// 当网络出现异常，调用onFailed方法
							configListener.onFailed(context);
						}
					}
				}

			});
		}

		/**
		 * 更新在线配置参数，需要用户传入Context对象，然后该方法将自动与网络连接，
		 * 比较网络上与本地的配置参数是否一致，若参数发生变化了，自动更新与网络上的配置参数一致，若用户想获取相应的Config值，可以查看
		 * {@link #getConfig(String)}
		 * 
		 * @param context
		 *            android.content.Context对象
		 * @param configListener
		 *            实现MFConfigListener接口的对象
		 */
		public void updateConfig(Context context) {
			updateConfig(context, null);
		}

		private void initUrlAndAppKey(Context context) {
			String app_key = null;
			try {
				ApplicationInfo info = context.getPackageManager()
						.getApplicationInfo(context.getPackageName(),
								PackageManager.GET_META_DATA);
				app_key = (String) info.metaData.get("MOFANG_APPKEY");
				baseUrl = "http://m.imofan.com/online_config/?app_key=" + app_key;
			} catch (NameNotFoundException e) {
				Log.e("MFConfigService", "没有获取到appKey : "+ app_key);
			}
		}

		/**
		 * 获取与key对象对应的那个Value值，同Map对象的Key-Vlaue值一致，若key值为空或者传入错误的key值，则返回空字符串
		 * 
		 * @param key
		 *            参数key
		 * @return 参数值
		 */
		public String getConfig(String key) {
			if (pref == null) {
				return "";
			}
			return pref.getString(key, "");
		}

		/**
		 * 
		 * @param url
		 *            发送Get请求的Url
		 * @return 服务器响应的字符串
		 * @throws IOException
		 * @throws ClientProtocolException
		 *             Signals an error in the HTTP protocol.
		 * @throws IOException
		 */
		private String getRequest(final String url) throws ClientProtocolException,
				IOException, ParseException {
			if (url.equals("") || url == null)
				return "";
			try{
				HttpClient client = new DefaultHttpClient();
				HttpGet get = new HttpGet(url);
				HttpResponse response = client.execute(get);
				if (response.getStatusLine().getStatusCode() == 200) {
					String result = EntityUtils.toString(response.getEntity());
					return result;
				}
			}catch(Exception e){
				e.printStackTrace();
			}
			return "";
		}
		

		private void getValueFromJSONObj(JSONObject json) throws JSONException {
			@SuppressWarnings("unchecked")
			Iterator<String> iter = json.keys();
			Editor editor = pref.edit();

			while (iter.hasNext()) {
				String key = iter.next();
				String value = json.optString(key);
				receiveMap.put(key, value);
				if (!pref.contains(key) || !pref.getString(key, "").equals(value)) {
					editor.putString(key, value);
					editor.commit();
					changeMap.put(key, value);
				}
			}
		}
		
		/**
		 * 设置从线上拿到json数据后处理的监听器
		 * @param onReceiveJson
		 */
		public void setOnReceiveJSON(OnReceiveJson onReceiveJson){
			this.onReceiveJson = onReceiveJson;
		}
		
		private OnReceiveJson onReceiveJson;
		
		/**
		 * 接受到json后处理json
		 * @author user
		 *
		 */
		public static interface OnReceiveJson{
			void onReceive(String json);
		}

}
