/**
 *  Copyright 2015 ZhaoHai <[email protected]>
 *  
 *  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.
 */

/**
 * @author zhaohai
 * @time 2015.10
 * ARSC编辑器主界面
 * */
package zhao.arsceditor;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.CharacterCodingException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.ContentValues;
import android.content.Context;
import android.content.DialogInterface;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.BaseAdapter;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import zhao.arsceditor.ResDecoder.ARSCCallBack;
import zhao.arsceditor.ResDecoder.data.ResTable;
import zhao.arsceditor.Translate.DoTranslate;

@SuppressWarnings("deprecation")
public class MainActivity extends Activity implements OnItemLongClickListener {

	// 存储字符串的集合
	public List<String> txtOriginal = new ArrayList<String>();
	// 存储修改后的字符串的集合
	public List<String> txtTranslated = new ArrayList<String>();
	// 存储字符串在资源中对应的键
	public List<String> txtTranslated_Key = new ArrayList<String>();
	// 列表控件
	public ListView stringListView;
	// 数据处理器
	public stringListAdapter mAdapter;
	// 存储资源Configs的集合
	public static List<String> Configs;
	// 存储资源种类的集合
	public static List<String> Types;
	// 存储资源的集合
	private List<ContentValues> RESOURCES = new ArrayList<ContentValues>();
	// 显示资源种类的文本控件
	private TextView textCategory;
	// 显示资源Config的文本框
	private TextView textConfig;
	// 用于在列表顶部显示信息的TextView控件
	private TextView info;
	// 翻译按钮
	private ImageView btnTranslate;
	// 搜索按钮
	private ImageView btnSearch;
	// 保存按钮
	private ImageView btnSave;
	// ARSC解析器
	private AndrolibResources mAndRes;
	// 字符串是否修改
	public boolean isChanged = false;
	// 资源类型
	private int ResType;
	// 资源类型常量
	public static final int ARSC = 0, AXML = 1, DEX = 2;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		// 设置主界面布局文件
		setContentView(R.layout.string_list);
		// 初始化列表控件
		stringListView = (ListView) findViewById(R.id.list_res_string);
		// 初始化显示资源类型的文本框
		textCategory = (TextView) findViewById(R.id.textCategory);
		// 初始化显示资源Config的文本框
		textConfig = (TextView) findViewById(R.id.textConfig);
		// 初始化翻译按钮
		btnTranslate = (ImageView) findViewById(R.id.btnTranslate);
		// 初始化搜索按钮
		btnSearch = (ImageView) findViewById(R.id.btnSearch);
		// 初始化保存按钮
		btnSave = (ImageView) findViewById(R.id.btnSave);
		// 获取用来显示信息的文本框
		info = (TextView) findViewById(R.id.info);
		// 为显示资源类型的文本框设置点击事件的监听器
		textCategory.setOnClickListener(MyOnClickListener);
		// 为显示资源Config的文本框设置点击事件的监听器
		textConfig.setOnClickListener(MyOnClickListener);
		// 为显示资源类型的文本框设置文本内容改变的监听器
		textCategory.addTextChangedListener(textWatcher);
		// 为显示资源Config的文本框设置文本内容改变的监听器
		textConfig.addTextChangedListener(textWatcher);
		// 为翻译按钮设置点击事件监听器
		btnTranslate.setOnClickListener(MyOnClickListener);
		// 为搜索按钮设置点击事件监听器
		btnSearch.setOnClickListener(MyOnClickListener);
		// 为保存按钮设置点击事件监听器
		btnSave.setOnClickListener(MyOnClickListener);
		// 初始化数据适配器
		mAdapter = new stringListAdapter(this);
		// 为列表控件设置数据适配器
		stringListView.setAdapter(mAdapter);
		// 为列表控件设置长按事件监听器
		stringListView.setOnItemLongClickListener(this);
		try {
			open("/sdcard/resources.arsc");
		} catch (IOException e) {
			showMessage(this, e.toString()).show();
		}
	}

	// 列表项目长按事件处理
	@Override
	public boolean onItemLongClick(AdapterView<?> arg0, View arg1, final int arg2, long arg3) {

		if (textCategory.getText().toString().equals("id")) {
			return false;
		}
		// 弹出一个对话框,显示一个翻译选项
		new AlertDialog.Builder(this).setItems(R.array.translate, new DialogInterface.OnClickListener() {
			@Override
			public void onClick(DialogInterface arg0, int arg1) {
				// 初始化翻译
				DoTranslate translateTask = new DoTranslate(txtOriginal, txtTranslated, false, MainActivity.this);
				// 开启翻译
				translateTask.init(arg2);
			}
		}).create().show();

		return true;
	}

	// 一些控件的点击事件监听器
	private OnClickListener MyOnClickListener = new OnClickListener() {
		@Override
		public void onClick(View arg0) {
			// TODO Auto-generated method stub
			switch (arg0.getId()) {
			// 点击了翻译按钮
			case R.id.btnTranslate:
				if (textCategory.getText().toString().equals("id")) {
					Toast.makeText(MainActivity.this, R.string.can_not_edit, Toast.LENGTH_LONG).show();
					return;
				}
				// 初始化翻译
				DoTranslate translate = new DoTranslate(txtOriginal, txtTranslated, true, MainActivity.this);
				// 开启翻译·
				translate.init(0);
				break;
			// 点击了搜索按钮
			case R.id.btnSearch:
				// 初始化搜索
				SearchString searchTask = new SearchString(MainActivity.this, txtOriginal);
				// 开启搜索
				searchTask.search();
				break;
			// 点击了保存按钮
			case R.id.btnSave:
				// 创建一个线程用来保存资源文件
				SaveFileTask saveTask = new SaveFileTask();
				// 执行该线程
				saveTask.execute("/sdcard/1.arsc");
				break;
			// 点击了资源类型的文本框
			case R.id.textCategory:
				// 弹出一个对话框,列出所有的资源类型
				new AlertDialog.Builder(MainActivity.this).setTitle("")
						.setItems((String[]) Types.toArray(new String[Types.size()]),
								new DialogInterface.OnClickListener() {
									// 对话框上的条目点击的事件监听器
									@Override
									public void onClick(DialogInterface arg0, int arg1) {
										// TODO Auto-generated method stub
										textCategory.setText(Types.get(arg1));
									}
								})
						.create().show();
				break;
			// 点击了资源Config的文本框
			case R.id.textConfig:
				// 弹出一个对话框,列出所有的资源Config
				new AlertDialog.Builder(MainActivity.this).setTitle("")
						.setItems((String[]) Configs.toArray(new String[Configs.size()]),
								new DialogInterface.OnClickListener() {
									// 对话框上的条目点击的事件监听器
									@Override
									public void onClick(DialogInterface arg0, int arg1) {
										// TODO Auto-generated method stub
										textConfig.setText(Configs.get(arg1));
									}
								})
						.create().show();
				break;
			}
		}
	};

	private void open(String resFile) throws IOException {
		if (resFile.endsWith(".arsc")) {
			open(new FileInputStream(resFile), ARSC);
		} else if (resFile.endsWith(".xml")) {
			open(new FileInputStream(resFile), AXML);
		} else if (resFile.endsWith(".dex")) {
			open(new FileInputStream(resFile), DEX);
		} else {
			throw new IOException("Unsupported FileType");
		}
	}

	private void open(InputStream resInputStream, int resType) {
		// 初始化一个线程用来解析资源文件
		AsyncTask<InputStream, Integer, String> task = new ParseTask();
		try {
			// 开启该线程
			task.execute(resInputStream);
			ResType = resType;
		} catch (OutOfMemoryError e) {
			showMessage(this, getString(R.string.out_of_memory)).show();
		}
		// 初始化一个线程用来获取解析后的资源
		AsyncTask<String, Integer, String> getTask = new GetTask();
		// 开启该线程
		getTask.execute(textCategory.getText().toString(), textConfig.getText().toString());
	}

	/**
	 * 文本框内容改变的事件监听器
	 * 
	 * @author zhaohai
	 */
	private TextWatcher textWatcher = new TextWatcher() {

		// 文本改变后的事件处理
		@Override
		public void afterTextChanged(Editable s) {
			// 初始化一个线程用来获取资源
			AsyncTask<String, Integer, String> task = new GetTask();
			// 开启该线程
			task.execute(textCategory.getText().toString(), textConfig.getText().toString());
		}

		// 文本改变之前的事件处理
		@Override
		public void beforeTextChanged(CharSequence s, int start, int count, int after) {
			// TODO Auto-generated method stub
			Log.d("TAG", "beforeTextChanged--------------->");
		}

		// 文本改变的事件处理
		@Override
		public void onTextChanged(CharSequence s, int start, int before, int count) {

		}

	};

	/**
	 * 一个用来获取解析后的资源的线程
	 * 
	 * @author zhaohai
	 */
	class GetTask extends AsyncTask<String, Integer, String> {
		// 进度条
		private ProgressDialog dlg;

		// 耗时任务开始前执行的任务
		@Override
		protected void onPreExecute() {
			super.onPreExecute();
			// 初始化进度条
			dlg = new ProgressDialog(MainActivity.this);
			// 设置标题
			dlg.setTitle(R.string.parsing);
			// 设置按返回进度条不消失
			dlg.setCancelable(false);
			// 显示进度条
			dlg.show();

			// 如果储存Config的列表未初始化
			if (Configs == null) {
				// 初始化Config列表
				Configs = new ArrayList<String>();
			}

			// 检查是否发生改变
			for (String str : txtTranslated) {
				if (!str.equals(""))
					isChanged = true;
				break;
			}

			if (isChanged) {
				// 排序整理修改后的内容,以方便一一写入
				for (int i = 0; i < txtOriginal.size(); i++)
					mAndRes.mARSCDecoder.mTableStrings.sortStringBlock(txtOriginal.get(i), txtTranslated.get(i));
			}

			// 清除几个列表中的元素
			txtOriginal.clear();
			txtTranslated.clear();
			txtTranslated_Key.clear();
			Configs.clear();
		}

		// 执行耗时任务
		@Override
		protected String doInBackground(String... params) {
			switch (ResType) {

			case ARSC:
				for (ContentValues resource : RESOURCES) {
					// 获取资源的键
					String NAME = (String) resource.get(MyObj.NAME);
					// 获取资源的值
					String VALUE = (String) resource.get(MyObj.VALUE);
					// 获取资源类型
					String TYPE = (String) resource.get(MyObj.TYPE);
					// 获取资源分支
					String CONFIG = (String) resource.get(MyObj.CONFIG);

					// 如果资源的Config开头存在-符号,并且Config列表中不存在该资源的Config元素,并且资源种类是params[0]的值
					if (CONFIG.startsWith("-") && !Configs.contains(CONFIG.substring(1)) && TYPE.equals(params[0]))
						// 向Config列表中添加元素
						Configs.add(CONFIG.substring(1));
					// 如果资源的Config开头不存在-符号,并且Config列表中不存在该资源的Config元素,并且资源种类是params[0]的值
					else if (!CONFIG.startsWith("-") && !Configs.contains(CONFIG) && TYPE.equals(params[0]))
						Configs.add(CONFIG);

					// 如果资源的Config开头存在-符号,并且Config列表中存在该资源的Config元素,并且Config是params[1]的值
					if (TYPE.equals(params[0]) && CONFIG.startsWith("-") && CONFIG.substring(1).equals(params[1])) {
						// 向储存字符串的列表中添加字符串成员
						txtOriginal.add(VALUE);
						// 向储存修改后的字符串的列表中添加空成员
						txtTranslated.add("");
						// 向储存资源的键的列表添加键
						txtTranslated_Key.add(NAME);
						// 如果资源的Config开头不存在-符号,并且Config列表中存在该资源的Config元素,并且Config是params[1]的值
					} else if (TYPE.equals(params[0]) && !CONFIG.startsWith("-") && CONFIG.equals(params[1])) {
						// 向储存字符串的列表中添加字符串成员
						txtOriginal.add(VALUE);
						// 向储存修改后的字符串的列表中添加空成员
						txtTranslated.add("");
						// 向储存资源的键的列表添加键
						txtTranslated_Key.add(NAME);
					}
				}
				break;
			case AXML:
				try {
					mAndRes.mAXMLDecoder.getStrings(txtOriginal);
					for (int i = 0; i < txtOriginal.size(); i++) {
						// 向储存修改后的字符串的列表中添加空成员
						txtTranslated.add("");
						// 向储存资源的键添加空成员
						txtTranslated_Key.add("");
					}
				} catch (CharacterCodingException e) {
					return e.toString();
				}
				break;
			case DEX:

				break;
			}
			// 返回一个成功的标志
			return getString(R.string.success);
		}

		// 耗时任务执行完毕后的事件处理
		@Override
		protected void onPostExecute(String result) {
			// 隐藏进度条
			dlg.dismiss();
			// 如果收到的返回值不是成功的标志
			if (!result.equals(getString(R.string.success))) {
				// 则显示错误详情
				showMessage(MainActivity.this, result).show();
				return;
			} else if (result.equals(getString(R.string.success)) && txtOriginal.size() == 0) // 如果收到成功的标志,并且字符串列表没有成员,说明资源列表中不存在这样的成员
			{
				if (Configs.size() != 0)
					// 那么就获取默认的资源
					textConfig.setText(
							Configs.contains("[DEFAULT]") ? Configs.get(Configs.indexOf("[DEFAULT]")) : Configs.get(0));
			}
			// 对Config列表进行排序
			Collections.sort(Configs);
			//
			// Collections.sort(txtOriginal);
			// 通知数据适配器更新数据
			mAdapter.notifyDataSetInvalidated();
		}

	}

	// 一个储存键的类
	class MyObj {
		public final static String NAME = "name";
		public final static String VALUE = "value";
		public final static String TYPE = "type";
		public final static String CONFIG = "config";
	}

	/**
	 * @author zhaohai 一个用来解析ARSC的线程
	 */
	class ParseTask extends AsyncTask<InputStream, Integer, String> {
		// 资源回调接口
		private ARSCCallBack callback;
		// 进度条
		private ProgressDialog dlg;
		// 创建values值对象
		private ContentValues values = null;

		// 耗时任务开始前执行的任务
		@Override
		protected void onPreExecute() {
			super.onPreExecute();
			// 初始化ARSC解析器
			mAndRes = new AndrolibResources(MainActivity.this);
			// 初始化进度条
			dlg = new ProgressDialog(MainActivity.this);
			// 设置进度条标题
			dlg.setTitle(R.string.parsing);
			// 设置按进度条外部进度条不消失
			dlg.setCancelable(false);
			// 显示进度条
			dlg.show();

			// 如果储存资源类型的列表未初始化
			if (Types == null) {
				// 初始化储存资源类型的列表
				Types = new ArrayList<String>();
			}

			// 实现资源回调接口
			callback = new ARSCCallBack() {
				// 进度值
				int i = 0;

				@Override
				public void back(String config, String type, String key, String value) {
					// 这里是为了出去一些不能编辑的字符串
					if (type != null) {
						// 初始化键值映射
						values = new ContentValues();
						// 向映射中添加资源的键
						values.put(MyObj.NAME, key);
						// 向映射中添加资源的值
						values.put(MyObj.VALUE, value);
						// 向映射中添加资源的种类
						values.put(MyObj.TYPE, type);
						// 向映射中添加资源的Config
						values.put(MyObj.CONFIG, config);
						// 向资源中添加该映射
						RESOURCES.add(values);
					}
					// 如果资源种类集合中不存在该种类
					if (!Types.contains(type))
						// 向其中添加该种类
						Types.add(type);
					// 进度值加1
					i++;
					// 更新进度条
					publishProgress(i);
				}
			};
		}

		// 获取ARSC文件的ResTable的方法
		public ResTable getResTable(InputStream ARSCStream) throws IOException {
			return mAndRes.getResTable(ARSCStream);
		}

		// 执行耗时任务
		@Override
		protected String doInBackground(InputStream... params) {
			try {
				switch (ResType) {
				case ARSC:
					// 解析ARSC
					mAndRes.decodeARSC(getResTable(params[0]), callback);
					break;
				case AXML:
					// 解析ARSC
					mAndRes.decodeAXML(params[0]);
					break;
				}
			} catch (Exception e) {
				return e.toString();
			}
			return getString(R.string.success);
		}

		// 更新ui界面
		@Override
		protected void onProgressUpdate(Integer... values) {
			dlg.setMessage(String.valueOf(values[0]));
		}

		// 耗时任务执行完毕后的事件处理
		@Override
		protected void onPostExecute(String result) {
			// 隐藏进度条
			dlg.dismiss();
			// 如果返回的结果不是成功
			if (!result.equals(getString(R.string.success))) {
				// 显示错误信息
				showMessage(MainActivity.this, result).show();
				return;
			}
			// 对资源种类列表排序
			Collections.sort(Types);
		}

	}

	/**
	 * @author zhaohai 一个用来保存资源文件的线程
	 */
	class SaveFileTask extends AsyncTask<String, String, String> {
		// 进度条
		private ProgressDialog dlg;

		// 耗时任务开始前执行的任务
		@Override
		protected void onPreExecute() {
			super.onPreExecute();
			// 初始化进度条
			dlg = new ProgressDialog(MainActivity.this);
			// 设置进度条标题
			dlg.setTitle(R.string.saving);
			// 设置按进度条外部进度条不消失
			dlg.setCancelable(false);
			// 显示进度条
			dlg.show();
		}

		// 执行耗时任务
		@Override
		protected String doInBackground(String... params) {
			try {
				switch (ResType) {
				case ARSC:
					// 创建新文件输出流
					FileOutputStream fo1 = new FileOutputStream(params[0]);
					mAndRes.mARSCDecoder.write(fo1, txtOriginal, txtTranslated);
					fo1.close();
					break;
				case AXML:
					// 创建新文件输出流
					FileOutputStream fo2 = new FileOutputStream(params[0]);
					mAndRes.mAXMLDecoder.write(txtOriginal, txtTranslated, fo2);
					fo2.close();
					break;
				case DEX:
					break;
				}
			} catch (IOException e) {
				return e.toString();
			} catch (OutOfMemoryError e) {
				return getString(R.string.out_of_memory);
			}
			return getString(R.string.success);
		}

		// 耗时任务执行完毕后的事件处理
		@Override
		protected void onPostExecute(String result) {
			// 隐藏进度条
			dlg.dismiss();
			// 如果返回的结果不是成功
			if (!result.equals(getString(R.string.success))) {
				// 显示错误信息
				showMessage(MainActivity.this, result).show();
				return;
			}
			// 还原是否改变的标志
			isChanged = false;
		}

	}

	// 数据适配器
	public class stringListAdapter extends BaseAdapter {

		// 上下文
		private Context mContext;
		// 显示原来的字符串内容的控件
		private TextView txtOriginalView;
		// 用于修改的文本框控件
		private EditText txtTranslatedView;

		// 构造函数
		public stringListAdapter(Context context) {
			super();
			// 获取上下文
			this.mContext = context;
		}

		// 获取数据成员个数
		@Override
		public int getCount() {
			// TODO Auto-generated method stub
			return txtOriginal.size();
		}

		// 获取指定条目的内容
		@Override
		public Object getItem(int arg0) {
			// TODO Auto-generated method stub
			return arg0;
		}

		// 获取指定条目的文字
		@Override
		public long getItemId(int arg0) {
			// TODO Auto-generated method stub
			return arg0;
		}

		// 文本框点击是事件监听器
		OnTouchListener touch = new OnTouchListener() {
			@SuppressLint("ClickableViewAccessibility")
			@Override
			public boolean onTouch(View arg0, MotionEvent arg1) {
				if (arg1.getAction() == MotionEvent.ACTION_UP)
					Toast.makeText(MainActivity.this, R.string.can_not_edit, Toast.LENGTH_LONG).show();
				return false;
			}
		};

		// 获取View
		@SuppressLint({ "ViewHolder", "InflateParams" })
		@Override
		public View getView(final int position, View view, ViewGroup arg2) {

			// 文本框内容改变的事件监听器
			TextWatcher textWatcher = new TextWatcher() {

				// 文本改变后的事件处理
				@Override
				public void afterTextChanged(Editable s) {

				}

				// 文本改变之前的事件处理
				@Override
				public void beforeTextChanged(CharSequence s, int start, int count, int after) {
					// TODO Auto-generated method stub
					Log.d("TAG", "beforeTextChanged--------------->");
				}

				// 文本改变的事件处理
				@Override
				public void onTextChanged(CharSequence s, int start, int before, int count) {
					// 从集合中移除该条目对应的空白内容
					txtTranslated.remove(position);
					// 向当前位置添加新的内容,以此实现文本的更新
					txtTranslated.add(position, s.toString());
				}

			};

			// 创建view对象
			view = LayoutInflater.from(mContext).inflate(R.layout.res_string_item, null);
			// 获取显示原来的字符串的控件
			txtOriginalView = (TextView) view.findViewById(R.id.txtOriginal);
			// 获取用来修改的文本框
			txtTranslatedView = (EditText) view.findViewById(R.id.txtTranslated);

			// 如果选中了style资源,则显示没有可供编辑的字符串的提示
			if (textCategory.getText().toString().equals("style")) {
				// 隐藏列表
				stringListView.setVisibility(View.INVISIBLE);
				// 显示一个控件用来提示
				info.setVisibility(View.VISIBLE);
				// 显示文字
				info.setText(R.string.no_strings_for_editing);
				return view;
			} else {
				// 隐藏显示信息的控件
				info.setVisibility(View.GONE);
				// 显示列表
				stringListView.setVisibility(View.VISIBLE);
			}
			// 如果选中了id资源,则设置文本框不可编辑,因为id不能随意编辑
			if (textCategory.getText().toString().equals("id")) {
				txtTranslatedView.setFocusable(false);
				txtTranslatedView.setOnTouchListener(touch);
			}
			// 显示原来的字符串
			txtOriginalView.setText(txtOriginal.get(position));
			// 显示修改后的字符串
			txtTranslatedView.setText(txtTranslated.get(position));
			// 为文本框设置底层的显示内容
			txtTranslatedView.setHint(txtTranslated_Key.get(position));
			// 为文本框设置内容改变的监听器
			txtTranslatedView.addTextChangedListener(textWatcher);
			return view;
		}
	}

	// 显示信息的方法
	public static AlertDialog.Builder showMessage(Context activity, String message) {
		return new AlertDialog.Builder(activity).setMessage(message).setNegativeButton(R.string.ok, null)
				.setCancelable(false).setTitle(R.string.error);
	}
}