package com.yidianling.uikit.custom.widget;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
import android.util.AttributeSet;
import android.view.View;

import com.yidianling.nimbase.common.util.sys.ScreenUtil;
import com.yidianling.im.R;


/**
 * Created by sunpingji.
 */
public class LoadingView extends View {

    private static final float DEFAULT_RADIUS = ScreenUtil.dip2px(5);
    private static final int DEFAULT_BALL_COLOR = 0xffffffff;
    private static final float DEFAULT_SPEED = (float) 0.5;

    private Paint paint = new Paint();

    private Paint paint2 = new Paint();

    private PointF leftBall;
    private PointF rightBall;

    //两个小球的碰撞参数
    private float handleLenRate = 1f;

    private float radius = DEFAULT_RADIUS;
    private float mv = 0.5f;
    private float maxTouchDistance = (float) (DEFAULT_RADIUS * 2.5);


    private int ballLeftColor = DEFAULT_BALL_COLOR;
    private int ballRightColor = DEFAULT_BALL_COLOR;


    //两个小球动画距离
    private float ballMoveDistance = (float) (DEFAULT_RADIUS * 3.5);

    //默认1秒 speed = 1/time;故speed=0.5表示2秒结束动画
    private float animationSpeed = DEFAULT_SPEED;

    private float baseX;
    private float baseY;

    private boolean isNeedAnimation;

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

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

    public LoadingView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(attrs);
    }

    public void reset() {
        if (leftBall != null && rightBall != null) {
            leftBall.x = baseX;
            rightBall.x = baseX;
        }
    }

    public void setPaintMode(int mode) {
        paint.setStyle(mode == 0 ? Paint.Style.STROKE : Paint.Style.FILL);
        paint2.setStyle(mode == 0 ? Paint.Style.STROKE : Paint.Style.FILL);
        invalidate();

        leftBall.x = rightBall.x;
    }

    private void init(AttributeSet attrs) {

        TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.LoadingView);
        ballLeftColor = a.getColor(R.styleable.LoadingView_left_ball_color, DEFAULT_BALL_COLOR);
        ballRightColor = a.getColor(R.styleable.LoadingView_right_ball_color, DEFAULT_BALL_COLOR);
        radius = a.getFloat(R.styleable.LoadingView_radius, DEFAULT_RADIUS);
        maxTouchDistance = (float) (radius * 2.5);
        ballMoveDistance = (float) (radius * 3.5);
        animationSpeed = a.getFloat(R.styleable.LoadingView_animation_speed, DEFAULT_SPEED);
        isNeedAnimation = a.getBoolean(R.styleable.LoadingView_need_animation, true);
        a.recycle();
        paint.setColor(ballLeftColor);
        paint.setStyle(Paint.Style.FILL);
        paint.setAntiAlias(true);

        paint2.setColor(ballRightColor);
        paint2.setStyle(Paint.Style.FILL);
        paint2.setAntiAlias(true);
    }

    private void initMetaballs() {
        baseX = this.getMeasuredWidth() / 2;
        baseY = this.getMeasuredHeight() / 2;
        leftBall = new PointF(baseX, baseY);
        rightBall = new PointF(baseX, baseY);
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        if (changed) {
            initMetaballs();
        }
    }

    private float[] getVector(float radians, float length) {
        float x = (float) (Math.cos(radians) * length);
        float y = (float) (Math.sin(radians) * length);
        return new float[]{
                x, y
        };
    }

    /**
     * @param canvas          画布
     * @param v               控制两个圆连接时候长度，间接控制连接线的粗细，该值为1的时候连接线为直线
     * @param handle_len_rate
     * @param maxDistance
     */
    private void metaball(Canvas canvas, float v, float handle_len_rate, float maxDistance) {

        float d = getDistance();

        float radius1 = radius;
        float radius2 = radius;
        float pi2 = (float) (Math.PI / 2);
        float u1, u2;


        if (d > maxDistance) {
            canvas.drawCircle(rightBall.x, rightBall.y, radius, paint2);
        } else {
            canvas.drawCircle(rightBall.x, rightBall.y, radius, paint2);
        }

        if (radius1 == 0 || radius2 == 0) {
            return;
        }

        if (d > maxDistance || d <= Math.abs(radius1 - radius2)) {
            return;
        } else if (d < radius1 + radius2) {
            u1 = (float) Math.acos((radius1 * radius1 + d * d - radius2 * radius2) /
                    (2 * radius1 * d));
            u2 = (float) Math.acos((radius2 * radius2 + d * d - radius1 * radius1) /
                    (2 * radius2 * d));
        } else {
            u1 = 0;
            u2 = 0;
        }
        float[] centermin = new float[]{rightBall.x - leftBall.x, rightBall.y - leftBall.y};

        float angle1 = (float) Math.atan2(centermin[1], centermin[0]);
        float angle2 = (float) Math.acos((radius1 - radius2) / d);
        float angle1a = angle1 + u1 + (angle2 - u1) * v;
        float angle1b = angle1 - u1 - (angle2 - u1) * v;
        float angle2a = (float) (angle1 + Math.PI - u2 - (Math.PI - u2 - angle2) * v);
        float angle2b = (float) (angle1 - Math.PI + u2 + (Math.PI - u2 - angle2) * v);


        float[] p1a1 = getVector(angle1a, radius1);
        float[] p1b1 = getVector(angle1b, radius1);
        float[] p2a1 = getVector(angle2a, radius2);
        float[] p2b1 = getVector(angle2b, radius2);

        float[] p1a = new float[]{p1a1[0] + leftBall.x, p1a1[1] + leftBall.y};
        float[] p1b = new float[]{p1b1[0] + leftBall.x, p1b1[1] + leftBall.y};
        float[] p2a = new float[]{p2a1[0] + rightBall.x, p2a1[1] + rightBall.y};
        float[] p2b = new float[]{p2b1[0] + rightBall.x, p2b1[1] + rightBall.y};


        float[] p1_p2 = new float[]{p1a[0] - p2a[0], p1a[1] - p2a[1]};

        float totalRadius = (radius1 + radius2);
        float d2 = Math.min(v * handle_len_rate, getLength(p1_p2) / totalRadius);
        d2 *= Math.min(1, d * 2 / (radius1 + radius2));

        radius1 *= d2;
        radius2 *= d2;

        float[] sp1 = getVector(angle1a - pi2, radius1);
        float[] sp2 = getVector(angle2a + pi2, radius2);
        float[] sp3 = getVector(angle2b - pi2, radius2);
        float[] sp4 = getVector(angle1b + pi2, radius1);


        Path path1 = new Path();
        path1.moveTo(p1a[0], p1a[1]);
        path1.cubicTo(p1a[0] + sp1[0], p1a[1] + sp1[1], p2a[0] + sp2[0], p2a[1] + sp2[1], p2a[0], p2a[1]);
        path1.lineTo(p2b[0], p2b[1]);
        path1.cubicTo(p2b[0] + sp3[0], p2b[1] + sp3[1], p1b[0] + sp4[0], p1b[1] + sp4[1], p1b[0], p1b[1]);
        path1.lineTo(p1a[0], p1a[1]);
        path1.close();
        canvas.drawPath(path1, paint2);

    }


    public float getBallMoveDistance() {
        return ballMoveDistance;
    }

    private float getLength(float[] b) {
        return (float) Math.sqrt(b[0] * b[0] + b[1] * b[1]);
    }

    private float getDistance() {
        float x = leftBall.x - rightBall.x;
        float y = leftBall.y - rightBall.y;
        float d = x * x + y * y;
        return (float) Math.sqrt(d);
    }

    public void setBaseX(float scale) {
        if (leftBall == null || rightBall == null) {
            return;
        }
        leftBall.x = baseX - scale * ballMoveDistance / 2;
        rightBall.x = baseX + scale * ballMoveDistance / 2;
        invalidate();
    }

    public void setNeedAnimation(boolean animation) {
        isNeedAnimation = animation;
        invalidate();
    }

    private void startAnimation() {
        if (isNeedAnimation) {
            float input = (float) ((System.currentTimeMillis() % 10000 * animationSpeed % 1000) * 1.000 / 1000);
            float ratio = (float) ((Math.sin(2 * Math.PI * input)) * ballMoveDistance);
            leftBall.x = baseX + ratio;
            rightBall.x = baseX - ratio;
            float scaleRatio = (float) ((Math.cos(2 * Math.PI * input)) * DEFAULT_RADIUS * 0.2);
            radius = (float) (DEFAULT_RADIUS * 0.8 + scaleRatio);
            maxTouchDistance = (float) (radius * 2.5);
            invalidate();
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (leftBall == null || rightBall == null) {
            initMetaballs();
        }
        canvas.drawCircle(leftBall.x, leftBall.y, radius, paint);
        metaball(canvas, mv, handleLenRate, maxTouchDistance);
        startAnimation();
    }

}
