package com.yuqirong.screenlockview.view;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

import com.yuqirong.screenlockview.R;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by yuqirong on 2016/4/20.
 */
public class ScreenLockView extends View {

    private static final String TAG = "ScreenLockView";
    // 错误格子的图片
    private Bitmap errorBitmap;
    // 正常格子的图片
    private Bitmap normalBitmap;
    // 手指按下时格子的图片
    private Bitmap pressedBitmap;
    // 错误时连线的图片
    private Bitmap lineErrorBitmap;
    // 手指按住时连线的图片
    private Bitmap linePressedBitmap;
    // 偏移量，使九宫格在屏幕中央
    private int offset;
    // 九宫格的九个格子是否已经初始化
    private boolean init;
    // 格子的半径
    private int radius;
    // 密码
    private String password = "123456";
    // 九个格子
    private Point[][] points = new Point[3][3];
    private int width;
    private int height;
    private Matrix matrix = new Matrix();
    private float moveX = -1;
    private float moveY = -1;
    // 是否手指在移动
    private boolean isMove;
    // 是否可以触摸
    private boolean isTouch = true;
    // 用来存储记录被按下的点
    private List<Point> pressedPoint = new ArrayList<>();
    // 屏幕解锁监听器
    private OnScreenLockListener listener;
    private Runnable runnable = new Runnable() {
        @Override
        public void run() {
            isTouch = true;
            reset();
            invalidate();
        }
    };

    public ScreenLockView(Context context) {
        this(context, null);
    }

    public ScreenLockView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public ScreenLockView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        errorBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.bitmap_error);
        normalBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.bitmap_normal);
        pressedBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.bitmap_pressed);
        lineErrorBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.line_error);
        linePressedBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.line_pressed);
        radius = normalBitmap.getWidth() / 2;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        if (widthSize > heightSize) {
            offset = (widthSize - heightSize) / 2;
        } else {
            offset = (heightSize - widthSize) / 2;
        }
        setMeasuredDimension(widthSize, heightSize);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (!init) {
            width = getWidth();
            height = getHeight();
            initPoint();
            init = true;
        }
        // 画九宫格的格子
        drawPoint(canvas);

        if (moveX != -1 && moveY != -1) {
            // 画直线
            drawLine(canvas);
        }
    }

    // 画直线
    private void drawLine(Canvas canvas) {

        // 将pressedPoint中的所有格子依次遍历，互相连线
        for (int i = 0; i < pressedPoint.size() - 1; i++) {
            // 得到当前格子
            Point point = pressedPoint.get(i);
            // 得到下一个格子
            Point nextPoint = pressedPoint.get(i + 1);
            // 旋转画布
            canvas.rotate(RotateDegrees.getDegrees(point, nextPoint), point.getX(), point.getY());

            matrix.reset();
            // 根据距离设置拉伸的长度
            matrix.setScale(getDistance(point, nextPoint) / linePressedBitmap.getWidth(), 1f);
            // 进行平移
            matrix.postTranslate(point.getX(), point.getY() - linePressedBitmap.getWidth() / 2);


            if (point.getState() == Point.PRESSED_MODE) {
                canvas.drawBitmap(linePressedBitmap, matrix, null);
            } else {
                canvas.drawBitmap(lineErrorBitmap, matrix, null);
            }
            // 把画布旋转回来
            canvas.rotate(-RotateDegrees.getDegrees(point, nextPoint), point.getX(), point.getY());
        }

        // 如果是手指在移动的情况
        if (isMove) {
            Point lastPoint = pressedPoint.get(pressedPoint.size() - 1);
            canvas.rotate(RotateDegrees.getDegrees(lastPoint, moveX, moveY), lastPoint.getX(), lastPoint.getY());

            matrix.reset();
            Log.i(TAG, "the distance : " + getDistance(lastPoint, moveX, moveY) / linePressedBitmap.getWidth());
            matrix.setScale(getDistance(lastPoint, moveX, moveY) / linePressedBitmap.getWidth(), 1f);
            matrix.postTranslate(lastPoint.getX(), lastPoint.getY() - linePressedBitmap.getWidth() / 2);
            canvas.drawBitmap(linePressedBitmap, matrix, null);

            canvas.rotate(-RotateDegrees.getDegrees(lastPoint, moveX, moveY), lastPoint.getX(), lastPoint.getY());
        }
    }

    // 根据point和坐标点计算出之间的距离
    private float getDistance(Point point, float moveX, float moveY) {
        Point b = new Point(moveX,moveY,null);
        return getDistance(point,b);
    }

    // 根据两个point计算出之间的距离
    private float getDistance(Point point, Point nextPoint) {
        return (float) Math.sqrt(Math.pow(nextPoint.getX() - point.getX(), 2f) + Math.pow(nextPoint.getY() - point.getY(), 2f));
    }


    // 画九宫格的格子
    private void drawPoint(Canvas canvas) {
        for (int i = 0; i < points.length; i++) {
            for (int j = 0; j < points[i].length; j++) {
                int state = points[i][j].getState();
                if (state == Point.NORMAL_MODE) {
                    canvas.drawBitmap(normalBitmap, points[i][j].getX() - radius, points[i][j].getY() - radius, null);
                } else if (state == Point.PRESSED_MODE) {
                    canvas.drawBitmap(pressedBitmap, points[i][j].getX() - radius, points[i][j].getY() - radius, null);
                } else {
                    canvas.drawBitmap(errorBitmap, points[i][j].getX() - radius, points[i][j].getY() - radius, null);
                }
            }
        }
    }

    // 重置节点
    private void reset(){
        for (int i = 0; i < points.length; i++) {
            for (int j = 0; j < points[i].length; j++) {
                points[i][j].setState(Point.NORMAL_MODE);
            }
        }
        pressedPoint.clear();
    }

    // 初始化九个格子
    private void initPoint() {
        points[0][0] = new Point(width / 4, offset + width / 4, "0");
        points[0][1] = new Point(width / 2, offset + width / 4, "1");
        points[0][2] = new Point(width * 3 / 4, offset + width / 4, "2");

        points[1][0] = new Point(width / 4, offset + width / 2, "3");
        points[1][1] = new Point(width / 2, offset + width / 2, "4");
        points[1][2] = new Point(width * 3 / 4, offset + width / 2, "5");

        points[2][0] = new Point(width / 4, offset + width * 3 / 4, "6");
        points[2][1] = new Point(width / 2, offset + width * 3 / 4, "7");
        points[2][2] = new Point(width * 3 / 4, offset + width * 3 / 4, "8");
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (isTouch) {
            float x = event.getX();
            float y = event.getY();
            Point point;
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    point = isPoint(x, y);
                    if (point != null) {
                        point.setState(Point.PRESSED_MODE);
                        pressedPoint.add(point);
                    }
                    break;
                case MotionEvent.ACTION_MOVE:
                    if (pressedPoint.size() > 0) {
                        point = isPoint(x, y);
                        if (point != null) {
                            if (!crossPoint(point)) {
                                point.setState(Point.PRESSED_MODE);
                                pressedPoint.add(point);
                            }
                        }
                        moveX = x;
                        moveY = y;
                        isMove = true;
                    }
                    break;
                case MotionEvent.ACTION_UP:
                    isMove = false;
                    String tempPwd = "";
                    for (Point p : pressedPoint) {
                        tempPwd += p.getMark();
                    }
                    if (listener != null) {
                        listener.getStringPassword(tempPwd);
                    }

                    if (tempPwd.equals(password)) {
                        if (listener != null) {
                            listener.isPassword(true);
                        }
                    } else {
                        for (Point p : pressedPoint) {
                            p.setState(Point.ERROR_MODE);
                        }
                        isTouch = false;
                        this.postDelayed(runnable, 1000);
                        if (listener != null) {
                            listener.isPassword(false);
                        }
                    }
                    break;
            }
            invalidate();
        }
        return true;
    }

    // 是否已经被包含在pressedPoint里
    private boolean crossPoint(Point point) {
        if (pressedPoint.contains(point)) {
            return true;
        }
        return false;
    }

    // 该触摸点是否为某个格子
    private Point isPoint(float x, float y) {
        Point point;
        for (int i = 0; i < points.length; i++) {
            for (int j = 0; j < points[i].length; j++) {
                point = points[i][j];
                if (isContain(point, x, y)) {
                    return point;
                }
            }
        }
        return null;
    }

    // 该点(x，y)是否被包含
    private boolean isContain(Point point, float x, float y) {
        // 该点的(x,y)与圆心的距离若小于半径就是被包含了
        return Math.sqrt(Math.pow(x - point.getX(), 2f) + Math.pow(y - point.getY(), 2f)) <= radius;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public interface OnScreenLockListener {
        public void getStringPassword(String password);
        public void isPassword(boolean flag);
    }


    public void setOnScreenLockListener(OnScreenLockListener listener) {
        this.listener = listener;
    }

}
