/* 
 * This is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * 
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this software; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
 * USA.
 */
/** 
	 * FullMouseMode.java
	 * Autor: Alberto Población Navarro
	 * Añadido al proyecto en la version v0.1
	 * Añadido a:
	 		* Proyecto original: http://code.google.com/p/android-vnc-viewer/
	 		* Release: 39
*/
package android.androidVNC;

import android.content.pm.ActivityInfo;
import android.os.CountDownTimer;
import android.util.Log;
import android.view.Display;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageButton;
import android.widget.RelativeLayout;
import android.widget.Toast;
import android.widget.ZoomControls;
import android.widget.RelativeLayout.LayoutParams;


	/**
	 * Modo para un control global del raton y el teclado remotos
	 * @author Alberto Población Navarro
	 *
	 */
	class FullMouseMode implements AbstractInputHandler {
	
		private static final String TAG = "DEBUG";
		private static VncCanvas vncCanvas;
		private static VncCanvasActivity vncCanvasActivity;
		//Al ser static se pueden utilizar en los demas modos de visualizacion aunque no se haya utilizado el FullMouseMode
		static ZoomControls zoom_control;
		static ImageButton reset;
		private Zoom zoom;
		int orientation;
		/**
		 *  Modo para un control global del ratón y el teclado remotos
		 *  @param vnccanvas instancia de la clase VncCanvas que se estÃ¡ utilizando, es la imagen que se dibuja
		 *  @param vnccanvasactivity instacia de la clase VncCanvasActivity, la encargada de intercambiar informacion entre el rfb protocol y el vnccanvas
		 */
		FullMouseMode(VncCanvas vnccanvas, VncCanvasActivity vnccanvasactivity)
		{
			vncCanvas = vnccanvas;
			vncCanvasActivity = vnccanvasactivity;
			orientation = vncCanvasActivity.getRequestedOrientation();
			
			zoom= Zoom.Instancia(vncCanvasActivity, vncCanvas);
			//Modo de situacion de los widget en la pantalla: Modo relativo
			RelativeLayout tabla = new RelativeLayout(vncCanvasActivity);
			//Configuramos los parametros de la tabla: que ocupe toda la pantalla
			tabla.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT ,LayoutParams.FILL_PARENT));
			zoom_control = new ZoomControls(vncCanvasActivity);
			//Lo inicializamo "escondido" para que solo se muestren cuando se active la opcion de menu
			zoom_control.hide();
			//Configuracion de los parametros d los controles de zoom: ocupen su tamaño tal cual
			LayoutParams parametros = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
			//Añadimos configuraciones: alieneado al fondo de padre(table) y centrado horizontalmente
			parametros.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
			parametros.addRule(RelativeLayout.CENTER_HORIZONTAL);
			//Añadimos las configuraciones al zoom y configuramos ambos botones.
			zoom_control.setLayoutParams(parametros);
			zoom_control.setOnZoomInClickListener(new OnClickListener(){
				@Override
				public void onClick(View v) {
					zoom.zoom_in();
				}
			});
			zoom_control.setOnZoomOutClickListener(new OnClickListener(){
				@Override
				public void onClick(View v) {
					zoom.zoom_out();
				}
			});
			//Añadimos los controles de zoom a la tabla
			tabla.addView(zoom_control);
			//Nuevo boton con imagen
			reset= new ImageButton(vncCanvasActivity);
			//Configuramos las características del boton: imagen, visibilidad y comportamiento.
			reset.setImageResource(R.drawable.reset); 
			reset.setVisibility(View.INVISIBLE);
			reset.setOnClickListener(new OnClickListener(){
				@Override
				public void onClick(View v) {
					zoom.reset();	
				}
			});
			//Añadimos el boton a la tabla
			tabla.addView(reset);
			//Añadimos la tabla a la vista con los parámetros configurados anteriormente
			vncCanvasActivity.addContentView(tabla, tabla.getLayoutParams());
			
		}
				
		/* (non-Javadoc)
		 * @see android.androidVNC.AbstractInputHandler#onKeyDown(int, android.view.KeyEvent)
		 */
		@Override
		public boolean onKeyDown(int keyCode, KeyEvent evt) {
			switch (keyCode) {
				case KeyEvent.KEYCODE_VOLUME_UP: //Hacemos zoom in
					zoom.zoom_in(); 
					break;
				case KeyEvent.KEYCODE_VOLUME_DOWN: //Hacemos zoom out
					zoom.zoom_out(); 
					break;
				case KeyEvent.KEYCODE_BACK: //Desconectamos
					Notificacion notificacion = Notificacion.Instancia(vncCanvasActivity);
					notificacion.notificar(vncCanvasActivity.getString(R.string.disconnected),vncCanvasActivity.getString(R.string.connection_closed));
					notificacion.eliminar();
					vncCanvasActivity.disconnect=true;
					vncCanvas.closeConnection();
					vncCanvasActivity.finish();
					break;
				case KeyEvent.KEYCODE_DPAD_CENTER: //Mandamos el click derecho del ratón en la posicion actual del raton
					KeyEvent camera = new KeyEvent(KeyEvent.ACTION_DOWN,KeyEvent.KEYCODE_CAMERA);
					vncCanvas.processLocalKeyEvent(KeyEvent.KEYCODE_CAMERA, camera);
					vncCanvas.processPointerEvent(MotionEvent.obtain(1, System.currentTimeMillis(), MotionEvent.ACTION_DOWN, vncCanvas.mouseX,vncCanvas.mouseY, 0), false);
					break;			
				case KeyEvent.KEYCODE_1:
					vncCanvasActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
					break;
				case KeyEvent.KEYCODE_2:
					vncCanvasActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_USER);
					break;
				default:
					//Comportamiento por defecto del resto de las teclas
					return vncCanvasActivity.defaultKeyDownHandler( keyCode, evt);
				}
				return true;
			}
		
		/* (non-Javadoc)
		 * @see android.androidVNC.AbstractInputHandler#onKeyUp(int, android.view.KeyEvent)
		 */
		@Override
		public boolean onKeyUp(int keyCode, KeyEvent evt) {
			
			if(keyCode == KeyEvent.KEYCODE_DPAD_CENTER){ //Click derecho del raton
				vncCanvas.processPointerEvent(MotionEvent.obtain(1, System.currentTimeMillis(), MotionEvent.ACTION_UP, vncCanvas.mouseX,vncCanvas.mouseY, 0), false);
				KeyEvent camera = new KeyEvent(KeyEvent.ACTION_UP,KeyEvent.KEYCODE_CAMERA);
				vncCanvas.processLocalKeyEvent(KeyEvent.KEYCODE_CAMERA, camera);		
				}
			else{
				vncCanvasActivity.defaultKeyDownHandler( keyCode, evt);
			}
				return true;
		}
	
		/* (non-Javadoc)
		 * @see android.androidVNC.AbstractInputHandler#onTouchEvent(android.view.MotionEvent)
		 */
		@Override
		public boolean onTouchEvent(MotionEvent event) {
			return fullmousetouch(event);			
		}
		/* (non-Javadoc)
		 * @see android.androidVNC.AbstractInputHandler#onTrackballEvent(android.view.MotionEvent)
		 */
		@Override
		public boolean onTrackballEvent(MotionEvent evt) {
			return false;
		}
		/* (non-Javadoc)
		 * @see android.androidVNC.AbstractInputHandler#handlerDescription()
		 */
		@Override
		public CharSequence getHandlerDescription() {
			return vncCanvasActivity.getResources().getText(R.string.input_mode_full_mouse);
		}

        /* (non-Javadoc)
         * @see android.androidVNC.AbstractInputHandler#getName()
         */
        @Override
        public String getName() {
                return "FULL MOUSE";
        }
		
	
	private long down; //Momento de la pulsacion
	private long up; // Momento en el que se suelta la pulsacion
	private final int click = 100; //Tiempo en milisegundos para saber que se trata de un click
	private final int drag = 500; //Tiempo en milisegundos para saber si hay que arrastrar en vez de mover
		
	CountDownTimer timer; //Temporizador para saber si se trata de un click o para arrastrar
	
	/**
	 * Segun el parametro event, realiza una acción que se será enviada al servidor como acción de ratón.
	 * Depende de la acción podemos mandar un movimiento, un click o la acción de arrastrar
	 * @param event evento táctil que sera tratado por la función
	 * @return 
	 * @author Alberto Población Navarro
	 */
	public boolean fullmousetouch( MotionEvent event) 
	{ 
	
		//Ajustamos la posicion del evento para que sea compatible con el el Zoom
		event.setLocation((event.getX()/zoom.getZoom()), (event.getY()/zoom.getZoom()));
		
		switch (event.getAction()) {
			case MotionEvent.ACTION_DOWN:
				down= event.getEventTime(); //Momento de la pulsacion
				final MotionEvent evento = MotionEvent.obtain(event);
				//Si es una pulsacion larga: modo de arrastre. 
				timer = new CountDownTimer(drag, 10){
	
				     public void onTick(long millisUntilFinished) {
				    	 //No hacer nada durante los intervalos
				     }
				     				 
				     public void onFinish() {
				    	 // Si se completa la cuenta atras entramos en el modo de arrastre "Draggin mode"
				    	 Toast.makeText(vncCanvasActivity, vncCanvasActivity.getString(R.string.drag), Toast.LENGTH_SHORT).show();
				    	 //Mandamos un click down ajustando la posicion de raton segun el zoom
						 evento.setAction(MotionEvent.ACTION_DOWN);
						 //Ajustamos las coordenadadas teniendo en cuenta la status bar
						 evento.offsetLocation(0, -1f * vncCanvas.getTop()/zoom.getZoom());
						 //Ajustamos las coordenadas para realizar el panning del escritorio
						 evento.offsetLocation(vncCanvasActivity.absoluteXPosition/zoom.getZoom(), vncCanvasActivity.absoluteYPosition/zoom.getZoom());
						 vncCanvas.processPointerEvent(evento, true);
					}
				  }.start();
				return true;
				
			case MotionEvent.ACTION_MOVE:
				//Cancelas el timeout para que no entre en el modo de arrastre
				timer.cancel();
				return Move(event);
				
				
				
			case MotionEvent.ACTION_UP:
				//up=new Date(); 
				up = event.getEventTime(); //Para conocer la duracion de la pulsacion
				timer.cancel();
				//Si es una pulsacion rapida: click de raton
				if (up - down < click)
				{
					//Mandas el gesto del click complento, cuando pulsas y cuando sueltas la tecla
					event.setAction(MotionEvent.ACTION_DOWN);
					//Ajustamos las coordenadadas teniendo en cuenta la status bar
					event.offsetLocation(0, -1f * vncCanvas.getTop()/zoom.getZoom());
					//Ajustamos las coordenadas para realizar el panning del escritorio
					event.offsetLocation(vncCanvasActivity.absoluteXPosition/zoom.getZoom(), vncCanvasActivity.absoluteYPosition/zoom.getZoom());
					//Mandas el click completo: pulsas y sueltas
					vncCanvas.processPointerEvent(event, true);
					event.setAction(MotionEvent.ACTION_UP);
					return vncCanvas.processPointerEvent(event, true);
				}
				//Si no ha sido un click del raton mandas que se levantado la tecla simplemente
				event.setAction(MotionEvent.ACTION_UP);
				//Ajustamos las coordenadas para realizar el panning del escritorio
				event.offsetLocation(0, -1f * vncCanvas.getTop()/zoom.getZoom());
				//Ajustamos las coordenadas para realizar el panning del escritorio
				event.offsetLocation(vncCanvasActivity.absoluteXPosition/zoom.getZoom(), vncCanvasActivity.absoluteYPosition/zoom.getZoom());
				return vncCanvas.processPointerEvent(event, true);			
			}
		return false;
					
	}
	
	final int border = 30; //Distancia entre el cursor y el borde para que se desplace la pantalla
	/**
	 * Mueve la parte de escritorio en la que nos encontramos si estamos a una distancia menor de X de un extremo
	 * @param event
	 * @author Alberto Poblacion Navarro
	 */
	private boolean Move(MotionEvent event) {
			//Obtienes las cordenadas donde tienes el cursor
			float curX = event.getX()*zoom.getZoom();
			float curY = event.getY()*zoom.getZoom();
			int scrollX =0;
			int scrollY =0;
			//Si pulsamos el raton a menos distancia de "border" de uno de los extremos, configuramos la posicion que debemos mover la imagen
			//De la actividad conseguimos el manager de la ventana y de este la pantalla por defecto
			Display display=vncCanvasActivity.getWindowManager().getDefaultDisplay();
			if (curX > (display.getWidth()-border)){
				scrollX +=border;
				//Log.d(TAG, "DERECHA");
			}if (curX  < border){
				scrollX -=border;
				//Log.d(TAG, "IZQIERDA");
			}if (curY  > (display.getHeight()-border)){
				scrollY +=border;
				//Log.d(TAG, "ABAJO");
			}if (curY  < border){
				scrollY -=border;
				//Log.d(TAG, "ARRIBA");
			}
			//Sumamos a la posición absoluta la cantidad que no tengamos que mover	
			vncCanvasActivity.absoluteXPosition += scrollX;
			vncCanvasActivity.absoluteYPosition += scrollY;
			//Comprobamos los margenes superior e izquierdo
			if(vncCanvasActivity.absoluteXPosition < 0){
				Log.d(TAG, "Entro en margen izquierdo");
				scrollX=0;
				vncCanvasActivity.absoluteXPosition=0;
				vncCanvas.scrollTo(vncCanvasActivity.absoluteXPosition, vncCanvas.getScrollY());
			}
			if(vncCanvasActivity.absoluteYPosition < 0){
				Log.d(TAG, "Entro en margen superior AbsY: "+vncCanvasActivity.absoluteYPosition+" Hegi: "+vncCanvas.getHeight()+" Top: "+vncCanvas.getTop()+" > ImageHe: "+ vncCanvas.getImageHeight());
				
				scrollY=0;
				vncCanvasActivity.absoluteYPosition=0;
				vncCanvas.scrollTo(vncCanvas.getScrollX(), vncCanvasActivity.absoluteYPosition);
			}
			//Comprobamos los márgenes derecho y inferior
			if(vncCanvasActivity.absoluteXPosition+ display.getWidth()> vncCanvas.getImageWidth()){
				Log.d(TAG, "Entro en margen derexo Zoom: "+zoom.getZoom()+" Absx: "+vncCanvasActivity.absoluteXPosition+" weid*zoom: "+vncCanvas.getWidth()*zoom.getZoom()+" > ImagWi: "+ vncCanvas.getImageWidth());
				vncCanvasActivity.absoluteXPosition=vncCanvas.getImageWidth()-(display.getWidth());
				vncCanvas.scrollTo(0, vncCanvas.getScrollY());
				vncCanvas.scrollTo(vncCanvasActivity.absoluteXPosition,vncCanvas.getScrollY());
				scrollX=0;
			}
			if(vncCanvasActivity.absoluteYPosition + display.getHeight()> vncCanvas.getImageHeight()){
				Log.d(TAG, "Entro en margen inferior AbsY: "+vncCanvasActivity.absoluteYPosition+" Hegi: "+vncCanvas.getHeight()+" Top: "+vncCanvas.getTop()+" > ImageHe: "+ vncCanvas.getImageHeight());
				vncCanvasActivity.absoluteYPosition=vncCanvas.getImageHeight()-(vncCanvas.getHeight());
				vncCanvas.scrollTo(vncCanvas.getScrollX(),0);
				vncCanvas.scrollTo(vncCanvas.getScrollX(), vncCanvasActivity.absoluteYPosition);
				scrollY=0;
			}
			//Movemos la posicion del escritorio
			//if(scrollX !=0) Log.d(TAG, "Movemos en X la posición del escritorio "+scrollX);
			//if(scrollY !=0) Log.d(TAG, "Movemos en Y la posición del escritorio "+scrollY);
			
			vncCanvas.scrollBy(scrollX, scrollY);
			//Ajustamos la posicion del evento la barra de notificaciones
			event.offsetLocation(0, -1f * vncCanvas.getTop()/zoom.getZoom());
			//Ajustamos la posicion del evento lo que nos movamos
			event.offsetLocation(vncCanvasActivity.absoluteXPosition/zoom.getZoom(),vncCanvasActivity.absoluteYPosition/zoom.getZoom());
			//Procesamos el evento sin el click pulsado, solo movimiento de raton
			return vncCanvas.processPointerEvent(event, false);
	}
}