package com.usai.apex.KPI;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.ColorDrawable;
import android.support.annotation.Nullable;
import android.text.Layout;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewParent;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Random;


/**
 * Created by macmini1 on 2018/3/28.
 */

public class PieChartView extends View {

//    private static final long serialVersionUID = 4564384597971491851L;

    private static float titleFontSize = 40.0f;
    private static float nameFontSize = 50.0f;
    private static float detal = 10;
    private static double M_PI = 3.14159265358979323846264338327950288;
    private static double M_PI_2 = 1.57079632679489661923132169163975144;

    public interface PieChartItemClickListener {

        void pieChartItemClicked(PieChartView pieChartView, ChartItem item);
        void pieChartCenterClicked(PieChartView pieChartView);
        void pieChartDidBeginTouch();
        void pieChartDidEndTouch();
    }

    public static class ChartItem implements Serializable {

        private static final long serialVersionUID = 1437379045091025768L;

        public String shortTitle;
        public boolean display = true;

        public int color = -1;
        public float value;
        public String title;
        public int titleColor = -1;

        private float startAngle;
        private float angle;
        private float endAngle;
        private boolean select;
        private PointF titlePosition;
        private float percentage;
        private Size titleSize;



        private int getColor() {
            if (color == -1) {
                String r,g,b;
                Random random = new Random();
                r = Integer.toHexString(random.nextInt(256)).toUpperCase();
                g = Integer.toHexString(random.nextInt(256)).toUpperCase();
                b = Integer.toHexString(random.nextInt(256)).toUpperCase();

                r = r.length()==1 ? "0" + r : r ;
                g = g.length()==1 ? "0" + g : g ;
                b = b.length()==1 ? "0" + b : b ;
                color = Color.parseColor("#" + r + g + b);
            }
            return color;
        }

        private int getTitleColor() {
            if (titleColor == -1) {
//                String r,g,b;
//                Random random = new Random();
//                r = Integer.toHexString(random.nextInt(256)).toUpperCase();
//                g = Integer.toHexString(random.nextInt(256)).toUpperCase();
//                b = Integer.toHexString(random.nextInt(256)).toUpperCase();
//
//                r = r.length()==1 ? "0" + r : r ;
//                g = g.length()==1 ? "0" + g : g ;
//                b = b.length()==1 ? "0" + b : b ;
//                titleColor = Color.parseColor("#" + r + g + b);
                titleColor = Color.WHITE;
            }
            return titleColor;
        }

        private PieChartView.Size measure() {

            Paint textPaint = new Paint();
            textPaint.setColor(getTitleColor());
            textPaint.setTextSize(titleFontSize);
            textPaint.setStyle(Paint.Style.FILL);
            //该方法即为设置基线上那个点到底是left,center,还是right  这里我设置为center
            textPaint.setTextAlign(Paint.Align.CENTER);


            Rect rect = new Rect();
            String msg = getMessage();
            textPaint.getTextBounds(msg, 0, msg.length(), rect);
            int width = rect.width();// 文字宽
            int height = rect.height();// 文字高

            Paint.FontMetrics fontMetrics = textPaint.getFontMetrics();
            float top = fontMetrics.top;//为基线到字体上边框的距离,即上图中的top
            float bottom = fontMetrics.bottom;//为基线到字体下边框的距离,即上图中的bottom
            float baseY = 0 - top / 2.0f - bottom / 2.0f;//基线中间点的y轴计算公式


            titleSize = new Size(width,height);
            return titleSize;
        }

        public float getPercentage() {
            return percentage;
        }

        public void setPercentage(float percent) {
            percentage = percent;
        }

        private String getMessage() {
            return String.format("%.2f%%",percentage * 100);
        }
    }

    private static class Size implements Serializable {
        private static final long serialVersionUID = 3369542887994794927L;
        int mWidth, mHeight;
        public Size(int width, int height) {
            mWidth = width;
            mHeight = height;
        }
    }

    public static int px2dp(Context context, float pxValue) {
        float scale = context.getResources().getDisplayMetrics().density;
        return (int) (pxValue / scale + 0.5f);
    }

    public static int dp2px(Context context, float dpValue) {
        float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }

    public static int px2sp(Context context, float pxValue) {
        float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
        return (int) (pxValue / fontScale + 0.5f);
    }

    public static int sp2px(Context context, float spValue) {
        float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
        return (int) (spValue * fontScale + 0.5f);
    }


    private Paint mBrush = new Paint(Paint.ANTI_ALIAS_FLAG);
    private int mWidth,mHeight;
    private Context mCtx;
    private ArrayList<ChartItem> chartItems = new ArrayList<>();
    private ChartItem mSelectedItem;
    private float mRadius;
    private PieChartItemClickListener mPieChartItemClickListener;
    public float minTitleAngle = 0;

    public float progress = 0;

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

    public PieChartView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs,0);
    }

    public PieChartView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mCtx = context;
        init();
    }

    public void setPieChartItemClickListener(PieChartItemClickListener listener) {
        mPieChartItemClickListener = listener;
    }


    private float total = 0;
    public void setChartItems(ArrayList<ChartItem> items) {
        chartItems = items;

        if (items != null) {
            total = 0;
            for (int i = 0; i < items.size(); i++) {
                ChartItem item = items.get(i);
                total += item.value;
            }

        } else {
            chartItems = new ArrayList<>();
            total = 0;
        }

        invalidate();
    }

    private String mName;
    private int mCount;
    public void setNameAndCount(String name, int count) {
        mName = name;
        mCount = count;
    }

    public void setRadius(float radius) {
        mRadius = dp2px(getContext(),radius);
    }

    private void init() {

        setBackgroundColor(Color.WHITE);
        mBrush.setAntiAlias(true); // 抗锯齿
        mBrush.setDither(true); // 防抖动
        mBrush.setStyle(Paint.Style.FILL);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mWidth = w;
        mHeight = h;

        mRadius = radius();
        titleFontSize = 4.0f * px2dp(getContext(),mRadius) / 18.0f;
        nameFontSize = 5.0f * px2dp(getContext(),mRadius) / 18.0f;
        invalidate();
    }

    @Override
    protected void onDraw(Canvas canvas) {

        if (total == 0) {
            super.onDraw(canvas);
        } else {

            prepareItems();

            showPie(canvas);

            float hollowR = radius() * 0.5f;
            float x = (mWidth - hollowR * 2) * 0.5f;
            float y = (mHeight - hollowR * 2) * 0.5f;

            RectF rect = new RectF(x, y,x + 2 * hollowR, y + 2 * hollowR);

            Paint hollowPaint = new Paint();
            hollowPaint.setAntiAlias(true); // 抗锯齿
            hollowPaint.setDither(true); // 防抖动
            hollowPaint.setStyle(Paint.Style.FILL);
            ColorDrawable colordDrawable = (ColorDrawable) getBackground();
            int color = colordDrawable.getColor();
            hollowPaint.setColor(color);
            canvas.drawArc(rect,0,360,true,hollowPaint);

            drawPieTitle(canvas,mName,String.format("%d",mCount));
        }

    }

    private void showPie(Canvas canvas) {

        for (int i = 0; i < chartItems.size(); i++) {
            ChartItem item = chartItems.get(i);
            drawPieItem(canvas,item);
        }
    }

    private void prepareItems() {


        float perIntervalAngle = 1.0f;

        ArrayList<ChartItem> zeroItems = new ArrayList<>();
        // 剔除value == 0
        for (int i = 0; i < chartItems.size(); i++) {
            ChartItem item = chartItems.get(i);
            if (item.value == 0) {
                zeroItems.add(item);
            }
        }

        if (zeroItems.size() > 0) {
            for (int j = 0; j < zeroItems.size(); j++) {
                ChartItem item = zeroItems.get(j);
                chartItems.remove(item);
            }
        }

        if (chartItems.size() == 1) {
            perIntervalAngle = 0;
        }
        float totalIntervalAngle = perIntervalAngle * chartItems.size();
        float totalAngle = 360.f - totalIntervalAngle;
        float currentAngle = perIntervalAngle;

        for (int i = 0; i < chartItems.size(); i++) {
            ChartItem item = chartItems.get(i);
            if (total > 0) {
                item.percentage = item.value / total;
            } else {
                item.percentage = 0.f;
            }
            item.startAngle = currentAngle;
            item.angle = totalAngle * item.percentage;
            item.endAngle = item.startAngle + item.angle;

            currentAngle += item.angle + perIntervalAngle;


            float midAngle = (item.startAngle + item.endAngle) * 0.5f;

            PointF point = findTitlePosition(midAngle);
            item.titlePosition = point;
            Size titleSize = item.measure();
//            float x = point.x + titleSize.mWidth * 0.5f;
//            float y = point.y - titleSize.mHeight * 0.5f;
//
//            item.titlePosition = new PointF(x,y);

        }

        // Title
//        int lcount = lbArr.size() + ltArr.size();
//        int rcount = rbArr.size() + rtArr.size();
//
//        float lh = mHeight / (lcount * 1.0f);
//        float rh = mHeight / (rcount * 1.0f);
//
//        // 0
//        for (int i = rbArr.size() - 1; i >= 0; i--) {
//            // 最后一个Title在最下
//            ChartItem item = rbArr.get(i);
//            int index = (rbArr.size() - 1) - i;
//
//            float maxY = mHeight - rh * index;
//            float minY = mHeight - rh * (index + 1);
//            Size titleSize = item.measure();
//
////            float y = mHeight - rh * (index + 0.5f);
//            float y = perfectY(maxY,minY,item.lineEndPoint.y,titleSize.mHeight);
//            float x = mWidth * 1.0f - titleSize.mWidth;
//            item.baseX = x + 0.5f * titleSize.mWidth;
//
//            item.titlePoint = new PointF(x,y);
////            Log.d("prepareItems", "RB: " + item.title);
//        }
//        // 1
//        for (int i = 0; i < lbArr.size(); i++) {
//            // 第一个Title在最下
//            ChartItem item = lbArr.get(i);
//            int index = i;
//            float maxY = mHeight - lh * index;
//            float minY = mHeight - lh * (index + 1);
//            Size titleSize = item.measure();
//
////            float y = mHeight - lh * (index + 0.5f);
//            float y = perfectY(maxY,minY,item.lineEndPoint.y,titleSize.mHeight);
//            float x = titleSize.mWidth;
//            item.baseX = x - 0.5f * titleSize.mWidth;
//
//            item.titlePoint = new PointF(x,y);
////            Log.d("prepareItems", "LB: " + item.title);
//        }
//
//        // 2
//        for (int i = ltArr.size() - 1; i >= 0; i--) {
//            //最后一个Title在最上
//            ChartItem item = ltArr.get(i);
//            int index = (ltArr.size() - 1) - i;
//
//            float minY = lh * index;
//            float maxY = lh * (index + 1);
//            Size titleSize = item.measure();
//
////            float y = lh * (index + 0.5f);
//            float x = titleSize.mWidth;
//            float y = perfectY(maxY,minY,item.lineEndPoint.y,titleSize.mHeight);
//            item.baseX = x - 0.5f * titleSize.mWidth;
//
//            item.titlePoint = new PointF(x,y);
////            Log.d("prepareItems", "LT: " + item.title);
//        }
//
//        // 3
//        for (int i = 0; i < rtArr.size(); i++) {
//            // 第一个Title在最上
//            ChartItem item = rtArr.get(i);
//            int index = i;
//
//            float minY = rh * index;
//            float maxY = rh * (index + 1);
//            Size titleSize = item.measure();
//
////            float y = rh * (index + 0.5f);
//            float x = mWidth * 1.0f - titleSize.mWidth;
//            float y = perfectY(maxY,minY,item.lineEndPoint.y,titleSize.mHeight);
//            item.baseX = x + 0.5f * titleSize.mWidth;
//
//            item.titlePoint = new PointF(x,y);
//            Log.d("prepareItems", "RT: " + item.title);
//        }

    }

    public float perfectY(float maxY, float minY,float py, float h) {
        float min_y = py - h * 0.5f, max_y = py + h * 0.5f;
        if (min_y >= minY && max_y <= maxY) {
            return py;
        }

        if ((min_y - minY) < 0) {
            py += minY - min_y;
        } else {
            py -= max_y - maxY;
        }

        return py;
    }

    private void drawPieTitle(Canvas canvas, String title, String count) {

        if (canvas == null || title == null || count == null) {
            return;
        }

        if (title.length() == 0 || count.length() == 0) {
            return;
        }

        float centerX = mWidth * 0.5f;
        float centerY = mHeight * 0.5f;

        float r = mRadius * 0.5f;
        float w = (float) (Math.sqrt(Math.pow(r,2) / 2)) * 2.0f;
        float h = w;

        float x = centerX - w * 0.5f;
        float y = centerY - h * 0.5f;

//        String msg = "Per ETA\r\nContainer\r\n485845";

//        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
//        paint.setStyle(Paint.Style.STROKE);
//        canvas.drawLine(x,y,x + w,y,paint);

        String msg = title + "\r\n" + count;

        canvas.save();

        TextPaint textPaint = new TextPaint();
        textPaint.setColor(Color.BLACK);
        textPaint.setTextSize(nameFontSize);
        textPaint.setAntiAlias(true);

        StaticLayout layout = new StaticLayout(msg, textPaint, (int)w, Layout.Alignment.ALIGN_CENTER, 1.0F, 0.0F, true);

        y = y + (h - layout.getHeight()) * 0.5f;
        canvas.translate(x,y);
        layout.draw(canvas);

        canvas.restore();



//        canvas.drawText(msg,x,y,textPaint);
    }

    private void drawPieItem(Canvas canvas,ChartItem item) {
        if (item == null || canvas == null) {
            return;
        }

        // draw Pie
        if (item.angle > 0) {
            float r = radius();
            if (item.select) {
                r += detal * progress;
            }
            float x = (mWidth - r * 2) * 0.5f;
            float y = (mHeight - r * 2) * 0.5f;

            RectF rect = new RectF(x, y,x + 2 * r, y + 2 * r);

            mBrush.setColor(item.getColor());
            canvas.drawArc(rect,item.startAngle,item.angle,true,mBrush);
        }

        if (minTitleAngle > item.angle) {
            return;
        }

        // draw Title
        Paint textPaint = new Paint();
        textPaint.setColor(item.getTitleColor());
        textPaint.setTextSize(titleFontSize);
        textPaint.setStyle(Paint.Style.FILL);
        //该方法即为设置基线上那个点到底是left,center,还是right  这里我设置为center
        textPaint.setTextAlign(Paint.Align.CENTER);

        String msg = item.getMessage();
        canvas.drawText(msg,item.titlePosition.x,item.titlePosition.y + item.titleSize.mHeight * 0.5f,textPaint);


//        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
//        paint.setStyle(Paint.Style.STROKE);
//        canvas.drawLine(item.titlePosition.x - 40.0f,item.titlePosition.y,item.titlePosition.x + 40.0f, item.titlePosition.y,paint);
//        canvas.drawLine(item.titlePosition.x,item.titlePosition.y - 400.f,item.titlePosition.x, item.titlePosition.y + 40.0f,paint);

    }

    private PointF center() {
        return new PointF(mWidth * 0.5f,mHeight * 0.5f);
    }

    private float radius() {
//        if (mRadius <= 0) {
            return Math.min(mWidth,mHeight) * 0.5f * 0.9f;
//        } else {
//            return mRadius;
//        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {

        if (event.getAction() == MotionEvent.ACTION_DOWN || event.getAction() == MotionEvent.ACTION_MOVE) {

            float touchX = event.getX();
            float touchY = event.getY();

            float distance = (float) Math.sqrt(Math.pow(center().x - touchX,2) + Math.pow(center().y - touchY,2));

            if (distance < radius() * 0.5f) {
                if (event.getAction() == MotionEvent.ACTION_DOWN) {
                    if (mPieChartItemClickListener != null) {
                        mPieChartItemClickListener.pieChartDidBeginTouch();
                    }
                }

                if (mPieChartItemClickListener != null) {
                    mPieChartItemClickListener.pieChartCenterClicked(this);
                }
                return true;
            }

            if (distance > radius()) {
                return super.onTouchEvent(event);
            }

            if (event.getAction() == MotionEvent.ACTION_DOWN) {
                if (mPieChartItemClickListener != null) {
                    mPieChartItemClickListener.pieChartDidBeginTouch();
                }
            }

            double rad_angle = findAngleBytouchPoint(touchX,touchY);
            float angle = (float) (180.0f / M_PI * rad_angle);

            Log.d("Touch", String.format("onTouch Angle: %f",angle));

            Iterator iterator = chartItems.iterator();
            while (iterator.hasNext()) {
                ChartItem item = (ChartItem) iterator.next();
                if (item.startAngle <= angle && item.endAngle >= angle) {
                    if (mSelectedItem != null) {
                        if (mSelectedItem == item) {
                            break;
                        } else {
                            mSelectedItem.select = false;
                        }
                    }
                    mSelectedItem = item;
                    mSelectedItem.select = true;
                    invalidate();
                    if (mPieChartItemClickListener != null) {
                        mPieChartItemClickListener.pieChartItemClicked(this,item);
                    }
                    break;
                }
            }
            return true;
        } else if (event.getAction() == MotionEvent.ACTION_CANCEL || event.getAction() == MotionEvent.ACTION_UP) {

            if (mPieChartItemClickListener != null) {
                mPieChartItemClickListener.pieChartDidEndTouch();
            }

            if (mSelectedItem != null) {
                mSelectedItem.select = false;
                invalidate();
                mSelectedItem = null;
            }
            if (mPieChartItemClickListener != null) {
                mPieChartItemClickListener.pieChartItemClicked(this,null);
            }

        }



        return super.onTouchEvent(event);
    }

    private double findAngleBytouchPoint(float touchX, float touchY) {

        float r = mRadius;
        float x = (mWidth - r * 2) * 0.5f;
        float y = (mHeight - r * 2) * 0.5f;
        RectF rect = new RectF(x, y,x + 2 * r, y + 2 * r);

        if (rect.contains(touchX,touchY)) {

            float centerX = mWidth * 0.5f;
            float centerY = mHeight * 0.5f;

            float distance = (float) Math.sqrt(Math.pow(centerX - touchX,2) + Math.pow(centerY - touchY,2));
            float angle = (float) Math.asin(Math.abs(touchY - centerY) / distance);

            float offsetX = touchX - centerX;
            float offsetY = touchY - centerY;


            if (offsetX > 0 && offsetY > 0) {
                return angle;
            }
            if (offsetX < 0 && offsetY > 0) {
                return M_PI - angle;
            }
            if (offsetX < 0 && offsetY < 0) {
                return M_PI + angle;
            }
            if (offsetX > 0 && offsetY < 0) {
                return M_PI * 2 - angle;
            }
            if (offsetX == 0) {
                if (offsetY > 0) {
                    return M_PI;
                }
                if (offsetY < 0) {
                    return M_PI_2 * 3;
                }
            }
            if (offsetY == 0) {
                if (offsetX > 0) {
                    return 0;
                }
                if (offsetX < 0) {
                    return M_PI;
                }
            }

            return 0;

        }
        return 0;
    }

    private PointF findTitlePosition(float angle) {

        float centerX = mWidth * 0.5f;
        float centerY = mHeight * 0.5f;
        float r = mRadius * 0.75f;
        float rad = (float) (angle * M_PI / 180.0f);

        return new PointF(centerX + (float) Math.cos(rad) * r, centerY + (float) Math.sin(rad) * r);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

//        KPICell p = (KPICell) getParent();
//        int w = p.getKPIWidth();
//
//        int leftInterval = dp2px(getContext(),60);
//        int rightInterval = dp2px(getContext(),60);
//
//        int pieW = (w - leftInterval - rightInterval);

//        widthMeasureSpec = MeasureSpec.makeMeasureSpec(pieW, MeasureSpec.EXACTLY);
//        heightMeasureSpec = MeasureSpec.makeMeasureSpec(pieW, MeasureSpec.EXACTLY);

        int width = MeasureSpec.getSize(widthMeasureSpec);
        heightMeasureSpec = MeasureSpec.makeMeasureSpec(width,MeasureSpec.EXACTLY);

        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }
}
