package cc.makeblock.makeblock;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.UUID;

import org.json.JSONException;
import org.json.JSONObject;

import com.umeng.analytics.MobclickAgent;

import cc.makeblock.modules.MeModule;
import android.app.ActionBar;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothManager;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.BitmapDrawable;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.PopupWindow;
import android.widget.Toast;
import android.widget.PopupWindow.OnDismissListener;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.SimpleAdapter;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.TextView;

public class LayoutView extends Activity {
	static final String dbg = "LayoutView";
	static final int BOARD_ARDUINO=0;
	static final int BOARD_MAKEBLOCK_LEONARDO=1;
	static final int BOARD_MAKEBLOCK_UNO=2;// the ch340+328p baseboard
	private Context mContext;

    private int screenWidth,screenHeight;  

    private int leftEdge;  

    private int rightEdge = 0;  

    private int menuPadding = 800;  

    private View content;  

    private View menu;  

    private LinearLayout.LayoutParams menuParams;  
 
    private float xDown;  

    private float xMove;  

    private float xUp;  
 
    private boolean isMenuVisible;
    
    ImageButton addModBtn;
    ImageButton runBtn;
    ListView moduleListView;
    
	public final static String ITEM_IMAGE = "image";  
    public final static String ITEM_CAPTION = "caption"; 
    
    
    LocalLayout layouts;
    FrameLayout contentView;
    UpgradeFirm firmup;
    
    MeLayout layout;
    PopupWindow popupWindow;
	LinearLayout popupLayout;
	RadioGroup portGroup;
	RadioGroup slotGroup;
	RadioButton rPort1,rPort2,rPort3,rPort4,rPort5,rPort6,rPort7,rPort8,rPortM1,rPortM2;
	RadioButton rSlot1,rSlot2;
	
	RadioGroup modSelect;
	RadioButton rMakeblock,rArduino;
	
	int boardType = BOARD_ARDUINO;
	static float firmVersion = 0f;

	// bluetooth related
	MenuItem blticon;
	Bluetooth blt;
	PopupWindow popupBtSelect;
	DeviceListAdapter devAdapter;
	ArrayAdapter<String> pairAdapter;
	ProgressDialog uploadPb;
	
	// Mscript related 
	static final int STAGE_IDLE = 0; // the layout is editable in this state
	static final int STAGE_PROBING = 1;
	static final int STAGE_DONWLOAD_PROCESS = 2;
	static final int STAGE_DONWLOAD_FIN = 2;
	static final int STAGE_RUN = 4;
	int engineState = STAGE_IDLE;
	int downPtr = 0;
	Timer mTimer;
	TimerTask mTimerTask;
	int queryListIndex;
	private Matrix imageMatrix = new Matrix();  
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		mContext = this;
		setContentView(R.layout.activity_layout);
		layouts = new LocalLayout(this);
		firmup = new UpgradeFirm(this);
		contentView = (FrameLayout)findViewById(R.id.content); 
		contentView.getForeground().setAlpha(0);
		initValues();
		addModBtn = (ImageButton)this.findViewById(R.id.drawModule);
		addModBtn.setOnClickListener(new OnClickListener(){
			@Override
			public void onClick(View arg0) {
				if(engineState>STAGE_IDLE) return;
				if(!isMenuVisible){
					new ScrollTask().execute(30);
				}else{
					new ScrollTask().execute(-30);
				}
				MobclickAgent.onEvent(mContext, "drawModule");
			}
		});
		
		runBtn = (ImageButton)this.findViewById(R.id.runLayout);
		runBtn.setOnClickListener(new OnClickListener(){
			@Override
			public void onClick(View view){
				if(engineState==STAGE_IDLE){
					if(blt!=null){
						if(blt.connDev==null){
							showBtSelect();
						}else{
							if(firmVersion==0){
								stopTimer(); // stop previous version probing timer
								Log.d("firmversion", "UNKNOW");
								showUpgradeDialog();
								engineState = STAGE_IDLE;
							}else{
								engineState = STAGE_RUN;
								enableAllModule();
								runBtn.setImageResource(R.drawable.pause_button);
							}
							startTimer(200);
						}
					}else{
						if(BluetoothLE.sharedManager().isConnected()){
							if(firmVersion==0){
								stopTimer(); // stop previous version probing timer
								Log.d("firmversion", "UNKNOW");
								showUpgradeDialog();
								engineState = STAGE_IDLE;
							}else{
								engineState = STAGE_RUN;
								enableAllModule();
								runBtn.setImageResource(R.drawable.pause_button);
							}
							startTimer(200);
						}else{
							showBtSelect();
						}
					}
				}else{
					stopTimer();
					engineState = STAGE_IDLE;
					disableAllModule();
					runBtn.setImageResource(R.drawable.run_button);
				}
				MobclickAgent.onEvent(mContext, "runLayout");
			}
		});
		
		String jsonstr = getIntent().getExtras().getString("layout");
		JSONObject json;
		
		try {
			json = new JSONObject(jsonstr);
			layout = new MeLayout(json);
			for(MeModule mod : layout.moduleList){
				addViewModule(mod);
			}
		} catch (JSONException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		ActionBar actionBar = getActionBar(); 
		actionBar.setTitle(layout.name);
		actionBar.setDisplayHomeAsUpEnabled(true);
		moduleListView = (ListView)this.findViewById(R.id.moduleListView);
		SimpleAdapter adapter = new SimpleAdapter(this,getData(),R.layout.list_modulelist,
				new String[]{"title","info","img"},
				new int[]{R.id.title,R.id.info,R.id.img});
		moduleListView.setAdapter(adapter);
		moduleListView.setOnItemClickListener(new OnItemClickListener(){
			@Override
			public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
				Map<String, Object> dev = getData().get(position);
				int deviceType = (Integer) dev.get("dev");
				//Log.i(dbg, "add module "+deviceType);
				MeModule mod = layout.addModule(deviceType, deviceType==MeModule.DEV_DCMOTOR?9:3, 0, 10, 10);
				addViewModule(mod);
				saveLayout();
			}
		});
		
		
		if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
			blt = Bluetooth.sharedManager();
			blt.mHandler = mHandler;
			devAdapter = new DeviceListAdapter(this,blt.getBtDevList(),R.layout.device_list_item);
        }else{
	        BluetoothLE.sharedManager().setup(this);
			BluetoothLE.sharedManager().leHandler = mLeHandler;
			devAdapter = new DeviceListAdapter(this,BluetoothLE.sharedManager().getDeviceList(),R.layout.device_list_item);
			MeTimer.startWrite();
        }
		//new ArrayAdapter<String>(this, android.R.layout.simple_expandable_list_item_1,blt.getBtDevList());
//		pairAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_expandable_list_item_1,blt.getPairedList());

		disableAllModule();		
	}
	
	protected void startUpgradeing(){
		
		stopTimer();
		startTimer(500);
		engineState = STAGE_PROBING;
		
		if(blt!=null){
			blt.commMode = Bluetooth.MODE_FORWARD;
		}else{
			BluetoothLE.sharedManager().commMode = BluetoothLE.MODE_FORWARD;
		}
		
		uploadPb = ProgressDialog.show(this.mContext, getString(R.string.Upgrade_Firmware), getString(R.string.Please_Press_Reset_Button));
		uploadPb.setCancelable(true);
		uploadPb.setOnDismissListener(new DialogInterface.OnDismissListener() {
            @Override
            public void onDismiss(DialogInterface dialog) {
            	if(blt!=null){
            		blt.commMode = Bluetooth.MODE_LINE;
            	}else{
            		BluetoothLE.sharedManager().commMode = BluetoothLE.MODE_LINE;
            	}
				stopTimer();
				engineState = STAGE_IDLE;
				disableAllModule();
				runBtn.setImageResource(R.drawable.run_button);
				//startTimer(1000);
            }
        });
	}
	
	protected void showUpgradeDialog() {
//        AlertDialog.Builder builder = new AlertDialog.Builder(this);
//        builder.setTitle(getString(R.string.Alert));
//        builder.setMessage(getString(R.string.UnknowFirm))
//        .setPositiveButton(getString(R.string.upgrade), new DialogInterface.OnClickListener() {
//            public void onClick(DialogInterface dialog, int id) {
//            	startUpgradeing();
//            }
//        })
//        .setNegativeButton(getString(R.string.back), new DialogInterface.OnClickListener() {
//            public void onClick(DialogInterface dialog, int id) {
//                // User cancelled the dialog
//				stopTimer();
//				engineState = STAGE_IDLE;
//				disableAllModule();
//				runBtn.setImageResource(R.drawable.run_button);
//            }
//        });
//        builder.create().show();
	}
	
	@Override
	public void onStart(){
		super.onStart();
		Log.d("mb", "start");
	}
	
	@Override
	protected void onStop(){
		stopTimer();
		super.onStop();
		Log.d("mb", "stop");
	}
	@Override
	public void onResume() {
		super.onResume();
		MobclickAgent.onResume(this);
		Log.d("mb", "resume");
	}
	
	@Override
	public void onPause() {
		super.onPause();
		MobclickAgent.onPause(this);
		Log.d("mb", "pause");
	}
	
	void enableAllModule(){
		for(MeModule mod : layout.moduleList){
			mod.setEnable(mHandler);
			mod.update();
		}
		addModBtn.setVisibility(View.INVISIBLE);
	}
	
	void disableAllModule(){
		for(MeModule mod : layout.moduleList){
			mod.setDisable();
			mod.update();
		}
		addModBtn.setVisibility(View.VISIBLE);
	}
	
	void saveLayout(){
		try {
			layout.updateTime = layout.getTime();
			layouts.FileSave(layout.name+".json", layout.toString());
			getIntent().removeExtra("layout");
			getIntent().putExtra("layout", layout.toString()); // update intent string
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public void addViewModule(MeModule mod){
		View view = LayoutInflater.from(this).inflate(mod.viewLayout, null);
		FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(  
                FrameLayout.LayoutParams.WRAP_CONTENT,  
                FrameLayout.LayoutParams.WRAP_CONTENT, Gravity.LEFT|Gravity.TOP);  
		
        params.topMargin = mod.xPosition;  
        params.leftMargin = mod.yPosition;
        view.setOnTouchListener(new ModuleOnTouch(mod));
		mod.view = view;
		mod.setViewPortString(mod.port);
        mod.setViewPortImage(mod.imageId);
        mod.update();
		contentView.addView(mod.view,params);
		contentView.requestLayout();
	}
	
	void showPopupWindow(MeModule mod){
		// don't show port select for joystick
			
		
		popupLayout = (LinearLayout) LayoutInflater.from(this).inflate(
				R.layout.popup_menu, null);
		popupWindow = new PopupWindow(this);
		popupWindow.setWidth(screenWidth/2);
//		if(mod.type==MeModule.DEV_JOYSTICK){
//			popupWindow.setHeight((int) (screenHeight*0.2));
//		}else{
//			popupWindow.setHeight((int) (screenHeight*0.7));
//		}
		popupWindow.setHeight((int) (screenHeight*0.8));
		popupWindow.setOutsideTouchable(true);
		popupWindow.setFocusable(true);
		popupWindow.setContentView(popupLayout);
		popupWindow.showAtLocation(findViewById(R.id.content), Gravity.LEFT|Gravity.TOP, screenWidth/4, screenHeight/10+25);
		popupWindow.setOnDismissListener(new OnDismissListener(){
			@Override
			public void onDismiss() {
				contentView.getForeground().setAlpha(0);
			}
		});
		
		portGroup = (RadioGroup) popupLayout.findViewById(R.id.radioGroup1);
		rPort1 = (RadioButton)popupLayout.findViewById(R.id.port1);
		rPort2 = (RadioButton)popupLayout.findViewById(R.id.port2);
		rPort3 = (RadioButton)popupLayout.findViewById(R.id.port3);
		rPort4 = (RadioButton)popupLayout.findViewById(R.id.port4);
		rPort5 = (RadioButton)popupLayout.findViewById(R.id.port5);
		rPort6 = (RadioButton)popupLayout.findViewById(R.id.port6);
		rPort7 = (RadioButton)popupLayout.findViewById(R.id.port7);
		rPort8 = (RadioButton)popupLayout.findViewById(R.id.port8);
		rPortM1 = (RadioButton)popupLayout.findViewById(R.id.portm1);
		rPortM2 = (RadioButton)popupLayout.findViewById(R.id.portm2);
		switch(mod.port){
		case MeModule.PORT_1:
			rPort1.setChecked(true);
			break;
		case MeModule.PORT_2:
			rPort2.setChecked(true);
			break;
		case MeModule.PORT_3:
			rPort3.setChecked(true);
			break;
		case MeModule.PORT_4:
			rPort4.setChecked(true);
			break;
		case MeModule.PORT_5:
			rPort5.setChecked(true);
			break;
		case MeModule.PORT_6:
			rPort6.setChecked(true);
			break;		
		case MeModule.PORT_7:
			rPort7.setChecked(true);
			break;
		case MeModule.PORT_8:
			rPort8.setChecked(true);
			break;
		case MeModule.PORT_M1:
			rPortM1.setChecked(true);
			break;
		case MeModule.PORT_M2:
			rPortM2.setChecked(true);
			break;			
		}
		
		slotGroup = (RadioGroup) popupLayout.findViewById(R.id.slotRadioGroup);
		rSlot1 = (RadioButton)popupLayout.findViewById(R.id.slot1);
		rSlot2 = (RadioButton)popupLayout.findViewById(R.id.slot2);
		TextView joystickTip = (TextView)popupLayout.findViewById(R.id.joystickInfo);
		

		if(mod.type==MeModule.DEV_JOYSTICK||mod.type==MeModule.DEV_CAR_CONTROLLER){
			portGroup.setVisibility(View.GONE);
			slotGroup.setVisibility(View.GONE);
			joystickTip.setVisibility(View.VISIBLE);
		}else{
			if(!mod.shouldSelectSlot){
				slotGroup.setVisibility(View.GONE);
			}else{
				switch(mod.slot){
				case MeModule.SLOT_1:
					rSlot1.setChecked(true);
					break;
				case MeModule.SLOT_2:
					rSlot2.setChecked(true);
					break;
				}
				
			}
			joystickTip.setVisibility(View.GONE);
		}
		//portGroup.setOnCheckedChangeListener(new portChangeListener(mod));
		TextView txtTitle = (TextView) popupLayout.findViewById(R.id.popupTitle);
		txtTitle.setText(getDevString(mod.name));
		Button btnDelete = (Button) popupLayout.findViewById(R.id.popupDelBtn);
		btnDelete.setOnClickListener(new moduleDeleteListener(mod));
		Button btnOk = (Button) popupLayout.findViewById(R.id.popupOkBtn);
		btnOk.setOnClickListener(new portChangeListener(mod));
		contentView.getForeground().setAlpha(150);
	}
	
	class moduleDeleteListener implements OnClickListener{
		MeModule mod;
		public moduleDeleteListener(MeModule mod){
			this.mod = mod;
		}
		@Override
		public void onClick(View arg0) {
			Log.i(dbg, "delete module "+mod.name);			
			contentView.removeView(mod.view);
			layout.moduleList.remove(mod);
			popupWindow.dismiss();
			saveLayout();
		}
	}
	
	class portChangeListener implements OnClickListener{
		MeModule mod;
		public portChangeListener(MeModule mod){
			this.mod = mod;
		}
		@Override
		public void onClick(View arg0) {
			int id= portGroup.getCheckedRadioButtonId();
			switch(id){
			case R.id.port1:
				mod.port = MeModule.PORT_1;
				break;
			case R.id.port2:
				mod.port = MeModule.PORT_2;
				break;
			case R.id.port3:
				mod.port = MeModule.PORT_3;
				break;
			case R.id.port4:
				mod.port = MeModule.PORT_4;
				break;
			case R.id.port5:
				mod.port = MeModule.PORT_5;
				break;
			case R.id.port6:
				mod.port = MeModule.PORT_6;
				break;
			case R.id.port7:
				mod.port = MeModule.PORT_7;
				break;
			case R.id.port8:
				mod.port = MeModule.PORT_8;
				break;				
			case R.id.portm1:
				mod.port = MeModule.PORT_M1;
				break;
			case R.id.portm2:
				mod.port = MeModule.PORT_M2;
				break;
			}
			if(mod.shouldSelectSlot){
				int slotid= slotGroup.getCheckedRadioButtonId();
				switch(slotid){
				
				case R.id.slot1:
					mod.slot = MeModule.SLOT_1;
					break;
				case R.id.slot2:
					mod.slot = MeModule.SLOT_2;
					break;
				}
				/*
				// inverse slot
				case R.id.slot2:
					mod.slot = MeModule.SLOT_1;
					break;
				case R.id.slot1:
					mod.slot = MeModule.SLOT_2;
					break;
				}
				*/
			}
			
			mod.setViewPortString(mod.port);
			popupWindow.dismiss();
			saveLayout();
		}
	}
	
	
	class ModuleOnTouch implements OnTouchListener {
	    private int lastX, lastY;
	    long startTime;
	    MeModule mod;
	    public ModuleOnTouch(MeModule mod){
	    	this.mod = mod;
	    }
	    
		@Override
		public boolean onTouch(View v, MotionEvent event) {
			if(engineState>STAGE_IDLE) return false;
			switch (event.getAction()) {  
			case MotionEvent.ACTION_DOWN:
				mod.view.bringToFront();
				lastX = (int) event.getRawX();  
	            lastY = (int) event.getRawY(); 
	            startTime = System.currentTimeMillis();
	            break;
	       	case MotionEvent.ACTION_MOVE:
				int dx = (int) event.getRawX() - lastX;
	            int dy = (int) event.getRawY() - lastY;
	            int left = v.getLeft() + dx;  
	            int top = v.getTop() + dy;  
	            int right = v.getRight() + dx;  
	            int bottom = v.getBottom() + dy;  
	            FrameLayout.LayoutParams params = (FrameLayout.LayoutParams)v.getLayoutParams();
	            params.topMargin = top;
	            params.leftMargin = left;
	            v.setLayoutParams(params);
	            mod.xPosition = top;
	            mod.yPosition = left;
				lastX = (int) event.getRawX();
	            lastY = (int) event.getRawY();
				break;
	       	case MotionEvent.ACTION_UP:
	       		long endTime = System.currentTimeMillis();
	       		if((endTime-startTime)<200){
	       			showPopupWindow(mod);
	       		}else{
	       			saveLayout();
	       		}
	       		break;
			}
			return true; 
		}
	}
	
	private List<Map<String, Object>> getData() {
		List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();

		Map<String, Object> map = new HashMap<String, Object>();
		
		map.put("title", getString(R.string.dcmotor));
		map.put("info", "");
		map.put("img", R.drawable.motor);
		map.put("dev", MeModule.DEV_DCMOTOR);
		list.add(map);

//		map = new HashMap<String, Object>();
//		map.put("title", getString(R.string.gripper));
//		map.put("info", "");
//		map.put("img", R.drawable.servo);
//		map.put("dev", MeModule.DEV_GRIPPER_CONTROLLER);
//		list.add(map);
		
		map = new HashMap<String, Object>();
		map.put("title", getString(R.string.servomotor));
		map.put("info", "");
		map.put("img", R.drawable.servo);
		map.put("dev", MeModule.DEV_SERVO);
		list.add(map);
		
		map = new HashMap<String, Object>();
		map.put("title", getString(R.string.joystick));
		map.put("info", "");
		map.put("img", R.drawable.joystick_icon);
		map.put("dev", MeModule.DEV_JOYSTICK);
		list.add(map);
		
		map = new HashMap<String, Object>();
		map.put("title", getString(R.string.RGBled));
		map.put("info", "");
		map.put("img", R.drawable.rgbled);
		map.put("dev", MeModule.DEV_RGBLED);
		list.add(map);
		
		map = new HashMap<String, Object>();
		map.put("title", getString(R.string.digitalseg));
		map.put("info", "");
		map.put("img", R.drawable.sevseg);
		map.put("dev", MeModule.DEV_SEVSEG);
		list.add(map);

		map = new HashMap<String, Object>();
		map.put("title", getString(R.string.ultrasonic));
		map.put("info", "");
		map.put("img", R.drawable.ultrasonic);
		map.put("dev", MeModule.DEV_ULTRASOINIC);
		list.add(map);
		
		map = new HashMap<String, Object>();
		map.put("title", getString(R.string.temperature));
		map.put("info", "");
		map.put("img", R.drawable.temperature);
		map.put("dev", MeModule.DEV_TEMPERATURE);
		list.add(map);
		
		map = new HashMap<String, Object>();
		map.put("title", getString(R.string.lightsensor));
		map.put("info", "");
		map.put("img", R.drawable.lightsensor);
		map.put("dev", MeModule.DEV_LIGHTSENSOR);
		list.add(map);
		
		map = new HashMap<String, Object>();
		map.put("title", getString(R.string.soundsensor));
		map.put("info", "");
		map.put("img", R.drawable.soundsensor);
		map.put("dev", MeModule.DEV_SOUNDSENSOR);
		list.add(map);
		
		map = new HashMap<String, Object>();
		map.put("title", getString(R.string.linefollow));
		map.put("info", "");
		map.put("img", R.drawable.linefinder);
		map.put("dev", MeModule.DEV_LINEFOLLOWER);
		list.add(map);
		
		map = new HashMap<String, Object>();
		map.put("title", getString(R.string.potentialmeter));
		map.put("info", "");
		map.put("img", R.drawable.potentiometer);
		map.put("dev", MeModule.DEV_POTENTIALMETER);
		list.add(map);
		
		map = new HashMap<String, Object>();
		map.put("title", getString(R.string.limitswitch));
		map.put("info", "");
		map.put("img", R.drawable.limitswitch);
		map.put("dev", MeModule.DEV_LIMITSWITCH);
		list.add(map);
		
		map = new HashMap<String, Object>();
		map.put("title", getString(R.string.button));
		map.put("info", "");
		map.put("img", R.drawable.button);
		map.put("dev", MeModule.DEV_BUTTON);
		list.add(map);
		
		map = new HashMap<String, Object>();
		map.put("title", getString(R.string.pirsensor));
		map.put("info", "");
		map.put("img", R.drawable.pirmotion);
		map.put("dev", MeModule.DEV_PIRMOTION);
		list.add(map);
		
		
		
		return list;
	}
	
	private void initValues() {  
        WindowManager window = (WindowManager) getSystemService(Context.WINDOW_SERVICE);  
        screenWidth = window.getDefaultDisplay().getWidth();
        screenHeight = window.getDefaultDisplay().getHeight();
        content = findViewById(R.id.content);  
        menu = findViewById(R.id.menu);  
        menuParams = (LinearLayout.LayoutParams) menu.getLayoutParams();  
        // Ω´menuµƒøÌ∂»…Ë÷√Œ™∆¡ƒªøÌ∂»ºı»•menuPadding  
        //menuParams.width = screenWidth - menuPadding;  
        menuParams.width = (int) (screenWidth*0.3);
        // ◊Û±fl‘µµƒ÷µ∏≥÷µŒ™menuøÌ∂»µƒ∏∫ ˝  
        leftEdge = -menuParams.width;  
        // menuµƒleftMargin…Ë÷√Œ™◊Û±fl‘µµƒ÷µ£¨’‚—˘≥ı ºªØ ±menuæÕ±‰Œ™≤ªø…º˚  
        menuParams.leftMargin = leftEdge;  
        // Ω´contentµƒøÌ∂»…Ë÷√Œ™∆¡ƒªøÌ∂»  
        content.getLayoutParams().width = screenWidth;  
    }
	
	class ScrollTask extends AsyncTask<Integer, Integer, Integer> {  
		  
	        @Override  
	        protected Integer doInBackground(Integer... speed) {  
	            int leftMargin = menuParams.leftMargin;  
	            // ∏˘æ›¥´»ÎµƒÀŸ∂»¿¥πˆ∂ØΩÁ√Ê£¨µ±πˆ∂ØµΩ¥Ô◊Û±flΩÁªÚ”“±flΩÁ ±£¨Ã¯≥ˆ—≠ª∑°£  
	            while (true) {  
	                leftMargin = leftMargin + speed[0];  
	                if (leftMargin > rightEdge) {  
	                    leftMargin = rightEdge;  
	                    break;  
	                }  
	                if (leftMargin < leftEdge) {  
	                    leftMargin = leftEdge;  
	                    break;  
	                }  
	                publishProgress(leftMargin);  
	                // Œ™¡À“™”–πˆ∂Ø–ßπ˚≤˙…˙£¨√ø¥Œ—≠ª∑ πœfl≥ÃÀØ√fl20∫¡√Σ¨’‚—˘»‚—€≤≈ƒ‹πªø¥µΩπˆ∂Ø∂ت≠°£  
	                sleep(20);  
	            }  
	            if (speed[0] > 0) {  
	                isMenuVisible = true;  
	            } else {  
	                isMenuVisible = false;  
	            }  
	            
	            return leftMargin;  
	        }  
	  
	        @Override  
	        protected void onProgressUpdate(Integer... leftMargin) {  
	            menuParams.leftMargin = leftMargin[0];  
	            menu.setLayoutParams(menuParams);  
	            rotatoAddButton(45+leftMargin[0]*45/(rightEdge-leftEdge));
	        }  
	  
	        @Override  
	        protected void onPostExecute(Integer leftMargin) {  
	            menuParams.leftMargin = leftMargin;  
	            menu.setLayoutParams(menuParams);  
	            rotatoAddButton(45+leftMargin*45/(rightEdge-leftEdge));
	        }  
	    }  
	
		private void rotatoAddButton(int angle){

            Bitmap bitmap = ((BitmapDrawable) getResources().getDrawable(R.drawable.add_button)).getBitmap();  
            // …Ë÷√–˝◊™Ω«∂»  
            imageMatrix.setRotate(angle);  
            // ÷ÿ–¬ªÊ÷∆Bitmap  
            bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),bitmap.getHeight(), imageMatrix, true);  
            addModBtn.setImageBitmap(bitmap);
		}
	    /** 
	     *  πµ±«∞œfl≥ÃÀØ√fl÷∏∂®µƒ∫¡√Π˝°£ 
	     *  
	     * @param millis 
	     *            ÷∏∂®µ±«∞œfl≥ÃÀØ√fl∂‡æ√£¨“‘∫¡√ÎŒ™µ•Œª 
	     */  
	    private void sleep(long millis) {  
	        try {  
	            Thread.sleep(millis);  
	        } catch (InterruptedException e) {  
	            e.printStackTrace();  
	        }  
	    }
	    
		@Override
		public boolean onCreateOptionsMenu(Menu menu) {
			// Inflate the menu; this adds items to the action bar if it is present.
			getMenuInflater().inflate(R.menu.layout, menu);
			blticon = menu.findItem(R.id.action_bluetooth);
			if(blt==null){
				return true;
			}
			if(blt.connDev!=null){
				blticon.setIcon(R.drawable.bluetooth_on);
				Message msg = mHandler.obtainMessage(Bluetooth.MSG_CONNECTED);
				mHandler.sendMessage(msg);
			}
			return true;
		}
		
		@Override
		protected void onDestroy(){
			super.onDestroy();
			if(blt!=null){
				if(blt.connDev!=null){
					Bluetooth.sharedManager().bluetoothDisconnect(blt.connDev);
				}
			}else{
				BluetoothLE.sharedManager().close();
			}
//			this.unregisterReceiver(mBTDevDiscover);
			
		}
		
		@Override
		public boolean onOptionsItemSelected(MenuItem item) {
			switch (item.getItemId()) {
			case R.id.action_del:
				new AlertDialog.Builder(this)
				.setTitle(getString(R.string.delete))  
				.setMessage(getString(R.string.delete_this_layout))  
				.setPositiveButton(getString(R.string.ok), new DialogInterface.OnClickListener(){
					@Override
					public void onClick(DialogInterface dialog, int which) {
						layouts.FileDelete(layout.name+".json");
						setResult(1);finish();
					}
				})  
				.setNegativeButton(getString(R.string.cancel), null)  
				.show(); 
				break;
			case R.id.action_bluetooth:
				showBtSelect();
				break;
			default:
				Intent mIntent = new Intent(getApplicationContext(),MainActivity.class);
				startActivityForResult(mIntent, 0);
			}
			return true;
		}
		
		// --------------- BULETOOTH BELOW ---------------------
		final Handler mHandler = new Handler(){
			@Override
			public void handleMessage(Message msg){
				switch(msg.what){
				case Bluetooth.MSG_CONNECTED:
					{
						devListChanged();
						blticon.setIcon(R.drawable.bluetooth_on);
						Intent intent = new Intent(LayoutView.this,DialogActivity.class); 
						intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
						intent.putExtra("msg", getString(R.string.connected));
				        startActivity(intent);
				        firmVersion = 0.0f;
				        startTimer(1000);
					}
					break;
				case Bluetooth.MSG_DISCONNECTED:
					stopTimer();
					devListChanged();
					blticon.setIcon(R.drawable.bluetooth_off);
					boardType = BOARD_ARDUINO;
					break;
				case Bluetooth.MSG_CONNECT_FAIL:
				{
					Intent intent = new Intent(LayoutView.this,DialogActivity.class); 
					intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
					intent.putExtra("msg", getString(R.string.connectfail));
			        startActivity(intent);
					Log.d(dbg,"connect fail");
					}
					break;
				case Bluetooth.MSG_RX:
					int[] rx = (int[]) msg.obj;
					parseMsg(rx);
					break;
				case Bluetooth.MSG_FOUNDDEVICE:
					devListChanged();
					break;
				case Bluetooth.MSG_DISCOVERY_FINISHED:{
					if(btnRefresh!=null){
						AnimationDrawable d=(AnimationDrawable)btnRefresh.getCompoundDrawables()[0];
						d.stop();
					}
				}
				break;
				case MeModule.MSG_VALUECHANGED:
					byte[] cmd = (byte[]) msg.obj;
					if(blt!=null){
						blt.bluetoothWrite(cmd);
					}else{
						BluetoothLE.sharedManager().writeBuffer(cmd);
					}
					break;
				}
			}
		};
		final Handler mLeHandler = new Handler(){
			@Override
			public void handleMessage(Message msg){
				switch(msg.what){
				case BluetoothLE.MSG_CONNECTED:
					{
						devLEListChanged();
						blticon.setIcon(R.drawable.bluetooth_on);
						Intent intent = new Intent(LayoutView.this,DialogActivity.class); 
						intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
						intent.putExtra("msg", getString(R.string.connected));
				        startActivity(intent);
				        firmVersion = 0.0f;
				        startTimer(1000);
					}
					break;
				case BluetoothLE.MSG_DISCONNECTED:
					stopTimer();
					devLEListChanged();
					blticon.setIcon(R.drawable.bluetooth_off);
					boardType = BOARD_ARDUINO;
					break;
				case BluetoothLE.MSG_CONNECT_FAIL:
				{
					Intent intent = new Intent(LayoutView.this,DialogActivity.class); 
					intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
					intent.putExtra("msg", getString(R.string.connectfail));
			        startActivity(intent);
					Log.d(dbg,"connect fail");
					}
					break;
				case BluetoothLE.MSG_SCAN_START:{
					if(btnRefresh!=null){
						AnimationDrawable d=(AnimationDrawable)btnRefresh.getCompoundDrawables()[0];
						d.start();
					}
				}
					break;
				case BluetoothLE.MSG_SCAN_END:{
					if(btnRefresh!=null){
						AnimationDrawable d=(AnimationDrawable)btnRefresh.getCompoundDrawables()[0];
						d.stop();
					}
				}
					break;
				case BluetoothLE.MSG_RX:
					int[] rx = (int[]) msg.obj;
					parseMsg(rx);
					break;
				case BluetoothLE.MSG_FOUNDDEVICE:
					devLEListChanged();
					break;
				case BluetoothLE.MSG_DISCOVERY_FINISHED:{
					if(btnRefresh!=null){
						AnimationDrawable d=(AnimationDrawable)btnRefresh.getCompoundDrawables()[0];
						d.stop();
					}
				}
				break;
				case BluetoothLE.MSG_CONNECTING:{
					Intent intent =new Intent(LayoutView.this,DialogActivity.class); 
					intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
					intent.putExtra("msg", getString(R.string.connecting));
			        startActivity(intent);
				}
				break;
				case MeModule.MSG_VALUECHANGED:
					byte[] cmd = (byte[]) msg.obj;
					BluetoothLE.sharedManager().writeBuffer(cmd);
					break;
				}
			}
		};
		void queryVersion(){
			//Log.d("mb", "queryVersion");
			byte[] cmd = new byte[7];
			//a[8]={0xff,0x55,len,VERSION_INDEX,action,device,'\n'};
			cmd[0]=(byte) 0xff;
			cmd[1]=(byte) 0x55;
			cmd[2]=(byte) 3;
			cmd[3]=(byte) MeModule.VERSION_INDEX;
			cmd[4]=(byte) MeModule.READMODULE;
			cmd[5]=(byte) 0;
			cmd[6]=(byte) '\n';
			if(blt!=null){
				blt.bluetoothWrite(cmd);
			}else{
				BluetoothLE.sharedManager().writeBuffer(cmd);
			}
		}
		
		MeModule findModByVarReg(String reg){
			MeModule mod;
			for(int i=0;i<layout.moduleList.size();i++){
				mod = layout.moduleList.get(i);
				if(mod.varReg.equals(reg)){
					return mod;
				}
			}
			return null;
		}
		
		void parseMsg(int[] msg){
			
//			Log.d("mb", "parseMSG:"+msg.length);
			if(engineState==STAGE_PROBING){
				engineState = STAGE_DONWLOAD_PROCESS;
				stopTimer();
				int ret = firmup.parseCmd(msg);
				//if(ret>0) stopTimer();
				//firmup.loadFirm();
				firmup.startDownload();
				uploadPb.setMessage("Found Orion, now downloading");
				byte[] tosend = firmup.getHexPage();
				if(tosend!=null){
					if(blt!=null){
						blt.bluetoothWrite(tosend);
					}else{
						MeTimer.delayWrite(tosend,10);
					}
				}
			}else if(engineState == STAGE_DONWLOAD_PROCESS){
				byte[] tosend = firmup.getHexPage();
				if(tosend!=null){
					int percent = firmup.getDowningProcess();
					uploadPb.setMessage(getString(R.string.Upgrading)+" "+percent+"%");
					if(blt!=null){
						blt.bluetoothWrite(tosend);
					}else{
						MeTimer.delayWrite(tosend, 100);
					}
					if(percent==100){
						firmVersion = 1.1f;
						uploadPb.dismiss();
					}
				}
			}else if(msg.length>2){
				if((msg[2]&0xff)==MeModule.VERSION_INDEX){
					int len = msg[4];
					String hexStr="";
					for(int i=0;i<len;i++){
						hexStr+=String.format("%c", msg[5+i]);
					}
					Log.d("mb","version:"+hexStr);
					firmVersion = 1.1f;
					if(engineState==STAGE_IDLE){
						stopTimer();
					}
				}else{
					int moduleIndex = msg[2];
					if(msg.length<7) return;
					float f = 0.0f;
					if(msg[3]==2){
						if(msg.length>7){
							int tint = (msg[4]&0xff)+((msg[5]&0xff)<<8)+((msg[6]&0xff)<<16)+((msg[7]&0xff)<<24);
							f = Float.intBitsToFloat(tint);
						}
					}else if(msg[3]==1){
						f = (msg[4]&0xff);
					}else if(msg[3]==3){
						f = (msg[4]&0xff)+((msg[5]&0xff)<<8);
					}
					if(moduleIndex<0 || moduleIndex>layout.moduleList.size()){
						return;
					}
					//rx:FF 55 04 04 07 31 2E 31 2E 31 30 32 0D 0A 

					if(moduleIndex<layout.moduleList.size()){
						MeModule mod = layout.moduleList.get(moduleIndex);
						mod.setEchoValue(""+f);
					}
					
				}
			}else if(msg.length<3){
				return;
			}
		}
		
		public void devListChanged(){
			if(blt!=null){
				devAdapter.updateData (blt.getBtDevList());
				devAdapter.notifyDataSetChanged();
			}
		}
		public void devLEListChanged(){
			List<String> list = BluetoothLE.sharedManager().getDeviceList();
			if(devAdapter!=null){
				devAdapter.updateData (list);
				devAdapter.notifyDataSetChanged();
			}
		}
		private Button btnRefresh;
		void showBtSelect(){
			if(blt==null){
				BluetoothLE.sharedManager().start();
			}
			LinearLayout popupBtDevLayout;
			popupBtDevLayout = (LinearLayout) LayoutInflater.from(this).inflate(
					R.layout.popup_btselect, null);
			popupBtSelect = new PopupWindow(this);
			popupBtSelect.setWidth(screenWidth/2);
			popupBtSelect.setHeight((int) (screenHeight*0.8));
			popupBtSelect.setOutsideTouchable(true);
			popupBtSelect.setFocusable(true);
			popupBtSelect.setContentView(popupBtDevLayout);
			popupBtSelect.showAtLocation(findViewById(R.id.content), Gravity.LEFT|Gravity.TOP, screenWidth/4, screenHeight/10+25);
			ListView devlist = (ListView) popupBtDevLayout.findViewById(R.id.btdevList);
			//ListView pairlist = (ListView) popupBtDevLayout.findViewById(R.id.btpairList);
			devlist.setAdapter(devAdapter);
			//pairlist.setAdapter(pairAdapter);

			popupBtSelect.setOnDismissListener(new OnDismissListener(){
				@Override
				public void onDismiss() {
					contentView.getForeground().setAlpha(0);
				}
			});
			
			devlist.setOnItemClickListener(new OnItemClickListener(){
				@Override
				public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
					try{ // the bluetooth list may vary
						if(blt!=null){
							BluetoothDevice dev = blt.btDevices.get(position);
							if(blt.connDev!=null && blt.connDev.equals(dev)){
								// disconnect device
								blt.bluetoothDisconnect(blt.connDev);
								return;
							}
							blt.bluetoothConnect(dev);
						}else{
							if(BluetoothLE.sharedManager().isConnected()){
								BluetoothLE.sharedManager().close();
								devLEListChanged();
							}else{
								BluetoothLE.sharedManager().selectDevice(position);
							}
						}
					}catch(Exception e){
						Log.e(dbg, e.toString());
					}
				}
			});
			
			contentView.getForeground().setAlpha(150);
			btnRefresh = (Button) popupBtDevLayout.findViewById(R.id.popupRefreshBtn);
			btnRefresh.setOnClickListener(new OnClickListener(){
				@Override
				public void onClick(View v) {
					if(blt!=null){
						if(!blt.isDiscovery()){
							blt.devListClear();
							devListChanged();
							Log.i(dbg,"startDiscovery");
							blt.startDiscovery();	
						}	
					}else{
						BluetoothLE.sharedManager().stop();
						BluetoothLE.sharedManager().clear();
						devLEListChanged();
						BluetoothLE.sharedManager().start();
					}
					AnimationDrawable d=(AnimationDrawable)btnRefresh.getCompoundDrawables()[0];
					d.start();
				}
			});
			
			Button btnOk = (Button)popupBtDevLayout.findViewById(R.id.popupOkBtn);
			btnOk.setOnClickListener(new OnClickListener(){
				@Override
				public void onClick(View v) {
					popupBtSelect.dismiss();
					if(blt!=null){
						if(blt.connDev!=null){
							engineState = STAGE_RUN;
							if(firmVersion==0){
								stopTimer(); // stop previous version probing timer
								Log.d("firmversion", "UNKNOW");
								showUpgradeDialog();
							}
							stopTimer();
							startTimer(200);
							enableAllModule();
							runBtn.setImageResource(R.drawable.pause_button);
						}
					}else{
						if(BluetoothLE.sharedManager().isConnected()){
							engineState = STAGE_RUN;
							if(firmVersion==0){
								stopTimer(); // stop previous version probing timer
								Log.d("firmversion", "UNKNOW");
								showUpgradeDialog();
							}
							stopTimer();
							startTimer(200);
							enableAllModule();
							runBtn.setImageResource(R.drawable.pause_button);
						}
					}
				}
			});
		}
		
		byte[] getQueryString()
		{
			if(queryListIndex>=layout.moduleList.size()){
				return null;
			}
			MeModule mod = layout.moduleList.get(queryListIndex);
			byte[] query = mod.getQuery(queryListIndex);
			if(query==null){
				queryListIndex++;
				if(queryListIndex==layout.moduleList.size()){
					queryListIndex = 0;
					return null;
				}
				return getQueryString();
			}
			queryListIndex++;
			if(queryListIndex==layout.moduleList.size()){
				queryListIndex = 0;
			}
			return query;
		}
		
		
		void startTimer(int interval){
			if(mTimerTask == null){
				mTimerTask = new TimerTask(){
					@Override
					public void run() {
						if(engineState==STAGE_PROBING){
							byte[] queryStr = firmup.getProbeCmd();
							if(queryStr!=null){
								if(blt!=null){
									blt.bluetoothWrite(queryStr);
								}else{
									BluetoothLE.sharedManager().resetIO(queryStr);
								}
							}
						}else if(engineState==STAGE_RUN){
							byte[] queryStr = getQueryString();
							if(queryStr!=null){
								if(blt!=null){
									blt.bluetoothWrite(queryStr);
								}else{
									BluetoothLE.sharedManager().writeBuffer(queryStr);
								}
							}
						}else if(engineState==STAGE_IDLE){
							queryVersion();
						}
					}
				};
				if(mTimerTask !=null){
					mTimer = new Timer(true);
					mTimer.schedule(mTimerTask,600,interval);
				}
			}
		}
		
		void stopTimer(){
			if(mTimer!=null){
				mTimer.cancel();
				mTimer=null;
			}
			
			if(mTimerTask != null){
				mTimerTask.cancel();
				mTimerTask = null;
			}
		}	
		
		private String getDevString(String str){
			if(str.equals("servo")) return getString(R.string.servomotor);
			if(str.equals("dcmotor")) return getString(R.string.dcmotor);
			if(str.equals("joystick")) return getString(R.string.joystick);
			if(str.equals("rgbled")) return getString(R.string.RGBled);
			if(str.equals("digiseg")) return getString(R.string.digitalseg);
			if(str.equals("ultrasonic")) return getString(R.string.ultrasonic);
			if(str.equals("temperature")) return getString(R.string.temperature);
			if(str.equals("soundsensor")) return getString(R.string.soundsensor);
			if(str.equals("linefinder")) return getString(R.string.linefollow);
			if(str.equals("potentiometer")) return getString(R.string.potentialmeter);
			if(str.equals("limitswitch")) return getString(R.string.limitswitch);
			if(str.equals("button")) return getString(R.string.button);
			if(str.equals("pirsensor")) return getString(R.string.pirsensor);
			return "";
		}

}