package com.chenzy.owloading;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.CornerPathEffect;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PixelFormat;
import android.graphics.PorterDuffXfermode;
import android.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;

/**
 * 仿守望先锋的loading加载
 * Created by zhangyu on 2016/11/28.
 */

public class OWLoadingView extends SurfaceView {
    private static final String TAG = "OWLoadingView";
    //view的宽度和高度
    private int viewWidth, viewHeight;
    //view的中心点
    private Point center = new Point();
    //六边形的中心点
    private Point[] hexagonCenters = new Point[6];
    //六边形实例
    private Hexagon[] hexagons = new Hexagon[7];
    //六边形之间的间距
    private float space;
    //六边形的半径
    private float hexagonRadius;
    private int color = Color.parseColor("#ff9900");//默认橙色
    private Paint paint;
    private float sin30 = (float) Math.sin(30f * 2f * Math.PI / 360f);
    private float cos30 = (float) Math.cos(30f * 2f * Math.PI / 360f);
    //进行显示动画和进行隐藏动画的标志常量
    private final int ShowAnimatorFlag = 0x1137, HideAnimatorFlag = 0x1139;
    private int nowAnimatorFlag = ShowAnimatorFlag;
    //触发下一个动画开始的缩放临界点值
    private final float scaleCritical = 0.7f;
    //控制动画运行的标示位
    private boolean runAnim = false;
    private SurfaceHolder surfaceHolder;
    //基准数据是否已初始化
    private boolean baseDataInited = false;
    //是否自动开始动画
    private boolean autoStartAnim = false;

    public OWLoadingView(Context context) {
        super(context);
        init();
    }

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

    public OWLoadingView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();

    }

    private void init() {
        surfaceHolder = getHolder();
        setZOrderOnTop(true);
        surfaceHolder.setFormat(PixelFormat.TRANSLUCENT);//背景透明
        initPaint();
    }

    /**
     * 绘制图案
     */
    private void draw() {
        Canvas canvas = surfaceHolder.lockCanvas();
        if(canvas == null)
            return;
        paint.setXfermode(new PorterDuffXfermode(android.graphics.PorterDuff.Mode.CLEAR));
        canvas.drawPaint(paint);
        paint.setXfermode(new PorterDuffXfermode(android.graphics.PorterDuff.Mode.DST_OVER));

        for (int i = 0; i < 7; i++) {
            hexagons[i].drawHexagon(canvas, paint);
        }
        surfaceHolder.unlockCanvasAndPost(canvas);
    }

    private Runnable animRunnable = new Runnable() {
        @Override
        public void run() {
            try {
                while (runAnim) {
                    Thread.sleep(2);
                    flush();
                    draw();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    };

    //重置六边形数据
    private void resetHexagons() {
        for (int i = 0; i < hexagons.length; i++) {
            hexagons[i].setScale(0);
            hexagons[i].setAlpha(0);
        }
    }

    private void initPaint() {
        paint = new Paint();
        paint.setAntiAlias(true);
        paint.setStyle(Paint.Style.FILL);
        paint.setColor(color);
    }

    /**
     * 设置颜色
     *
     * @param color
     */
    public void setColor(int color) {
        this.color = color;
        paint.setColor(color);
    }

    /**
     * 开始动画
     *
     * @return 动画是否启动成功,true 启动成功;false 启动失败
     */
    public boolean startAnim() {
        if (runAnim || !baseDataInited)
            return false;
        runAnim = true;
        new Thread(animRunnable).start();
        setVisibility(View.VISIBLE);
        return true;
    }

    /**
     * 中止动画
     */
    public void stopAnim() {
        runAnim = false;
        nowAnimatorFlag = ShowAnimatorFlag;
        resetHexagons();
        draw();
        setVisibility(View.GONE);
    }

    /**
     * 设置初始化完成后是否自动开始动画。
     * 如果开启,建议在页面onStop()时调用{@link #stopAnim}()方法中止动画,节约内存开销
     * @param autoStartAnim
     */
    public void setAutoStartAnim(boolean autoStartAnim) {
        this.autoStartAnim = autoStartAnim;
    }

    /**
     * 初始化六边形中心店坐标
     */
    private void initHexagonCenters() {
        //1.5*r 加上竖直方向space 等于R*cos30(博客里画的图是不匹配的)
        float bigR = (float) ((1.5 * hexagonRadius + space) / cos30);
        hexagonCenters[0] = new Point(center.x - bigR * sin30, center.y - bigR * cos30);
        hexagonCenters[1] = new Point(center.x + bigR * sin30, center.y - bigR * cos30);
        hexagonCenters[2] = new Point(center.x + bigR, center.y);
        hexagonCenters[3] = new Point(center.x + bigR * sin30, center.y + bigR * cos30);
        hexagonCenters[4] = new Point(center.x - bigR * sin30, center.y + bigR * cos30);
        hexagonCenters[5] = new Point(center.x - bigR, center.y);

        for (int i = 0; i < 6; i++) {
            hexagons[i] = new Hexagon(hexagonCenters[i], hexagonRadius);
        }
        hexagons[6] = new Hexagon(center, hexagonRadius);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        viewHeight = getMeasuredHeight();
        viewWidth = getMeasuredWidth();
        if (viewWidth != 0 && viewHeight != 0) {
            center.x = viewWidth / 2f;
            center.y = viewHeight / 2f;
            float spaceRate = 1 / 100f;
            space = viewWidth <= viewHeight ? viewWidth * spaceRate : viewHeight * spaceRate;
            hexagonRadius = (float) ((viewWidth - 2 * space) / (3 * Math.sqrt(3)));
            initHexagonCenters();
            //圆角处理
            paint.setPathEffect(new CornerPathEffect(hexagonRadius * 0.1f));
            baseDataInited = true;
        }
    }

    /**
     * 刷新数据
     */
    private void flush() {
        if (nowAnimatorFlag == ShowAnimatorFlag) {//逐个显示出来
            hexagons[0].addScale();
            hexagons[0].addAlpha();
            for (int i = 0; i < hexagons.length - 1; i++) {
                if (hexagons[i].getScale() >= scaleCritical) {
                    hexagons[i + 1].addScale();
                    hexagons[i + 1].addAlpha();
                }
            }

            if (hexagons[6].getScale() == 1) {//当最后一个六边形都完全显示时,切换模式,下一轮逐个消失
                nowAnimatorFlag = HideAnimatorFlag;
            }

        } else {//逐个消失
            hexagons[0].subScale();
            hexagons[0].subAlpha();
            for (int i = 0; i < hexagons.length - 1; i++) {
                if (hexagons[i].getScale() <= 1 - scaleCritical) {
                    hexagons[i + 1].subScale();
                    hexagons[i + 1].subAlpha();
                }
            }
            if (hexagons[6].getScale() == 0) {//当最后一个六边形都完全消失时,切换模式,下一轮逐个开始显示
                nowAnimatorFlag = ShowAnimatorFlag;
            }
        }
    }

    /**
     * 六边形
     */
    private class Hexagon {

        //缩放值
        private float scale = 0;
        //透明度
        private int alpha = 0;
        public Point centerPoint;
        public float radius;
        //六个顶点
        private Point[] vertexs = new Point[6];
        //缩放程度每次改变量 变化范围为[0,1]
        private final float scaleChange = 0.07f;
        //透明度每次改变量 变化范围为[0,255]
        private final int alpahChange = 18;

        public Hexagon(Point centerPoint, float radius) {
            this.centerPoint = centerPoint;
            this.radius = radius;
            calculatePointsPosition();
        }

        public void drawHexagon(Canvas canvas, Paint paint) {
            paint.setAlpha(alpha);
            canvas.drawPath(getPath(), paint);
        }

        private int calculatePointsPosition() {
            if (centerPoint == null) {
                return -1;
            }
            //从最上方顺时针数1-6给各顶点标序号 共6个点
            vertexs[0] = new Point(centerPoint.x, centerPoint.y - radius * scale);
            vertexs[1] = new Point(centerPoint.x + radius * cos30 * scale, centerPoint.y - radius * sin30 * scale);
            vertexs[2] = new Point(centerPoint.x + radius * cos30 * scale, centerPoint.y + radius * sin30 * scale);
            vertexs[3] = new Point(centerPoint.x, centerPoint.y + radius * scale);
            vertexs[4] = new Point(centerPoint.x - radius * cos30 * scale, centerPoint.y + radius * sin30 * scale);
            vertexs[5] = new Point(centerPoint.x - radius * cos30 * scale, centerPoint.y - radius * sin30 * scale);
            return 1;
        }


        private Path getPath() {
            Path path = new Path();
            for (int i = 0; i < 6; i++) {
                if (i == 0)
                    path.moveTo(vertexs[i].x, vertexs[i].y);
                else
                    path.lineTo(vertexs[i].x, vertexs[i].y);
            }
            path.close();
            return path;
        }

        /**
         * 设置透明度
         *
         * @param alpha
         */
        public void setAlpha(int alpha) {
            this.alpha = alpha;
        }

        public int getAlpha() {
            return alpha;
        }


        /**
         * 设置缩放比例
         *
         * @param scale
         */
        public void setScale(float scale) {
            this.scale = scale;
            calculatePointsPosition();
        }

        public void addScale() {
            if (scale == 1)
                return;

            scale += scaleChange;
            scale = scale > 1 ? 1 : scale;
            calculatePointsPosition();
        }

        public void subScale() {
            if (scale == 0) {
                return;
            }
            scale -= scaleChange;
            scale = scale < 0 ? 0 : scale;
            calculatePointsPosition();
        }

        public void addAlpha() {
            if (alpha == 255) {
                return;
            }
            alpha += alpahChange;
            alpha = alpha > 255 ? 255 : alpha;
        }

        public void subAlpha() {
            if (alpha == 0) {
                return;
            }
            alpha -= alpahChange;
            alpha = alpha < 0 ? 0 : alpha;
        }

        /**
         * 获取当前缩放比例
         *
         * @return
         */
        public float getScale() {
            return scale;
        }
    }

    private class Point {
        public float x, y;

        public Point(float x, float y) {
            this.x = x;
            this.y = y;
        }

        public Point() {
        }
    }

    @Override
    public void onWindowFocusChanged(boolean hasWindowFocus) {
        super.onWindowFocusChanged(hasWindowFocus);
        Log.d(TAG,"onWindowFocusChanged  "+hasWindowFocus);
        if(hasWindowFocus && autoStartAnim){
            startAnim();
        }
    }

}