package com.handheld.SerialportTest;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnFocusChangeListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.Toast;
import cn.pda.serialport.SerialPort;
import cn.pda.serialport.Tools;

import com.handheld.apiinstructions.R;

public class SerialportActivity extends Activity implements OnClickListener {
	
	/** UI  **/
	private EditText editRecv ;
	private AutoCompleteTextView editSend ;
	private Spinner spinnerBuadrate ;
	private Spinner spinnerSerialport ;
	private Spinner spinnerPower ;
	private CheckBox checkRecv ;
	private CheckBox checkSend ;
	private Button buttonOpen ;
	private Button buttonSend ;
	private Button buttonClear ;
	
	private String[] buadrateStrs ;
	private String[] serialportStrs ;
	private String[] powerStrs ;
	
	private List<String> listBuadRate = new ArrayList<String>();
	private List<String> listSerialPort = new ArrayList<String>();
	private List<String> listPower = new ArrayList<String>();
	
	/** serialport **/
	private SerialPort mSerialPort ;
	private InputStream is ;
	private OutputStream os ;
	
	private int port ;
	private int buad ;
	private String powerStr;

	/** flag **/
	private boolean isHexRecv = false  ;
	private boolean isHexSend = false ;
	private boolean isOpen = false ;
	
	private Context context ;//context = this;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setTitle(R.string.serialport_debugging_tool);
		setContentView(R.layout.activity_serialport);
		
		context = this;
		
		initView();
		listener();
	}
	
	private void initView(){
		editRecv = (EditText) findViewById(R.id.editTextInfo);
		editSend = (AutoCompleteTextView) findViewById(R.id.editTextSend);
		initHistory("history",editSend); 
		spinnerBuadrate = (Spinner) findViewById(R.id.spinnerBuadrate);
		spinnerPower = (Spinner) findViewById(R.id.spinnerPower);
		spinnerSerialport = (Spinner) findViewById(R.id.spinnerSerialport);
		checkRecv = (CheckBox) findViewById(R.id.checkBoxHexRecv);
		checkSend = (CheckBox) findViewById(R.id.checkBoxHexSend);
		buttonOpen = (Button) findViewById(R.id.buttonOpen);
		buttonSend = (Button) findViewById(R.id.buttonSend);
		buttonClear = (Button) findViewById(R.id.buttonClear);
		
		buadrateStrs = context.getResources().getStringArray(R.array.buadrateArray);
		serialportStrs = context.getResources().getStringArray(R.array.serialportArray);
		powerStrs = context.getResources().getStringArray(R.array.powerArray);
		
		for(String buad:buadrateStrs){
			listBuadRate.add(buad);
		}
		for(String serial:serialportStrs){
			listSerialPort.add(serial);
		}
		for(String power:powerStrs){
			listPower.add(power);
		}
		spinnerBuadrate.setAdapter(new ArrayAdapter<String>(context, 
				android.R.layout.simple_spinner_dropdown_item,
				listBuadRate));
		spinnerSerialport.setAdapter(new ArrayAdapter<String>(context, 
				android.R.layout.simple_spinner_dropdown_item,
				listSerialPort));
		spinnerPower.setAdapter(new ArrayAdapter<String>(context, 
				android.R.layout.simple_spinner_dropdown_item,
				listPower));
	}
	
	/**
	 * listen componet
	 */
	private void listener(){
		spinnerSerialport.setOnItemSelectedListener(new OnItemSelectedListener() {

			@Override
			public void onItemSelected(AdapterView<?> adapter, View view,
					int position, long id) {
				port = position;
				
			}

			@Override
			public void onNothingSelected(AdapterView<?> arg0) {
				
			}
		});

		spinnerBuadrate.setOnItemSelectedListener(new OnItemSelectedListener() {

			@Override
			public void onItemSelected(AdapterView<?> adapter, View view,
					int position, long id) {
				String buadrate = buadrateStrs[position];
				buad = Integer.valueOf(buadrate);
			}

			@Override
			public void onNothingSelected(AdapterView<?> arg0) {
				
			}
		});

		spinnerPower.setOnItemSelectedListener(new OnItemSelectedListener() {

			@Override
			public void onItemSelected(AdapterView<?> adapter, View view,
					int position, long id) {
				powerStr = powerStrs[position];
			}

			@Override
			public void onNothingSelected(AdapterView<?> arg0) {
				
			}
		});
		
		checkRecv.setOnCheckedChangeListener(new OnCheckedChangeListener() {
			
			@Override
			public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
				isHexRecv = isChecked;
			}
		});

		checkSend.setOnCheckedChangeListener(new OnCheckedChangeListener() {
			
			@Override
			public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
				isHexSend = isChecked;
				
			}
		});
		
		buttonOpen.setOnClickListener(this);
		buttonSend.setOnClickListener(this);
		buttonClear.setOnClickListener(this);
	}
	
	@Override
	protected void onDestroy() {
		this.close();
		super.onDestroy();
	}

	//open serialport
	private void open(){
		//open
		try {
			mSerialPort = new SerialPort(port, buad, 0);
		}catch (Exception e) {
			showToast(String.valueOf(R.string.serialport_init_fail_));
			return;
		}

		if("3.3V".equals(powerStr)){
			mSerialPort.power3v3on();
		}else if("5V".equals(powerStr)){
			mSerialPort.power_5Von();
		}else if("scan power".equals(powerStr)){
			mSerialPort.scaner_poweron();
		}else if("psam power".equals(powerStr)){
			mSerialPort.psam_poweron();
		}else if("rfid power".equals(powerStr)){
			mSerialPort.rfid_poweron();
		}

		is = mSerialPort.getInputStream();
		os = mSerialPort.getOutputStream();
		isOpen = true;
		spinnerBuadrate.setClickable(false);
		spinnerPower.setClickable(false);
		spinnerSerialport.setClickable(false);
		buttonOpen.setText(context.getResources().getString(R.string.close));
		showToast("SerialPort open success");
	}

	//close serialport
	private void close(){
		if(mSerialPort != null){
			if("3.3V".equals(powerStr)){
				mSerialPort.power3v3off();
			}else if("5V".equals(powerStr)){
				mSerialPort.power_5Voff();
			}else if("scan power".equals(powerStr)){
				mSerialPort.scaner_poweroff();
			}else if("psam power".equals(powerStr)){
				mSerialPort.psam_poweroff();
			}else if("rfid power".equals(powerStr)){
				mSerialPort.rfid_poweroff();
			}
			try {
				is.close();
				os.close();
			} catch (IOException e) {
				e.printStackTrace();
			}

			mSerialPort.close(port);
			isOpen = false;
			spinnerBuadrate.setClickable(true);
			spinnerPower.setClickable(true);
			spinnerSerialport.setClickable(true);
			buttonOpen.setText(context.getResources().getString(R.string.open));
		}
	}
	
	//send cmd
	private void send(){
		byte[] cmd = null;
		String commandStr = editSend.getText().toString();
		if(commandStr == ""){
			showToast(getString(R.string.command_is_null_));
		}
		commandStr = commandStr.replace(" ", "");
		if(isHexSend){
				String regString = "^[a-f0-9A-F]{0,32}";
				boolean flag = Pattern.matches(regString, commandStr); //check data 
			if (flag) {
				cmd = Tools.HexString2Bytes(commandStr);
				try {
					os.write(cmd);
					os.flush();
					onDataReceived(cmd, cmd.length, false);
				} catch (IOException e) {
					e.printStackTrace();
				}
			}else {
				showToast(getString(R.string.please_input_hexadecimal_number));
			}
		}else{
			cmd = commandStr.getBytes();
			try {
				os.write(cmd);
				os.flush();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	private byte[] read() {
		byte[] responseData = null;
		byte[] response = null;
		int available = 0;
		int index = 0;
		int headIndex = 0;

		try {
			while(index < 10) {
				Thread.sleep(50L);
				available = this.is.available();
				if (available > 7) {
					break;
				}
				++index;
			}

			if (available > 0) {
				responseData = new byte[available];
				this.is.read(responseData);

				for(int i = 0; i < available; ++i) {
					if (responseData[i] == -69) {
						headIndex = i;
						break;
					}
				}

				response = new byte[available - headIndex];
				System.arraycopy(responseData, headIndex, response, 0, response.length);
			}
		} catch (Exception e1) {
			e1.printStackTrace();
		}

		return response;
	}

	@Override
	public void onClick(View v) {
		int id = v.getId();
		if (id == R.id.buttonOpen) {
			if (!isOpen) {
				this.open();
			} else {
				this.close();
			}
		} else if (id == R.id.buttonSend) {
			if (isOpen) {
				saveHistory("history", editSend);
				send();
				byte[] data = read();
				if (data != null)
					onDataReceived(data, data.length, true);
				else
					showToast("no answer");
			} else {
				showToast(getString(R.string.please_open_serialport_first_));
			}
		} else if (id == R.id.buttonClear) {
			editRecv.setText("");
		}
	}

	/**
	 * add recv data on UI
	 * @param buffer
	 * @param size
	 */
	private void onDataReceived(final byte[] buffer, final int size, final boolean recvB){
		runOnUiThread(new Runnable() {
			
			@Override
			public void run() {
				if(isHexRecv && buffer != null){
					String recv = Tools.Bytes2HexString(buffer, size);
					if (recvB)
						editRecv.append(getString(R.string._recv_hex_) + recv + "\n");
					else
						editRecv.append(getString(R.string.send) + "(HEX): " + recv + "\n");
				}else if (buffer != null){
					String recv = new String(buffer, 0 , size);
					if (recvB)
						editRecv.append(getString(R.string._recv_) + recv + "\n");
					else
						editRecv.append(getString(R.string.send) + ": " + recv + "\n");
				}
			}
		});
	}
	
	/**
	 * init history 
	 * @param field
	 * @param auto
	 */
	private void initHistory(String field,AutoCompleteTextView auto){
		SharedPreferences sp = getSharedPreferences("commad", 0);  
        String longhistory = sp.getString("history", "nothing");  
        String[]  hisArrays = longhistory.split(",");  
        ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,  
                android.R.layout.simple_dropdown_item_1line, hisArrays);
        if(hisArrays.length > 50){  
            String[] newArrays = new String[50];  
            System.arraycopy(hisArrays, 0, newArrays, 0, 50);  
            adapter = new ArrayAdapter<String>(this,  
                    android.R.layout.simple_dropdown_item_1line, newArrays);  
        }  
        auto.setAdapter(adapter);  
        auto.setDropDownHeight(350);  
        auto.setThreshold(1);  
        auto.setOnFocusChangeListener(new OnFocusChangeListener() {  
            @Override  
            public void onFocusChange(View v, boolean hasFocus) {  
                AutoCompleteTextView view = (AutoCompleteTextView) v;  
                if (hasFocus) {  
                        view.showDropDown();  
                }  
            }  
        });
	}

	/**
	 * save input history
	 * @param field
	 * @param auto
	 */
	private void saveHistory(String field,AutoCompleteTextView auto) {
		String text = auto.getText().toString();
		SharedPreferences sp = getSharedPreferences("commad", 0);  
		String longhistory = sp.getString(field, "nothing"); 
		 if (!longhistory.contains(text + ",")) {  
			StringBuilder sb = new StringBuilder(longhistory);
			sb.insert(0, text + ",");
			sp.edit().putString("history", sb.toString()).commit();
		}
	}

	private Toast toast;
	private void showToast(String info){
		if (toast==null) {
			toast = Toast.makeText(SerialportActivity.this, info, Toast.LENGTH_SHORT);
		}else {
			toast.setText(info);
		}
		toast.show();
	}
}
