/*
 * Copyright (c) 2015. Ncomz. All Rights Reserved
 */

package com.ntels.onecable.common.widget;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.SweepGradient;
import android.os.Build;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;

import com.ntels.onecable.R;

public class CircleProgressBar extends View {

  private static final String TAG = CircleProgressBar.class.getSimpleName();

  private static final String INSTANCE_STATE_SAVEDSTATE = "saved_state";

  private static final String INSTANCE_STATE_PROGRESS = "progress1";

  private static final String INSTANCE_STATE_MARKER_PROGRESS = "marker_progress";

  private static final String INSTANCE_STATE_PROGRESS_BACKGROUND_COLOR = "progress_background_color";

  private static final String INSTANCE_STATE_PROGRESS_COLOR = "progress_color";

  private final RectF mCircleBounds = new RectF();
  private final RectF mJogRect = new RectF();

  private Paint mBackgroundColorPaint = new Paint();
  private Paint mJogPaint = new Paint();

  private int mCircleStrokeWidth = 11;

  private int mGravity = Gravity.CENTER;

  private int mHorizontalInset = 0;

  private boolean mIsInitializing = true;

  private float mMarkerProgress = 0.0f;

  private boolean mOverrdraw = false;

  private float mProgress = 0.0f;

  private int mProgressBackgroundColor;

  private int mProgressColor;

  private Paint mProgressColorPaint;

  private float mRadius;

  private float mTranslationOffsetX;

  private float mTranslationOffsetY;

  private int mVerticalInset = 0;

  private Context mContext;

  public CircleProgressBar(final Context context) {

    this(context, null);
    mContext = context;
  }

  public CircleProgressBar(final Context context, final AttributeSet attrs) {

    this(context, attrs, R.attr.circleProgressBarStyle);
    mContext = context;
  }

  public CircleProgressBar(final Context context, final AttributeSet attrs, final int defStyle) {

    super(context, attrs, defStyle);

    mContext = context;
    final TypedArray attributes = context.obtainStyledAttributes(attrs, R.styleable.CircleProgressBar, defStyle, 0);
    if (attributes != null) {
      try {
        setProgress(attributes.getFloat(R.styleable.CircleProgressBar_progress1, 0.0f));
        setWheelSize((int) attributes.getDimension(R.styleable.CircleProgressBar_stroke_width, mCircleStrokeWidth));

        //                mGravity = attributes.getInt(R.styleable.HoloCircularProgressBar_android_gravity, Gravity.CENTER);
      } finally {
        attributes.recycle();
      }
    }

    updateJogColor();

    updateBackgroundColor();

    updateProgressColor();

    mIsInitializing = false;
  }

  @Override
  protected void onDraw(final Canvas canvas) {

    canvas.translate(mTranslationOffsetX, mTranslationOffsetY);
    canvas.rotate(-90);
    final float progressRotation = getCurrentRotation();

    canvas.drawArc(mJogRect, 0, 360, false, mJogPaint);

    canvas.drawArc(mCircleBounds, 0, 359, false, mBackgroundColorPaint);

    canvas.drawArc(mCircleBounds, 0, progressRotation >= 360 ? 359 : progressRotation, false, mProgressColorPaint);
  }

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

    final int height = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);
    final int width = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);

    final int diameter;
    if (heightMeasureSpec == MeasureSpec.UNSPECIFIED) {
      diameter = width;
      computeInsets(0, 0);
    } else if (widthMeasureSpec == MeasureSpec.UNSPECIFIED) {
      diameter = height;
      computeInsets(0, 0);
    } else {
      diameter = Math.min(width, height);
      computeInsets(width - diameter, height - diameter);
    }

    setMeasuredDimension(diameter, diameter);

    final float halfWidth = diameter * 0.5f;

    final float drawedWith;
    drawedWith = mCircleStrokeWidth / 2f;

    mRadius = halfWidth - drawedWith - 0.5f;

    mCircleBounds.set(-mRadius, -mRadius, mRadius, mRadius);
    int iPadding = (int) (mCircleStrokeWidth * 1.3);
    mJogRect.set(-mRadius + iPadding, -mRadius + iPadding, mRadius - iPadding, mRadius - iPadding);

    mTranslationOffsetX = halfWidth + mHorizontalInset;
    mTranslationOffsetY = halfWidth + mVerticalInset;
  }

  @Override
  protected void onRestoreInstanceState(final Parcelable state) {

    if (state instanceof Bundle) {
      final Bundle bundle = (Bundle) state;
      setProgress(bundle.getFloat(INSTANCE_STATE_PROGRESS));
      setMarkerProgress(bundle.getFloat(INSTANCE_STATE_MARKER_PROGRESS));

      final int progressColor = bundle.getInt(INSTANCE_STATE_PROGRESS_COLOR);
      if (progressColor != mProgressColor) {
        mProgressColor = progressColor;
        updateProgressColor();
      }

      final int progressBackgroundColor = bundle.getInt(INSTANCE_STATE_PROGRESS_BACKGROUND_COLOR);
      if (progressBackgroundColor != mProgressBackgroundColor) {
        mProgressBackgroundColor = progressBackgroundColor;
        updateBackgroundColor();
      }

      super.onRestoreInstanceState(bundle.getParcelable(INSTANCE_STATE_SAVEDSTATE));
      return;
    }

    super.onRestoreInstanceState(state);
  }

  @Override
  protected Parcelable onSaveInstanceState() {

    final Bundle bundle = new Bundle();
    bundle.putParcelable(INSTANCE_STATE_SAVEDSTATE, super.onSaveInstanceState());
    bundle.putFloat(INSTANCE_STATE_PROGRESS, mProgress);
    bundle.putFloat(INSTANCE_STATE_MARKER_PROGRESS, mMarkerProgress);
    bundle.putInt(INSTANCE_STATE_PROGRESS_COLOR, mProgressColor);
    bundle.putInt(INSTANCE_STATE_PROGRESS_BACKGROUND_COLOR, mProgressBackgroundColor);
    return bundle;
  }

  public int getCircleStrokeWidth() {

    return mCircleStrokeWidth;
  }

  public float getProgress() {

    return mProgress;
  }

  public void setMarkerProgress(final float progress) {

    mMarkerProgress = progress;
  }

  public void setProgress(final float progress) {

    if (progress == mProgress) {
      return;
    }

    if (progress == 1) {
      mOverrdraw = false;
      mProgress = 1;
    } else {

      if (progress >= 1) {
        mOverrdraw = true;
      } else {
        mOverrdraw = false;
      }

      mProgress = progress % 1.0f;
    }

    if (!mIsInitializing) {
      invalidate();
    }
  }

  public void setProgressBackgroundColor(final int color) {

    mProgressBackgroundColor = color;
    updateBackgroundColor();
  }

  public void setProgressColor(final int color) {

    mProgressColor = color;
    updateProgressColor();
  }

  public void setWheelSize(final int dimension) {

    mCircleStrokeWidth = dimension;
    updateBackgroundColor();
    updateProgressColor();
  }

  @SuppressLint("NewApi")
  private void computeInsets(final int dx, final int dy) {

    int absoluteGravity = mGravity;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
      absoluteGravity = Gravity.getAbsoluteGravity(mGravity, getLayoutDirection());
    }

    switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
      case Gravity.LEFT:
        mHorizontalInset = 0;
        break;
      case Gravity.RIGHT:
        mHorizontalInset = dx;
        break;
      case Gravity.CENTER_HORIZONTAL:
      default:
        mHorizontalInset = dx / 2;
        break;
    }
    switch (absoluteGravity & Gravity.VERTICAL_GRAVITY_MASK) {
      case Gravity.TOP:
        mVerticalInset = 0;
        break;
      case Gravity.BOTTOM:
        mVerticalInset = dy;
        break;
      case Gravity.CENTER_VERTICAL:
      default:
        mVerticalInset = dy / 2;
        break;
    }
  }

  private float getCurrentRotation() {

    return 360 * mProgress;
  }

  private void updateJogColor() {

    mJogPaint = new Paint();
    mJogPaint.setColor(Color.BLACK);
    mJogPaint.setAlpha(140);
    mJogPaint.setAntiAlias(true);
    mJogPaint.setStyle(Paint.Style.FILL);

    invalidate();
  }

  private void updateBackgroundColor() {

    mBackgroundColorPaint = new Paint();
    mBackgroundColorPaint.setColor(Color.WHITE);
    mBackgroundColorPaint.setAlpha(39);
    mBackgroundColorPaint.setAntiAlias(true);
    mBackgroundColorPaint.setStyle(Paint.Style.STROKE);
    mBackgroundColorPaint.setStrokeWidth(mCircleStrokeWidth);

    DashPathEffect dashPath = new DashPathEffect(new float[]{(float) (mCircleStrokeWidth / 6), (float) (mCircleStrokeWidth / 2.6)}, 1);

    mBackgroundColorPaint.setPathEffect(dashPath);
    invalidate();
  }

  private void updateProgressColor() {

    mProgressColorPaint = new Paint();
    mProgressColorPaint.setAntiAlias(true);
    mProgressColorPaint.setStyle(Paint.Style.STROKE);
    mProgressColorPaint.setStrokeWidth(mCircleStrokeWidth);
    int iColor1 = Color.parseColor("#ffffff");
    int iColor2 = Color.parseColor("#3fff9e");
    int iColor3 = Color.parseColor("#ff7200");
    int iColor4 = Color.parseColor("#ed0000");
    int[] COLORS = new int[]{iColor1, iColor2, iColor3, iColor4};
    Shader s = new SweepGradient(0, 0, COLORS, null);
    mProgressColorPaint.setShader(s);
    DashPathEffect dashPath = new DashPathEffect(new float[]{(float) (mCircleStrokeWidth / 6), (float) (mCircleStrokeWidth / 2.6)}, 1);

    mProgressColorPaint.setPathEffect(dashPath);
    invalidate();
  }
}
