package org.cocos2d.layers_scenes_transitions_nodes;

import org.cocos2d.CCDirector;
import org.cocos2d.base_nodes.CCNode;
import org.cocos2d.cocoa.CCGeometry.CCSize;
import org.cocos2d.events.CCKeyDispatcher;
import org.cocos2d.events.CCTouchDispatcher;
import org.cocos2d.protocols.CCKeyDelegateProtocol;
import org.cocos2d.protocols.CCTouchDelegateProtocol;
import org.cocos2d.support.CCPointExtension;

import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;

/**
 * @addtogroup layer
 * @{
 */

//
//CCLayer
//
/** @brief CCLayer is a subclass of CCNode that implements the TouchEventsDelegate protocol.
 * 
 * All features from CCNode are valid, plus the following new features:
 * - It can receive iPhone Touches
 * - It can receive Accelerometer input
 */
public class CCLayer extends CCNode 
	implements CCTouchDelegateProtocol, CCKeyDelegateProtocol, SensorEventListener {

	enum ccTouchesMode {
		kCCTouchesAllAtOnce,
		kCCTouchesOneByOne,
	};

	public CCLayer() {
		m_bTouchEnabled = false;
		m_bAccelerometerEnabled = false;
		m_bKeypadEnabled = false;
// TODO		m_pScriptTouchHandlerEntry = null;
// TODO		m_pScriptKeypadHandlerEntry = null;
// TODO		m_pScriptAccelerateHandlerEntry = null;
		m_nTouchPriority = 0;
		m_eTouchMode = ccTouchesMode.kCCTouchesAllAtOnce;

		m_bIgnoreAnchorPointForPosition = true;
		setAnchorPoint(0.5f, 0.5f);


		// TODO legacy -->

		// get the SensorManager from the Activity
		sensorManager = (SensorManager) CCDirector.sharedDirector().getActivity().getSystemService(Context.SENSOR_SERVICE);

		// if we have a SensorManager then get the accelerometer Sensor
		if (sensorManager != null) 
			accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
		else
			accelerometer = null;

		CCSize s = CCDirector.sharedDirector().getWinSizeInPixels();
		setRelativeAnchorPoint(false);

		setContentSize(s);
		setRelativeAnchorPoint(false);
	}

	@Override
	public boolean init() {
		boolean bRet = false;
		CCDirector pDirector = CCDirector.sharedDirector();
		if(pDirector != null) {
			this.setContentSize(pDirector.getWinSize());
			m_bTouchEnabled = false;
			m_bAccelerometerEnabled = false;
			// success
			bRet = true;
		}
		return bRet;
	}

	/** create one layer */
	public static CCLayer create() {
		CCLayer pRet = new CCLayer();
		if((pRet != null) && pRet.init()) {
			return pRet;
		} else {
			pRet = null;
			return null;
		}
	}

	@Override
	public void onEnter() {
		CCDirector pDirector = CCDirector.sharedDirector();
		// register 'parent' nodes first
		// since events are propagated in reverse order
		if (m_bTouchEnabled) {
			this.registerWithTouchDispatcher();
		}

		// then iterate over all the children
		super.onEnter();

		// add this layer to concern the Accelerometer Sensor
		if(m_bAccelerometerEnabled) {
// TODO			pDirector.getAccelerometer().setDelegate(this);

			// TODO legacy
			registerWithAccelerometer();
		}

		// add this layer to concern the keypad msg
		if(m_bKeypadEnabled) {
// TODO			pDirector.getKeypadDispatcher().addDelegate(this);

			// TODO legacy
			CCKeyDispatcher.sharedDispatcher().addDelegate(this, 0);
		}
	}

	@Override
	public void onExit() {
		CCDirector pDirector = CCDirector.sharedDirector();
		if(m_bTouchEnabled) {
// TODO			pDirector.getTouchDispatcher().removeDelegate(this);
			// [lua]:don't unregister script touch handler, or the handler will be destroyed
			// unregisterScriptTouchHandler();

			// TODO legacy
			CCTouchDispatcher.sharedDispatcher().removeDelegate(this);
		}

		// remove this layer from the delegates who concern Accelerometer Sensor
		if(m_bAccelerometerEnabled) {
// TODO			pDirector.getAccelerometer().setDelegate(NULL);

			// TODO legacy
			unregisterWithAccelerometer();
		}

		// remove this layer from the delegates who concern the keypad msg
		if(m_bKeypadEnabled) {
// TODO			pDirector.getKeypadDispatcher().removeDelegate(this);

			// TODO legacy
			CCKeyDispatcher.sharedDispatcher().removeDelegate(this);
		}

		super.onExit();
	}

	@Override
	public void onEnterTransitionDidFinish() {
		if(m_bAccelerometerEnabled) {
			CCDirector pDirector = CCDirector.sharedDirector();
// TODO			pDirector.getAccelerometer().setDelegate(this);
		}

		super.onEnterTransitionDidFinish();
	}

	// default implements are used to call script callback if exist

	public boolean ccTouchBegan(MotionEvent event) {
/* TODO
		if(kScriptTypeNone != m_eScriptType) {
			return excuteScriptTouchHandler(CCTOUCHBEGAN, pTouch) == 0 ? false : true;
		}
*/
		assert false : "Layer#ccTouchBegan override me";
		return true;
	}

	public void ccTouchMoved(MotionEvent event) {
/* TODO
 		if(kScriptTypeNone != m_eScriptType) {
			excuteScriptTouchHandler(CCTOUCHMOVED, pTouch);
			return;
		}
*/
	}

	public void ccTouchEnded(MotionEvent event) {
/* TODO
		if(kScriptTypeNone != m_eScriptType) {
			excuteScriptTouchHandler(CCTOUCHENDED, pTouch);
			return;
		}
*/
	}

	public void ccTouchCancelled(MotionEvent event) {
/* TODO
		if(kScriptTypeNone != m_eScriptType) {
			excuteScriptTouchHandler(CCTOUCHCANCELLED, pTouch);
			return;
		}
*/
	}

	// default implements are used to call script callback if exist

	public boolean ccTouchesBegan(MotionEvent event) {
/* TODO
		if(kScriptTypeNone != m_eScriptType) {
			excuteScriptTouchHandler(CCTOUCHBEGAN, pTouches);
			return;
		}
*/
		// TODO legacy -->
		assert false : "Layer#ccTouchBegan override me";
		return CCTouchDispatcher.kEventHandled;
	}

	public boolean ccTouchesMoved(MotionEvent event) {
/* TODO
		if(kScriptTypeNone != m_eScriptType) {
			excuteScriptTouchHandler(CCTOUCHMOVED, pTouches);
			return;
		}
*/
		// TODO legacy -->
		return CCTouchDispatcher.kEventIgnored;
	}

	public boolean ccTouchesEnded(MotionEvent event) {
/* TODO
		if(kScriptTypeNone != m_eScriptType) {
			excuteScriptTouchHandler(CCTOUCHENDED, pTouches);
			return;
		}
*/
		// TODO legacy -->
		return CCTouchDispatcher.kEventIgnored;
	}

	public boolean ccTouchesCancelled(MotionEvent event) {
/* TODO
		if(kScriptTypeNone != m_eScriptType) {
			excuteScriptTouchHandler(CCTOUCHCANCELLED, pTouches);
			return;
		}
*/
		// TODO legacy -->
		return CCTouchDispatcher.kEventIgnored;
	}
/* TODO
	public void didAccelerate(CCAcceleration pAccelerationValue) {
		if(m_eScriptType != kScriptTypeNone) {
			CCScriptEngineManager.sharedManager().getScriptEngine().executeAccelerometerEvent(this, pAccelerationValue);
		}
	}

	public void registerScriptAccelerateHandler(int nHandler) {
		unregisterScriptAccelerateHandler();
		m_pScriptAccelerateHandlerEntry = CCScriptHandlerEntry.create(nHandler);
	}

	public void unregisterScriptAccelerateHandler() {
		m_pScriptAccelerateHandlerEntry = null;
	}
*/

	/** If isTouchEnabled, this method is called onEnter. Override it to change the
	 * way CCLayer receives touch events.
	 * ( Default: CCTouchDispatcher::sharedDispatcher()->addStandardDelegate(this,0); )
	 * Example:
	 * void CCLayer::registerWithTouchDispatcher()
	 * {
	 * CCTouchDispatcher::sharedDispatcher()->addTargetedDelegate(this,INT_MIN+1,true);
	 * }
	 * @since v0.8.0
	 */
	public void registerWithTouchDispatcher() {
/* TODO
		CCTouchDispatcher pDispatcher = CCDirector.sharedDirector().getTouchDispatcher();

		// Using LuaBindings
		if(m_pScriptTouchHandlerEntry != null) {
			if(m_pScriptTouchHandlerEntry.isMultiTouches()) {
				pDispatcher.addStandardDelegate(this, 0);
// TODO				LUALOG("[LUA] Add multi-touches event handler: %d", m_pScriptTouchHandlerEntry->getHandler());
			} else {
				pDispatcher.addTargetedDelegate(this,
						m_pScriptTouchHandlerEntry.getPriority(),
						m_pScriptTouchHandlerEntry.getSwallowsTouches());
// TODO				LUALOG("[LUA] Add touch event handler: %d", m_pScriptTouchHandlerEntry->getHandler());
			}
		} else {
			if(m_eTouchMode == ccTouchesMode.kCCTouchesAllAtOnce ) {
				pDispatcher.addStandardDelegate(this, 0);
			} else {
				pDispatcher.addTargetedDelegate(this, m_nTouchPriority, true);
			}
		}
*/
		// TODO legacy -->
		CCTouchDispatcher.sharedDispatcher().addDelegate(this, 0);
	}

	/** Register script touch events handler */
	public void registerScriptTouchHandler(int nHandler) {
		registerScriptTouchHandler(nHandler, false, Integer.MIN_VALUE, false);
	}

	public void registerScriptTouchHandler(int nHandler, boolean bIsMultiTouches) {
		registerScriptTouchHandler(nHandler, bIsMultiTouches, Integer.MIN_VALUE, false);
	}

	public void registerScriptTouchHandler(int nHandler, boolean bIsMultiTouches, int nPriority) {
		registerScriptTouchHandler(nHandler, bIsMultiTouches, nPriority, false);
	}

	public void registerScriptTouchHandler(int nHandler, boolean bIsMultiTouches, int nPriority, boolean bSwallowsTouches) {
		unregisterScriptTouchHandler();
// TODO		m_pScriptTouchHandlerEntry = CCTouchScriptHandlerEntry.create(nHandler, bIsMultiTouches, nPriority, bSwallowsTouches);
	}

	/** Unregister script touch events handler */
	public void unregisterScriptTouchHandler() {
// TODO		m_pScriptTouchHandlerEntry = null;
	}

	public boolean isTouchEnabled() {
		return m_bTouchEnabled;
	}

	public void setTouchEnabled(boolean enabled) {
		if(m_bTouchEnabled != enabled) {
			m_bTouchEnabled = enabled;
			if(m_bRunning) {
				if(enabled) {
					this.registerWithTouchDispatcher();
				} else {
					// have problems?
					CCTouchDispatcher.sharedDispatcher().removeDelegate(this);
// TODO					CCDirector.sharedDirector().getTouchDispatcher().removeDelegate(this);
				}
			}
		}
	}

	public void setTouchMode(ccTouchesMode mode) {
		if(m_eTouchMode != mode) {
			m_eTouchMode = mode;

			if(m_bTouchEnabled) {
				setTouchEnabled(false);
				setTouchEnabled(true);
			}
		}
	}

	public ccTouchesMode getTouchMode() {
		return m_eTouchMode;
	}

	/** priority of the touch events. Default is 0 */

	public void setTouchPriority(int priority) {
		if(m_nTouchPriority != priority) {
			m_nTouchPriority = priority;

			if(m_bTouchEnabled) {
				setTouchEnabled(false);
				setTouchEnabled(true);
			}
		}
	}

	public int getTouchPriority() {
		return m_nTouchPriority;
	}

	/** whether or not it will receive Accelerometer events
	 * You can enable / disable accelerometer events with this property.
	 * @since v0.8.1
	 */

	public boolean isAccelerometerEnabled() {
		return m_bAccelerometerEnabled;
	}

	public void setAccelerometerEnabled(boolean enabled) {

		// TODO legacy -->

		if(enabled != m_bAccelerometerEnabled) {
			m_bAccelerometerEnabled = enabled;

			if(m_bRunning) {
				CCDirector pDirector = CCDirector.sharedDirector();
				if(enabled) {
// TODO					pDirector.getAccelerometer().setDelegate(this);

					// TODO legacy
					registerWithAccelerometer();
				} else {
// TODO					pDirector.getAccelerometer().setDelegate(NULL);

					// TODO legacy
					unregisterWithAccelerometer();
				}
			}
		}
	}

	public void setAccelerometerInterval(double interval) {
		if(m_bAccelerometerEnabled) {
			if(m_bRunning) {
				CCDirector pDirector = CCDirector.sharedDirector();
// TODO				pDirector.getAccelerometer().setAccelerometerInterval(interval);
			}
		}
	}

	/** whether or not it will receive keypad events
	 * You can enable / disable accelerometer events with this property.
	 * it's new in cocos2d-x
	 */

	public boolean isKeypadEnabled() {
		return m_bKeypadEnabled;
	}

	public void setKeypadEnabled(boolean enabled) {
		if (enabled != m_bKeypadEnabled) {
			m_bKeypadEnabled = enabled;

			if(m_bRunning) {
				CCDirector pDirector = CCDirector.sharedDirector();
				if (enabled) {
// TODO					pDirector.getKeypadDispatcher().addDelegate(this);

					// TODO legacy
					CCKeyDispatcher.sharedDispatcher().addDelegate(this, 0);
				} else {
// TODO					pDirector.getKeypadDispatcher().removeDelegate(this);

					// TODO legacy
					CCKeyDispatcher.sharedDispatcher().removeDelegate(this);
				}
			}
		}
	}

	/** Register keypad events handler */
	public void registerScriptKeypadHandler(int nHandler) {
		unregisterScriptKeypadHandler();
// TODO		m_pScriptKeypadHandlerEntry = CCScriptHandlerEntry.create(nHandler);
	}

	/** Unregister keypad events handler */
	public void unregisterScriptKeypadHandler() {
// TODO		m_pScriptKeypadHandlerEntry = null;
	}

	public void keyBackClicked() {
/* TODO
		if(m_pScriptKeypadHandlerEntry != null) {
			CCScriptEngineManager.sharedManager().getScriptEngine().executeLayerKeypadEvent(this, kTypeBackClicked);
		}
*/
	}

	public void keyMenuClicked() {
/* TODO
		if(m_pScriptKeypadHandlerEntry != null) {
			CCScriptEngineManager.sharedManager().getScriptEngine().executeLayerKeypadEvent(this, kTypeMenuClicked);
		}
*/
	}
/* TODO
	public CCTouchScriptHandlerEntry getScriptTouchHandlerEntry() {
		return m_pScriptTouchHandlerEntry;
	}

	public CCScriptHandlerEntry getScriptKeypadHandlerEntry() {
		return m_pScriptKeypadHandlerEntry;
	}

	public CCScriptHandlerEntry getScriptAccelerateHandlerEntry() {
		return m_pScriptAccelerateHandlerEntry;
	};
*/

	protected boolean m_bTouchEnabled;
	protected boolean m_bAccelerometerEnabled;
	protected boolean m_bKeypadEnabled;
/* TODO
	// Script touch events handler
	private CCTouchScriptHandlerEntry m_pScriptTouchHandlerEntry;
	private CCScriptHandlerEntry m_pScriptKeypadHandlerEntry;
	private CCScriptHandlerEntry m_pScriptAccelerateHandlerEntry;
*/
	private int m_nTouchPriority;
	private ccTouchesMode m_eTouchMode;
/* TODO
	private int excuteScriptTouchHandler(int nEventType, CCTouch pTouch) {
		return CCScriptEngineManager.sharedManager().getScriptEngine().executeLayerTouchEvent(this, nEventType, pTouch);
	}

	private int excuteScriptTouchHandler(int nEventType, CCSet pTouches) {
		return CCScriptEngineManager.sharedManager().getScriptEngine().executeLayerTouchesEvent(this, nEventType, pTouches);
	}
*/

	
	
	// TODO legacy -->



    protected int accelerometerUpdateRate = SensorManager.SENSOR_DELAY_GAME;

    protected final SensorManager sensorManager;
    protected final Sensor accelerometer;
    
    //added by DustinEwan
    public void enableAccelerometerWithRate(int rate) {
    	accelerometerUpdateRate = rate;
    	setAccelerometerEnabled(true);
    }
    
    public static CCLayer node() {
        return new CCLayer();
    }

    protected void registerWithAccelerometer() {
    	if (accelerometer != null) {
    		boolean registered = sensorManager.registerListener(this, accelerometer, accelerometerUpdateRate);
    		if (!registered) {
    	        Log.e("Layer", "Could not register accelerometer sensor listener!");
    		}
    	}
    }

    protected void unregisterWithAccelerometer() {
    	if (accelerometer != null) {
    		sensorManager.unregisterListener(this, accelerometer);
    	}
    	
    	/** reset the poll rate to GAME default */
    	accelerometerUpdateRate = SensorManager.SENSOR_DELAY_GAME;
    }
    
    public void ccAccelerometerChanged(float accelX, float accelY, float accelZ) {
		// Override to process accelerometer events.
    }
    
	public void onAccuracyChanged(Sensor sensor, int accuracy) {
		// Override to process sensor accuracy changes (for any registered sensors).
	}

	public void onSensorChanged(SensorEvent event) {
		// Override to process other sensor change events.
		// Make sure you this base implementation if you want accelerometer events passed.
		
		if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
			ccAccelerometerChanged(event.values[0], event.values[1], event.values[2]);
		}
	}

	//added by Ishaq 
	public boolean ccKeyDown(int keyCode, KeyEvent event) {
		assert false : "Layer# ccKeyDown override me";
		return CCKeyDispatcher.kEventHandled;
	}

	//added by Ishaq 
	public boolean ccKeyUp(int keyCode, KeyEvent event) {
		assert false : "Layer# ccKeyUp override me";
		return CCKeyDispatcher.kEventHandled;
	}
}

// end of layer group
/// @}
