package de.reinhardt_karlheinz.pcc.android.plugins.remote_minecraft;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.os.RemoteException;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;

public class RemoteMinecraftActivity extends Activity implements
    SensorEventListener {

  private static final String TAG = "RemoteMinecraftActivity";

  // private SensorManager sm;
  /* sensor data */
  // @http://pastebin.com/c1MNT5x7
  SensorManager m_sensorManager;

  float[] m_lastMagFields;

  float[] m_lastAccels;

  private float[] m_rotationMatrix = new float[16];

  private float[] m_remappedR = new float[16];

  private float[] m_orientation = new float[4];

  /* fix random noise by averaging tilt values */
  final static int AVERAGE_BUFFER = 30;

  float[] m_prevPitch = new float[AVERAGE_BUFFER];

  float m_lastPitch = 0.f;

  float m_lastYaw = 0.f;

  /* current index int m_prevEasts */
  int m_pitchIndex = 0;

  float[] m_prevRoll = new float[AVERAGE_BUFFER];

  float m_lastRoll = 0.f;

  /* current index into m_prevTilts */
  int m_rollIndex = 0;

  /* center of the rotation */
  private float m_tiltCentreX = 0.f;

  private float m_tiltCentreY = 0.f;

  private float m_tiltCentreZ = 0.f;

  private boolean alreadyStarted = false;

  @Override
  public void onCreate(Bundle savedInstanceState) {
    if (alreadyStarted == false) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.minecraft);
      // setViews();//FIXME
      Log.d(TAG, "act started");
      m_sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
      registerListeners();
      // TiltCalc tc = new TiltCalc(getBaseContext());
      bindToPCCService();
      alreadyStarted = true;
    }
  }

  // FIXME
  private void setViews() {
    setContentView(R.layout.pcc_rmt_mc);
    FrameLayout left = (FrameLayout) findViewById(R.id.frameLayout1);
    FrameLayout right = (FrameLayout) findViewById(R.id.frameLayout2);
    View leftView = findViewById(R.layout.headctrl);
    left.addView(leftView);
    View rightView = findViewById(R.layout.move_btns);
    right.addView(rightView);
  }

  private void registerListeners() {
    m_sensorManager.registerListener(this,
        m_sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD),
        SensorManager.SENSOR_DELAY_GAME);
    m_sensorManager.registerListener(this,
        m_sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
        SensorManager.SENSOR_DELAY_GAME);
  }

  private void unregisterListeners() {
    m_sensorManager.unregisterListener(this);
  }

  /**
   * not needed yet
   */
  double delayYaw = 5;

  double delayRoll = 7.5f;

  double delayPitch = 7.5f;

  private void computeOrientation() {
    if (SensorManager.getRotationMatrix(m_rotationMatrix, null, m_lastAccels,
        m_lastMagFields)) {
      SensorManager.getOrientation(m_rotationMatrix, m_orientation);

      /* 1 radian = 57.2957795 degrees */
      /*
       * [0] : yaw, rotation around z axis [1] : pitch, rotation around x axis
       * [2] : roll, rotation around y axis
       */
      float yaw = m_orientation[0] * 57.2957795f;
      float pitch = m_orientation[1] * 57.2957795f;
      float roll = m_orientation[2] * 57.2957795f;

      /* append returns an average of the last 10 values */
      m_lastYaw = m_filters[0].append(yaw);
      m_lastPitch = m_filters[1].append(pitch);
      m_lastRoll = m_filters[2].append(roll);
      // TextView rt = (TextView) findViewById(R.id.roll);
      // TextView pt = (TextView) findViewById(R.id.pitch);
      // TextView yt = (TextView) findViewById(R.id.yaw);
      // yt.setText("azi z: " + m_lastYaw);
      // pt.setText("pitch x: " + m_lastPitch);
      // rt.setText("roll y: " + m_lastRoll);
      // Log.d("tag", "yaw: " + m_lastYaw + " pitch: " + m_lastPitch
      // + " roll: " + m_lastRoll);
      // pitch //TODO shorter
      if (m_lastPitch >= delayRoll) {
        ptch = 1;
      }
      if (m_lastPitch <= -delayRoll) {
        ptch = -1;
      }
      if (m_lastPitch < delayRoll && m_lastPitch > -delayRoll) {
        ptch = 0;
      }
      // send pitch
      if (lastptch != ptch) {
        try {
          pccSvConn.getPccService().sendMsg("ptch_" + ptch);
        } catch (RemoteException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
        }// FIXME
        lastptch = ptch;
      }
      // roll
      if (m_lastRoll >= delayPitch) {
        rll = 1;
      } else {
        if (m_lastRoll <= -delayPitch) {
          rll = -1;
        } else {
          rll = 0;
        }
      }
      // send roll
      if (lastrll != rll) {
        try {
          pccSvConn.getPccService().sendMsg("rll_" + rll);
        } catch (RemoteException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
        }// FIXME
        lastrll = rll;
      }
    }
  }

  int rll = 0;

  int ptch = 0;

  int lastptch = 0;

  int lastrll = 0;

  // @Override
  // protected void onResume() {
  // super.onResume();
  // // Sensor acc_sensor = sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
  //
  // // register this class as a listener for the orientation and
  // // accelerometer sensors
  // // sm.registerListener(this, acc_sensor, SensorManager.SENSOR_DELAY_UI);
  // }

  private final TouchVector referenceVector = new TouchVector(0, 0, 0, 1);

  float lastXPos = 0;

  float lastYPos = 0;

  @Override
  public boolean onTouchEvent(MotionEvent me) {
    // TODO set intervall

    int action = me.getAction();
    float currentXPosition = me.getX();
    float currentYPosition = me.getY();

    // Log.v(TAG, "Action = " + action);
    // Log.v(TAG, "X = " + currentXPosition + "Y = " + currentYPosition);
    if (action == MotionEvent.ACTION_DOWN) {
      // lastXPos = 0;
      // lastYPos = 0;
      lastXPos = me.getX();
      lastYPos = me.getY();
    }
    if (action == MotionEvent.ACTION_MOVE) {
      // calculate vector
      TouchVector vector = new TouchVector(lastXPos, currentXPosition,
          lastYPos, currentYPosition);

      // McGlobals.svr.sendMsg("angl("+ angle+")lnght("+length+")");
      try {
        pccSvConn.getPccService().sendMsg(
            "X(" + vector.getX() + ")Y(" + vector.getY() + ")");
      } catch (RemoteException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }// FIXME

      // Toast.makeText(getBaseContext(), "" + angle, 10).show();

      // do something
      lastXPos = currentXPosition;
      lastYPos = currentYPosition;

    }

    if (action == MotionEvent.ACTION_UP) {
      // do something
      // lastXPos = 0;
      // lastYPos = 0;
      Log.v(TAG, "finger released");
    }

    return true;
  }

  @Override
  public void onDestroy() {
    unregisterListeners();
    unbindService(pccSvConn);
    super.onDestroy();
  }

  @Override
  public void onPause() {
    unregisterListeners();
    super.onPause();
  }

  @Override
  public void onResume() {
    registerListeners();
    super.onResume();
  }

  @Override
  public void onAccuracyChanged(Sensor sensor, int accuracy) {
    // TODO Auto-generated method stub

  }

  @Override
  public void onSensorChanged(SensorEvent event) {
    if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
      accel(event);
    }
    if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
      mag(event);
    }
  }

  private void accel(SensorEvent event) {
    if (m_lastAccels == null) {
      m_lastAccels = new float[3];
    }

    System.arraycopy(event.values, 0, m_lastAccels, 0, 3);

    /*
     * if (m_lastMagFields != null) { computeOrientation(); }
     */
  }

  private void mag(SensorEvent event) {
    if (m_lastMagFields == null) {
      m_lastMagFields = new float[3];
    }

    System.arraycopy(event.values, 0, m_lastMagFields, 0, 3);

    if (m_lastAccels != null) {
      computeOrientation();
    }
  }

  Filter[] m_filters = { new Filter(), new Filter(), new Filter() };

  private class Filter {
    static final int AVERAGE_BUFFER = 10;

    float[] m_arr = new float[AVERAGE_BUFFER];

    int m_idx = 0;

    public float append(float val) {
      m_arr[m_idx] = val;
      m_idx++;
      if (m_idx == AVERAGE_BUFFER)
        m_idx = 0;
      return avg();
    }

    public float avg() {
      float sum = 0;
      for (float x : m_arr)
        sum += x;
      return sum / AVERAGE_BUFFER;
    }

  }

  // @Override
  // public void onAccuracyChanged(Sensor sensor, int accuracy) {
  // // TODO Auto-generated method stub

  // }

  // float[] values;
  //
  // @Override
  // public void onSensorChanged(SensorEvent event) {
  // values = event.values;
  // float[] R = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  // float[] orientation = sm.getOrientation(R, values);
  // Log.d("SENSOR LISTENER", "X: " + orientation[1] + "Y: "
  // + orientation[2] + "Z: " + orientation[0]);
  // }
  //
  // @Override
  // protected void onStop() {
  // // unregister listener
  // sm.unregisterListener(this);
  // super.onStop();
  // }
  // stuff for connection to PCC SERVICE
  private PCCServiceConnection pccSvConn;

  private static final String ACTION_PICK_SERVICE = "pcc.intent.action.PICK_PCCSERVICE";

  private static final String CATEG = "pcc.intent.category.PCC_PCCSERVICE";

  public void bindToPCCService() {
    Log.d("mcAct", "binding");
    pccSvConn = new PCCServiceConnection();
    Intent i = new Intent(ACTION_PICK_SERVICE);
    i.addCategory(CATEG);
    this.bindService(i, pccSvConn, Context.BIND_DEBUG_UNBIND);
  }

}
