/*
 * FreeOTP
 *
 * Authors: Nathaniel McCallum <npmccallum@redhat.com>
 *
 * Copyright (C) 2013  Nathaniel McCallum, Red Hat
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.fedorahosted.freeotp.add;

import java.util.List;

import org.fedorahosted.freeotp.R;
import org.fedorahosted.freeotp.Token;
import org.fedorahosted.freeotp.TokenPersistence;

import android.annotation.TargetApi;
import android.app.Activity;
import android.hardware.Camera;
import android.hardware.Camera.CameraInfo;
import android.hardware.Camera.Parameters;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.ImageView;
import android.widget.ProgressBar;

import com.squareup.picasso.Callback;
import com.squareup.picasso.Picasso;

public class ScanActivity extends Activity implements SurfaceHolder.Callback {
    private final CameraInfo    mCameraInfo  = new CameraInfo();
    private final ScanAsyncTask mScanAsyncTask;
    private final int           mCameraId;
    private Handler             mHandler;
    private Camera              mCamera;

    private static class AutoFocusHandler extends Handler implements Camera.AutoFocusCallback {
        private final Camera mCamera;

        public AutoFocusHandler(Camera camera) {
            mCamera = camera;
        }

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            mCamera.autoFocus(this);
        }

        @Override
        public void onAutoFocus(boolean success, Camera camera) {
            sendEmptyMessageDelayed(0, 1000);
        }
    }

    public static boolean haveCamera() {
        return findCamera(new CameraInfo()) >= 0;
    }

    private static int findCamera(CameraInfo cameraInfo) {
        int cameraId = Camera.getNumberOfCameras() - 1;

        // Find a back-facing camera, otherwise use the first camera.
        for (; cameraId > 0; cameraId--) {
            Camera.getCameraInfo(cameraId, cameraInfo);
            if (cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK)
                break;
        }

        return cameraId;
    }

    public ScanActivity() {
        super();

        mCameraId = findCamera(mCameraInfo);
        assert mCameraId >= 0;

        // Create the decoder thread
        mScanAsyncTask = new ScanAsyncTask() {
            @Override
            protected void onPostExecute(String result) {
                super.onPostExecute(result);
                Token token = TokenPersistence.addWithToast(ScanActivity.this, result);
                if (token == null || token.getImage() == null) {
                    finish();
                    return;
                }

                final ImageView image = (ImageView) findViewById(R.id.image);
                Picasso.with(ScanActivity.this)
                        .load(token.getImage())
                        .placeholder(R.drawable.scan)
                        .into(image, new Callback() {
                            @Override
                            public void onSuccess() {
                                findViewById(R.id.progress).setVisibility(View.INVISIBLE);
                                image.setAlpha(0.9f);
                                image.postDelayed(new Runnable() {
                                    @Override
                                    public void run() {
                                        finish();
                                    }
                                }, 2000);
                            }

                            @Override
                            public void onError() {
                                finish();
                            }
                        });
            }
        };
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.scan);
        mScanAsyncTask.execute();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        mScanAsyncTask.cancel(true);
    }

    @Override
    protected void onStart() {
        super.onStart();
        ((SurfaceView) findViewById(R.id.surfaceview)).getHolder().addCallback(this);
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        if (mCamera == null)
            return;

        // The code in this section comes from the developer docs. See:
        // http://developer.android.com/reference/android/hardware/Camera.html#setDisplayOrientation(int)

        int rotation = 0;
        switch (getWindowManager().getDefaultDisplay().getRotation()) {
        case Surface.ROTATION_0:
            rotation = 0;
            break;
        case Surface.ROTATION_90:
            rotation = 90;
            break;
        case Surface.ROTATION_180:
            rotation = 180;
            break;
        case Surface.ROTATION_270:
            rotation = 270;
            break;
        }

        int result = 0;
        switch (mCameraInfo.facing) {
        case Camera.CameraInfo.CAMERA_FACING_FRONT:
            result = (mCameraInfo.orientation + rotation) % 360;
            result = (360 - result) % 360; // compensate the mirror
            break;

        case Camera.CameraInfo.CAMERA_FACING_BACK:
            result = (mCameraInfo.orientation - rotation + 360) % 360;
            break;
        }

        mCamera.setDisplayOrientation(result);
        mCamera.startPreview();

        if (mHandler != null)
            mHandler.sendEmptyMessageDelayed(0, 100);
    }

    @Override
    @TargetApi(14)
    public void surfaceCreated(SurfaceHolder holder) {
        surfaceDestroyed(holder);

        try {
            // Open the camera
            mCamera = Camera.open(mCameraId);
            mCamera.setPreviewDisplay(holder);
            mCamera.setPreviewCallback(mScanAsyncTask);
        } catch (Exception e) {
            e.printStackTrace();
            surfaceDestroyed(holder);

            // Show error message
            findViewById(R.id.surfaceview).setVisibility(View.INVISIBLE);
            findViewById(R.id.progress).setVisibility(View.INVISIBLE);
            findViewById(R.id.window).setVisibility(View.INVISIBLE);
            findViewById(R.id.textview).setVisibility(View.VISIBLE);
            return;
        }

        // Set auto-focus mode
        Parameters params = mCamera.getParameters();
        List<String> modes = params.getSupportedFocusModes();
        if (modes.contains(Parameters.FOCUS_MODE_CONTINUOUS_PICTURE))
            params.setFocusMode(Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
        else if (modes.contains(Parameters.FOCUS_MODE_CONTINUOUS_VIDEO))
            params.setFocusMode(Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
        else if (modes.contains(Parameters.FOCUS_MODE_AUTO)) {
            params.setFocusMode(Parameters.FOCUS_MODE_AUTO);
            mHandler = new AutoFocusHandler(mCamera);
        }
        mCamera.setParameters(params);
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        if (mCamera == null)
            return;

        if (mHandler != null) {
            mCamera.cancelAutoFocus();
            mHandler.removeMessages(0);
            mHandler = null;
        }

        mCamera.stopPreview();
        mCamera.setPreviewCallback(null);
        mCamera.release();
        mCamera = null;
    }
}

@@ -2457,12 +2457,8 @@
 as()
- - 1
 ;%0A%0A 
@@ -2496,19 +2496,19 @@
 mera
-, o
+. O
 therwise
  use
@@ -2503,16 +2503,17 @@
 therwise
+,
  use the
@@ -2539,23 +2539,23 @@
     
-for (; 
+while (
 cameraId
  %3E 0
@@ -2554,24 +2554,14 @@
 raId
+--
  %3E 0
-; cameraId--
 ) %7B%0A
@@ -2632,16 +2632,33 @@
     if (
+cameraId == 0 %7C%7C 
 cameraIn

Fix barcode scanner preview orientation on Nexus 5x