package com.dnieadmin.gui;

import android.content.Context;
import android.view.MotionEvent;
import android.view.View;


/** Copyright (C) 2012 
 * Jason Valestin (valestin@gmail.com ) and Arindam Nath (strider2023@gmail.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import java.util.ArrayList;
import java.util.List;


import android.graphics.*;
import android.graphics.drawable.Drawable;
import android.view.*;
import android.widget.PopupWindow;

/**
 * This is the core class that handles the widget display and user interaction.
 * 
 * @author Jason Valestin (valestin@gmail.com )
 * @author Arindam Nath (strider2023@gmail.com)
 */
public class MyRadialMenuWidget extends View {

	private MyRadialMenuHelper helper;

	private List<MyRadialMenuItem> menuEntries = new ArrayList<MyRadialMenuItem>();
	private MyRadialMenuItem centerCircle = null;

	private float screen_density = getContext().getResources()
			.getDisplayMetrics().density;

	private int defaultColor = Color.rgb(34, 96, 120); // default color of wedge
														// pieces
	private int defaultAlpha = 180; // transparency of the colors, 255=Opague,
									// 0=Transparent
	private int wedge2Color = Color.rgb(250, 250, 250); // default color of wedge
														// pieces
	//private int wedge2Alpha = 180;
	private int wedge2Alpha = 255;
	private int outlineColor = Color.rgb(250, 250, 250); // color of outline
	private int outlineAlpha = 180; // transparency of outline
	private int selectedColor = Color.rgb(70, 130, 180); // color to fill when
															// something is
															// selected
	private int selectedAlpha = 210; // transparency of fill when something is
										// selected

	private int disabledColor = Color.rgb(34, 96, 120); // color to fill when
														// something is selected
	private int disabledAlpha = 100; // transparency of fill when something is
										// selected

	private int pictureAlpha = 255; // transparency of images

	private int textColor = Color.rgb(255, 255, 255); // color to fill when
														// something is selected
	private int textAlpha = 255; // transparency of fill when something is
									// selected

	private int headerTextColor = Color.rgb(255, 255, 255); // color of header
															// text
	private int headerTextAlpha = 255; // transparency of header text
	private int headerBackgroundColor = Color.rgb(0, 0, 0); // color of header
															// background
	private int headerBackgroundAlpha = 180; // transparency of header
												// background

	private int wedgeQty = 1; // Number of wedges
	private MyRadialMenuWedge[] Wedges = new MyRadialMenuWedge[wedgeQty];
	private MyRadialMenuWedge selected = null; // Keeps track of which wedge is
												// selected
	private MyRadialMenuWedge enabled = null; // Keeps track of which wedge is
											// enabled for outer ring
	private Rect[] iconRect = new Rect[wedgeQty];

	private int wedgeQty2 = 1; // Number of wedges
	private MyRadialMenuWedge[] Wedges2 = new MyRadialMenuWedge[wedgeQty2];
	private MyRadialMenuWedge selected2 = null; // Keeps track of which wedge is
												// selected
	private Rect[] iconRect2 = new Rect[wedgeQty2];
	private MyRadialMenuInterface wedge2Data = null; // Keeps track off which menuItem
												// data is being used for the
												// outer ring

	private int MinSize = scalePX(35); // Radius of inner ring size
	private int MaxSize = scalePX(90); // Radius of outer ring size
	private int r2MinSize = MaxSize + scalePX(5); // Radius of inner second ring
													// size
	private int r2MaxSize = r2MinSize + scalePX(45); // Radius of outer second
														// ring size
	private int MinIconSize = scalePX(15); // Min Size of Image in Wedge
	private int MaxIconSize = scalePX(35); // Max Size of Image in Wedge
	// private int BitmapSize = scalePX(40); //Size of Image in Wedge
	private int cRadius = MinSize - scalePX(7); // Inner Circle Radius
	private int textSize = scalePX(15); // TextSize
	private int animateTextSize = textSize;

	private int xPosition = scalePX(120); // Center X location of Radial Menu
	private int yPosition = scalePX(120); // Center Y location of Radial Menu

	private int xSource = 0; // Source X of clicked location
	private int ySource = 0; // Center Y of clicked location
	private boolean showSource = false; // Display icon where at source location

	private boolean inWedge = false; // Identifies touch event was in first
										// wedge
	private boolean inWedge2 = false; // Identifies touch event was in second
										// wedge
	private boolean inCircle = false; // Identifies touch event was in middle
										// circle

	private boolean Wedge2Shown = false; // Identifies 2nd wedge is drawn
	private boolean HeaderBoxBounded = false; // Identifies if header box is
												// drawn

	private String headerString = null;
	private int headerTextSize = textSize; // TextSize
	private int headerBuffer = scalePX(8);
	private Rect textRect = new Rect();
	private RectF textBoxRect = new RectF();
	private int headerTextLeft;
	private int headerTextBottom;

	private static final int ANIMATE_IN = 1;
	private static final int ANIMATE_OUT = 2;

	private int animateSections = 4;
	private int r2VariableSize;
	private boolean animateOuterIn = false;
	private boolean animateOuterOut = false;
	
	private PopupWindow mWindow;

	/**
	 * Radial menu widget constructor.
	 * @param context - Application Context.
	 * <strong> Usage </strong>
	 * 
	 * MyRadialMenuWidget pieMenu = new MyRadialMenuWidget(this);
	 * pieMenu.addMenuEntry(menuItem);
	 * pieMenu.show(view);
	 */
	public MyRadialMenuWidget(Context context) {
		super(context);
		helper = new MyRadialMenuHelper();
		mWindow = helper.initPopup(context);
		// Gets screen specs and defaults to center of screen
		this.xPosition = (getResources().getDisplayMetrics().widthPixels) / 2;
		this.yPosition = (getResources().getDisplayMetrics().heightPixels) / 2;
		
		determineWedges();
		helper.onOpenAnimation(this, xPosition, yPosition, xSource, ySource);
	}

	@Override
	public boolean onTouchEvent(MotionEvent e) {
		int state = e.getAction();
		int eventX = (int) e.getX();
		int eventY = (int) e.getY();
		if (state == MotionEvent.ACTION_DOWN) {
			// selected = null;
			// selected2 = null;
			inWedge = false;
			inWedge2 = false;
			inCircle = false;

			// Checks if a pie slice is selected in first Wedge
			for (int i = 0; i < Wedges.length; i++) {
				MyRadialMenuWedge f = Wedges[i];
				double slice = (2 * Math.PI) / wedgeQty;
				//double start = (2 * Math.PI) * (0.75) - (slice / 2); // this is
				double start = (2 * Math.PI) * (0.75); // this is
																		// done
																		// so
																		// top
																		// slice
																		// is
																		// the
																		// centered
																		// on
																		// top
																		// of
																		// the
																		// circle

				inWedge = helper
						.pntInWedge(eventX, eventY, xPosition, yPosition,
								MinSize, MaxSize, (i * slice) + start, slice);

				if (inWedge == true) {
					selected = f;
					break;
				}
			}

			// Checks if a pie slice is selected in second Wedge
			if (Wedge2Shown == true) {
				for (int i = 0; i < Wedges2.length; i++) {
					MyRadialMenuWedge f = Wedges2[i];
					double slice = (2 * Math.PI) / wedgeQty2;
					//double start = (2 * Math.PI) * (0.75) - (slice / 2); // this
					double start = (2 * Math.PI) * (0.75); 					// this is
																			// is
																			// done
																			// so
																			// top
																			// slice
																			// is
																			// the
																			// centered
																			// on
																			// top
																			// of
																			// the
																			// circle

					inWedge2 = helper.pntInWedge(eventX, eventY, xPosition,
							yPosition, r2MinSize, r2MaxSize, (i * slice)
									+ start, slice);

					if (inWedge2 == true) {
						selected2 = f;
						break;
					}
				}

			}

			// Checks if center is there and is selected
			if(centerCircle != null) {
				inCircle = helper.pntInCircle(eventX, eventY, xPosition, yPosition,
						cRadius);
				
				// If center is selected, deselect any other button
				if(inCircle)
					selected=null;
			}

		} else if (state == MotionEvent.ACTION_UP) {
			// execute commands...
			// put in stuff here to "return" the button that was pressed.
			if (inCircle == true) {
				if (Wedge2Shown == true) {
					enabled = null;
					animateOuterIn = true; // sets Wedge2Shown = false;
				}
				//selected = null;
				centerCircle.menuActiviated();
				inCircle = false;
				return true;

			} else if ((selected != null) &&(inWedge)){
				for (int i = 0; i < Wedges.length; i++) {
					MyRadialMenuWedge f = Wedges[i];
					if (f == selected) {

						// Checks if a inner ring is enabled if so closes the
						// outer ring an
						if (enabled != null) {
							enabled = null;
							animateOuterIn = true; // sets Wedge2Shown = false;
							// If outer ring is not enabled, then executes event
						} else {
							menuEntries.get(i).menuActiviated();

							// Figures out how many outer rings
							if (menuEntries.get(i).getChildren() != null) {
								determineOuterWedges(menuEntries.get(i));
								enabled = f;
								animateOuterOut = true; // sets Wedge2Shown =
														// true;
							} else {
								Wedge2Shown = false;
							}
						}
						//selected = null;
						return true;
					}
				}
			} else if ((selected2 != null) && (inWedge2)) {
				for (int i = 0; i < Wedges2.length; i++) {
					MyRadialMenuWedge f = Wedges2[i];
					if (f == selected2) {
						animateOuterIn = true; // sets Wedge2Shown = false;
						enabled = null;
						selected = null;
						wedge2Data.getChildren().get(i).menuActiviated();
					}
				}
			} else {
				// This is when something outside the circle or any of the rings
				// is selected
				//dismiss();
				return false;
			}
			// selected = null;
			selected2 = null;
			inCircle = false;
		}
		invalidate();
		return true;
	}

	@Override
	protected void onDraw(Canvas c) {

		Paint paint = new Paint();
		paint.setAntiAlias(true);
		paint.setStrokeWidth(3);

		// draws a dot at the source of the press
		if (showSource == true) {
			paint.setColor(outlineColor);
			paint.setAlpha(outlineAlpha);
			paint.setStyle(Paint.Style.STROKE);
			c.drawCircle(xSource, ySource, cRadius / 10, paint);

			paint.setColor(selectedColor);
			paint.setAlpha(selectedAlpha);
			paint.setStyle(Paint.Style.FILL);
			c.drawCircle(xSource, ySource, cRadius / 10, paint);
		}

		for (int i = 0; i < Wedges.length; i++) {
			MyRadialMenuWedge f = Wedges[i];
			paint.setColor(outlineColor);
			paint.setAlpha(outlineAlpha);
			paint.setStyle(Paint.Style.STROKE);
			c.drawPath(f, paint);
			if (f == enabled && Wedge2Shown == true) {
				paint.setColor(wedge2Color);
				paint.setAlpha(wedge2Alpha);
				paint.setStyle(Paint.Style.FILL);
				c.drawPath(f, paint);
			} else if (f != enabled && Wedge2Shown == true) {
				paint.setColor(disabledColor);
				paint.setAlpha(disabledAlpha);
				paint.setStyle(Paint.Style.FILL);
				c.drawPath(f, paint);
			} else if (f == enabled && Wedge2Shown == false) {
				paint.setColor(wedge2Color);
				paint.setAlpha(wedge2Alpha);
				paint.setStyle(Paint.Style.FILL);
				c.drawPath(f, paint);
			} else if (f == selected) {
				paint.setColor(wedge2Color);
				paint.setAlpha(wedge2Alpha);
				paint.setStyle(Paint.Style.FILL);
				c.drawPath(f, paint);
			} else {
				paint.setColor(defaultColor);
				paint.setAlpha(defaultAlpha);
				paint.setStyle(Paint.Style.FILL);
				c.drawPath(f, paint);
			}

			Rect rf = iconRect[i];

			if ((menuEntries.get(i).getIcon() != 0)
					&& (menuEntries.get(i).getLabel() != null)) {

				// This will look for a "new line" and split into multiple lines
				String menuItemName = menuEntries.get(i).getLabel();
				String[] stringArray = menuItemName.split("\n");

				paint.setColor(textColor);
				if (f != enabled && Wedge2Shown == true) {
					paint.setAlpha(disabledAlpha);
				} else {
					paint.setAlpha(textAlpha);
				}
				paint.setStyle(Paint.Style.FILL);
				paint.setTextSize(textSize);

				Rect rect = new Rect();
				float textHeight = 0;
				for (int j = 0; j < stringArray.length; j++) {
					paint.getTextBounds(stringArray[j], 0,
							stringArray[j].length(), rect);
					textHeight = textHeight + (rect.height() + 3);
				}

				Rect rf2 = new Rect();
				rf2.set(rf.left, rf.top - ((int) textHeight / 2), rf.right,
						rf.bottom - ((int) textHeight / 2));

				float textBottom = rf2.bottom;
				for (int j = 0; j < stringArray.length; j++) {
					paint.getTextBounds(stringArray[j], 0,
							stringArray[j].length(), rect);
					float textLeft = rf.centerX() - rect.width() / 2;
					textBottom = textBottom + (rect.height() + 3);
					c.drawText(stringArray[j], textLeft - rect.left, textBottom
							- rect.bottom, paint);
				}

				// Puts in the Icon
				Drawable drawable = null;
				if( f == selected)
					drawable = getResources().getDrawable(
							menuEntries.get(i).getIconSelected());
				else
					drawable = getResources().getDrawable(
							menuEntries.get(i).getIcon());
				
				drawable.setBounds(rf2);
				if (f != enabled && Wedge2Shown == true) {
					drawable.setAlpha(disabledAlpha);
				} else {
					drawable.setAlpha(pictureAlpha);
				}
				drawable.draw(c);

				// Icon Only
			} else if (menuEntries.get(i).getIcon() != 0) {
				// Puts in the Icon
				Drawable drawable = null;
				if( f == selected)
					drawable = getResources().getDrawable(
							menuEntries.get(i).getIconSelected());
				else
					drawable = getResources().getDrawable(
							menuEntries.get(i).getIcon());
				
				drawable.setBounds(rf);
				if (f != enabled && Wedge2Shown == true) {
					drawable.setAlpha(disabledAlpha);
				} else {
					drawable.setAlpha(pictureAlpha);
				}
				drawable.draw(c);

				// Text Only
			} else {
				// Puts in the Text if no Icon
				paint.setColor(textColor);
				if (f != enabled && Wedge2Shown == true) {
					paint.setAlpha(disabledAlpha);
				} else {
					paint.setAlpha(textAlpha);
				}
				paint.setStyle(Paint.Style.FILL);
				paint.setTextSize(textSize);

				// This will look for a "new line" and split into multiple lines
				String menuItemName = menuEntries.get(i).getLabel();
				String[] stringArray = menuItemName.split("\n");

				// gets total height
				Rect rect = new Rect();
				float textHeight = 0;
				for (int j = 0; j < stringArray.length; j++) {
					paint.getTextBounds(stringArray[j], 0,
							stringArray[j].length(), rect);
					textHeight = textHeight + (rect.height() + 3);
				}

				float textBottom = rf.centerY() - (textHeight / 2);
				for (int j = 0; j < stringArray.length; j++) {
					paint.getTextBounds(stringArray[j], 0,
							stringArray[j].length(), rect);
					float textLeft = rf.centerX() - rect.width() / 2;
					textBottom = textBottom + (rect.height() + 3);
					c.drawText(stringArray[j], textLeft - rect.left, textBottom
							- rect.bottom, paint);
				}
			}

		}

		// Animate the outer ring in/out
		if (animateOuterIn == true) {
			animateOuterWedges(ANIMATE_IN);
		} else if (animateOuterOut == true) {
			animateOuterWedges(ANIMATE_OUT);
		}

		if (Wedge2Shown == true) {

			for (int i = 0; i < Wedges2.length; i++) {
				MyRadialMenuWedge f = Wedges2[i];
				paint.setColor(outlineColor);
				paint.setAlpha(outlineAlpha);
				paint.setStyle(Paint.Style.STROKE);
				c.drawPath(f, paint);
				if (f == selected2) {
					paint.setColor(selectedColor);
					paint.setAlpha(selectedAlpha);
					paint.setStyle(Paint.Style.FILL);
					c.drawPath(f, paint);
				} else {
					paint.setColor(wedge2Color);
					paint.setAlpha(wedge2Alpha);
					paint.setStyle(Paint.Style.FILL);
					c.drawPath(f, paint);
				}

				Rect rf = iconRect2[i];
				if ((wedge2Data.getChildren().get(i).getIcon() != 0)
						&& (wedge2Data.getChildren().get(i).getLabel() != null)) {

					// This will look for a "new line" and split into multiple
					// lines
					String menuItemName = wedge2Data.getChildren().get(i)
							.getLabel();
					String[] stringArray = menuItemName.split("\n");

					paint.setColor(textColor);
					paint.setAlpha(textAlpha);
					paint.setStyle(Paint.Style.FILL);
					paint.setTextSize(animateTextSize);

					Rect rect = new Rect();
					float textHeight = 0;
					for (int j = 0; j < stringArray.length; j++) {
						paint.getTextBounds(stringArray[j], 0,
								stringArray[j].length(), rect);
						textHeight = textHeight + (rect.height() + 3);
					}

					Rect rf2 = new Rect();
					rf2.set(rf.left, rf.top - ((int) textHeight / 2), rf.right,
							rf.bottom - ((int) textHeight / 2));

					float textBottom = rf2.bottom;
					for (int j = 0; j < stringArray.length; j++) {
						paint.getTextBounds(stringArray[j], 0,
								stringArray[j].length(), rect);
						float textLeft = rf.centerX() - rect.width() / 2;
						textBottom = textBottom + (rect.height() + 3);
						c.drawText(stringArray[j], textLeft - rect.left,
								textBottom - rect.bottom, paint);
					}

					// Puts in the Icon
					Drawable drawable = getResources().getDrawable(
							wedge2Data.getChildren().get(i).getIcon());
					drawable.setBounds(rf2);
					drawable.setAlpha(pictureAlpha);
					drawable.draw(c);

					// Icon Only
				} else if (wedge2Data.getChildren().get(i).getIcon() != 0) {
					// Puts in the Icon
					Drawable drawable = getResources().getDrawable(
							wedge2Data.getChildren().get(i).getIcon());
					drawable.setBounds(rf);
					drawable.setAlpha(pictureAlpha);
					drawable.draw(c);

					// Text Only
				} else {
					// Puts in the Text if no Icon
					paint.setColor(textColor);
					paint.setAlpha(textAlpha);
					paint.setStyle(Paint.Style.FILL);
					paint.setTextSize(animateTextSize);

					// This will look for a "new line" and split into multiple
					// lines
					String menuItemName = wedge2Data.getChildren().get(i)
							.getLabel();
					String[] stringArray = menuItemName.split("\n");

					// gets total height
					Rect rect = new Rect();
					float textHeight = 0;
					for (int j = 0; j < stringArray.length; j++) {
						paint.getTextBounds(stringArray[j], 0,
								stringArray[j].length(), rect);
						textHeight = textHeight + (rect.height() + 3);
					}

					float textBottom = rf.centerY() - (textHeight / 2);
					for (int j = 0; j < stringArray.length; j++) {
						paint.getTextBounds(stringArray[j], 0,
								stringArray[j].length(), rect);
						float textLeft = rf.centerX() - rect.width() / 2;
						textBottom = textBottom + (rect.height() + 3);
						c.drawText(stringArray[j], textLeft - rect.left,
								textBottom - rect.bottom, paint);
					}
				}
			}
		}

		//Check if the user has given input for centre circle
		if(centerCircle != null) {
			// Draws the Middle Circle
			paint.setColor(outlineColor);
			paint.setAlpha(outlineAlpha);
			paint.setStyle(Paint.Style.STROKE);
			c.drawCircle(xPosition, yPosition, cRadius, paint);
			if (inCircle == true) {
				paint.setColor(selectedColor);
				paint.setAlpha(selectedAlpha);
				paint.setStyle(Paint.Style.FILL);
				c.drawCircle(xPosition, yPosition, cRadius, paint);
				helper.onCloseAnimation(this, xPosition, yPosition, xSource,
						ySource);
			} else {
				paint.setColor(defaultColor);
				paint.setAlpha(defaultAlpha);
				paint.setStyle(Paint.Style.FILL);
				c.drawCircle(xPosition, yPosition, cRadius, paint);
			}
			
			// Draw the circle picture
			if ((centerCircle.getIcon() != 0) && (centerCircle.getLabel() != null)) {
	
				// This will look for a "new line" and split into multiple lines
				String menuItemName = centerCircle.getLabel();
				String[] stringArray = menuItemName.split("\n");
	
				paint.setColor(textColor);
				paint.setAlpha(textAlpha);
				paint.setStyle(Paint.Style.FILL);
				paint.setTextSize(textSize);
	
				Rect rectText = new Rect();
				Rect rectIcon = new Rect();
				Drawable drawable = getResources().getDrawable(
						centerCircle.getIcon());
	
				int h = getIconSize(drawable.getIntrinsicHeight(), MinIconSize,
						MaxIconSize);
				int w = getIconSize(drawable.getIntrinsicWidth(), MinIconSize,
						MaxIconSize);
				rectIcon.set(xPosition - w / 2, yPosition - h / 2, xPosition + w
						/ 2, yPosition + h / 2);
	
				float textHeight = 0;
				for (int j = 0; j < stringArray.length; j++) {
					paint.getTextBounds(stringArray[j], 0, stringArray[j].length(),
							rectText);
					textHeight = textHeight + (rectText.height() + 3);
				}
	
				rectIcon.set(rectIcon.left, rectIcon.top - ((int) textHeight / 2),
						rectIcon.right, rectIcon.bottom - ((int) textHeight / 2));
	
				float textBottom = rectIcon.bottom;
				for (int j = 0; j < stringArray.length; j++) {
					paint.getTextBounds(stringArray[j], 0, stringArray[j].length(),
							rectText);
					float textLeft = xPosition - rectText.width() / 2;
					textBottom = textBottom + (rectText.height() + 3);
					c.drawText(stringArray[j], textLeft - rectText.left, textBottom
							- rectText.bottom, paint);
				}
	
				// Puts in the Icon
				drawable.setBounds(rectIcon);
				drawable.setAlpha(pictureAlpha);
				drawable.draw(c);
	
				// Icon Only
			} else if (centerCircle.getIcon() != 0) {
	
				Rect rect = new Rect();
	
				Drawable drawable = getResources().getDrawable(
						centerCircle.getIcon());
	
				int h = getIconSize(drawable.getIntrinsicHeight(), MinIconSize,
						MaxIconSize);
				int w = getIconSize(drawable.getIntrinsicWidth(), MinIconSize,
						MaxIconSize);
				rect.set(xPosition - w / 2, yPosition - h / 2, xPosition + w / 2,
						yPosition + h / 2);
	
				drawable.setBounds(rect);
				drawable.setAlpha(pictureAlpha);
				drawable.draw(c);
	
				// Text Only
			} else {
				// Puts in the Text if no Icon
				paint.setColor(textColor);
				paint.setAlpha(textAlpha);
				paint.setStyle(Paint.Style.FILL);
				paint.setTextSize(textSize);
	
				// This will look for a "new line" and split into multiple lines
				String menuItemName = centerCircle.getLabel();
				String[] stringArray = menuItemName.split("\n");
	
				// gets total height
				Rect rect = new Rect();
				float textHeight = 0;
				for (int j = 0; j < stringArray.length; j++) {
					paint.getTextBounds(stringArray[j], 0, stringArray[j].length(),
							rect);
					textHeight = textHeight + (rect.height() + 3);
				}
	
				float textBottom = yPosition - (textHeight / 2);
				for (int j = 0; j < stringArray.length; j++) {
					paint.getTextBounds(stringArray[j], 0, stringArray[j].length(),
							rect);
					float textLeft = xPosition - rect.width() / 2;
					textBottom = textBottom + (rect.height() + 3);
					c.drawText(stringArray[j], textLeft - rect.left, textBottom
							- rect.bottom, paint);
				}
	
			}
		}

		// Draws Text in TextBox
		if (headerString != null) {

			paint.setTextSize(headerTextSize);
			paint.getTextBounds(headerString, 0, headerString.length(),
					this.textRect);
			if (HeaderBoxBounded == false) {
				determineHeaderBox();
				HeaderBoxBounded = true;
			}

			paint.setColor(outlineColor);
			paint.setAlpha(outlineAlpha);
			paint.setStyle(Paint.Style.STROKE);
			c.drawRoundRect(this.textBoxRect, scalePX(5), scalePX(5), paint);
			paint.setColor(headerBackgroundColor);
			paint.setAlpha(headerBackgroundAlpha);
			paint.setStyle(Paint.Style.FILL);
			c.drawRoundRect(this.textBoxRect, scalePX(5), scalePX(5), paint);

			paint.setColor(headerTextColor);
			paint.setAlpha(headerTextAlpha);
			paint.setStyle(Paint.Style.FILL);
			paint.setTextSize(headerTextSize);
			c.drawText(headerString, headerTextLeft, headerTextBottom, paint);
		}

	}

	private int scalePX(int dp_size) {
		int px_size = (int) (dp_size * screen_density + 0.5f);
		return px_size;
	}
	
	private int getIconSize(int iconSize, int minSize, int maxSize) {

		if (iconSize > minSize) {
			if (iconSize > maxSize) {
				return maxSize;
			} else { // iconSize < maxSize
				return iconSize;
			}
		} else { // iconSize < minSize
			return minSize;
		}

	}

	private void animateOuterWedges(int animation_direction) {
		boolean animationComplete = false;
		// Wedge 2
		float slice2 = 360 / wedgeQty2;
		//float start_slice2 = 270 - (slice2 / 2);
		float start_slice2 = 270;
		// calculates where to put the images
		double rSlice2 = (2 * Math.PI) / wedgeQty2;
		//double rStart2 = (2 * Math.PI) * (0.75) - (rSlice2 / 2);
		double rStart2 = (2 * Math.PI) * (0.75);

		this.Wedges2 = new MyRadialMenuWedge[wedgeQty2];
		this.iconRect2 = new Rect[wedgeQty2];

		Wedge2Shown = true;

		int wedgeSizeChange = (r2MaxSize - r2MinSize) / animateSections;

		if (animation_direction == ANIMATE_OUT) {
			if (r2MinSize + r2VariableSize + wedgeSizeChange < r2MaxSize) {
				r2VariableSize += wedgeSizeChange;
			} else {
				animateOuterOut = false;
				r2VariableSize = r2MaxSize - r2MinSize;
				animationComplete = true;
			}

			// animates text size change
			this.animateTextSize = (textSize / animateSections)
					* (r2VariableSize / wedgeSizeChange);

			// calculates new wedge sizes
			for (int i = 0; i < Wedges2.length; i++) {
				this.Wedges2[i] = new MyRadialMenuWedge(xPosition, yPosition,
						r2MinSize, r2MinSize + r2VariableSize, (i * slice2)
								+ start_slice2, slice2);
				float xCenter = (float) (Math
						.cos(((rSlice2 * i) + (rSlice2 * 0.5)) + rStart2)
						* (r2MinSize + r2VariableSize + r2MinSize) / 2)
						+ xPosition;
				float yCenter = (float) (Math
						.sin(((rSlice2 * i) + (rSlice2 * 0.5)) + rStart2)
						* (r2MinSize + r2VariableSize + r2MinSize) / 2)
						+ yPosition;

				int h = MaxIconSize;
				int w = MaxIconSize;
				if (wedge2Data.getChildren().get(i).getIcon() != 0) {
					Drawable drawable = getResources().getDrawable(
							wedge2Data.getChildren().get(i).getIcon());
					h = getIconSize(drawable.getIntrinsicHeight(), MinIconSize,
							MaxIconSize);
					w = getIconSize(drawable.getIntrinsicWidth(), MinIconSize,
							MaxIconSize);
				}

				if (r2VariableSize < h) {
					h = r2VariableSize;
				}
				if (r2VariableSize < w) {
					w = r2VariableSize;
				}

				this.iconRect2[i] = new Rect((int) xCenter - w / 2,
						(int) yCenter - h / 2, (int) xCenter + w / 2,
						(int) yCenter + h / 2);

				int widthOffset = MaxSize;
				if (widthOffset < this.textRect.width() / 2) {
					widthOffset = this.textRect.width() / 2 + scalePX(3);
				}
				this.textBoxRect
						.set((xPosition - (widthOffset)), (int) (yPosition
								- (r2MinSize + r2VariableSize) - headerBuffer
								- this.textRect.height() - scalePX(3)),
								(xPosition + (widthOffset)), (yPosition
										- (r2MinSize + r2VariableSize)
										- headerBuffer + scalePX(3)));
				this.headerTextBottom = yPosition
						- (r2MinSize + r2VariableSize) - headerBuffer
						- this.textRect.bottom;

			}

		} else if (animation_direction == ANIMATE_IN) {
			if (r2MinSize < r2MaxSize - r2VariableSize - wedgeSizeChange) {
				r2VariableSize += wedgeSizeChange;
			} else {
				animateOuterIn = false;
				r2VariableSize = r2MaxSize;
				animationComplete = true;
			}

			// animates text size change
			this.animateTextSize = textSize
					- ((textSize / animateSections) * (r2VariableSize / wedgeSizeChange));

			for (int i = 0; i < Wedges2.length; i++) {
				this.Wedges2[i] = new MyRadialMenuWedge(xPosition, yPosition,
						r2MinSize, r2MaxSize - r2VariableSize, (i * slice2)
								+ start_slice2, slice2);

				float xCenter = (float) (Math
						.cos(((rSlice2 * i) + (rSlice2 * 0.5)) + rStart2)
						* (r2MaxSize - r2VariableSize + r2MinSize) / 2)
						+ xPosition;
				float yCenter = (float) (Math
						.sin(((rSlice2 * i) + (rSlice2 * 0.5)) + rStart2)
						* (r2MaxSize - r2VariableSize + r2MinSize) / 2)
						+ yPosition;

				int h = MaxIconSize;
				int w = MaxIconSize;
				if (wedge2Data.getChildren().get(i).getIcon() != 0) {
					Drawable drawable = getResources().getDrawable(
							wedge2Data.getChildren().get(i).getIcon());
					h = getIconSize(drawable.getIntrinsicHeight(), MinIconSize,
							MaxIconSize);
					w = getIconSize(drawable.getIntrinsicWidth(), MinIconSize,
							MaxIconSize);
				}

				if (r2MaxSize - r2MinSize - r2VariableSize < h) {
					h = r2MaxSize - r2MinSize - r2VariableSize;
				}
				if (r2MaxSize - r2MinSize - r2VariableSize < w) {
					w = r2MaxSize - r2MinSize - r2VariableSize;
				}

				this.iconRect2[i] = new Rect((int) xCenter - w / 2,
						(int) yCenter - h / 2, (int) xCenter + w / 2,
						(int) yCenter + h / 2);

				// computes header text box
				int heightOffset = r2MaxSize - r2VariableSize;
				int widthOffset = MaxSize;
				if (MaxSize > r2MaxSize - r2VariableSize) {
					heightOffset = MaxSize;
				}
				if (widthOffset < this.textRect.width() / 2) {
					widthOffset = this.textRect.width() / 2 + scalePX(3);
				}
				this.textBoxRect.set((xPosition - (widthOffset)),
						(int) (yPosition - (heightOffset) - headerBuffer
								- this.textRect.height() - scalePX(3)),
						(xPosition + (widthOffset)), (yPosition
								- (heightOffset) - headerBuffer + scalePX(3)));
				this.headerTextBottom = yPosition - (heightOffset)
						- headerBuffer - this.textRect.bottom;

			}
		}

		if (animationComplete == true) {
			r2VariableSize = 0;
			this.animateTextSize = textSize;
			if (animation_direction == ANIMATE_IN) {
				Wedge2Shown = false;
			}
		}

		invalidate(); // re-draws the picture
	}

	private void determineWedges() {

		int entriesQty = menuEntries.size();
		if (entriesQty > 0) {
			wedgeQty = entriesQty;

			float degSlice = 360 / wedgeQty;
			//float start_degSlice = 270 - (degSlice / 2);
			float start_degSlice = 270;
			// calculates where to put the images
			double rSlice = (2 * Math.PI) / wedgeQty;
			//double rStart = (2 * Math.PI) * (0.75) - (rSlice / 2);
			double rStart = (2 * Math.PI) * (0.75);

			this.Wedges = new MyRadialMenuWedge[wedgeQty];
			this.iconRect = new Rect[wedgeQty];

			for (int i = 0; i < Wedges.length; i++) {
				this.Wedges[i] = new MyRadialMenuWedge(xPosition, yPosition,
						MinSize, MaxSize, (i * degSlice) + start_degSlice,
						degSlice);
				float xCenter = (float) (Math
						.cos(((rSlice * i) + (rSlice * 0.5)) + rStart)
						* (MaxSize + MinSize) / 2) + xPosition;
				float yCenter = (float) (Math
						.sin(((rSlice * i) + (rSlice * 0.5)) + rStart)
						* (MaxSize + MinSize) / 2) + yPosition;

				int h = MaxIconSize;
				int w = MaxIconSize;
				if (menuEntries.get(i).getIcon() != 0) {
					Drawable drawable = getResources().getDrawable(
							menuEntries.get(i).getIcon());
					h = getIconSize(drawable.getIntrinsicHeight(), MinIconSize,
							MaxIconSize);
					w = getIconSize(drawable.getIntrinsicWidth(), MinIconSize,
							MaxIconSize);
				}

				this.iconRect[i] = new Rect((int) xCenter - w / 2,
						(int) yCenter - h / 2, (int) xCenter + w / 2,
						(int) yCenter + h / 2);
			}

			invalidate(); // re-draws the picture
		}
	}

	private void determineOuterWedges(MyRadialMenuItem entry) {

		int entriesQty = entry.getChildren().size();
		wedgeQty2 = entriesQty;

		// Wedge 2
		float degSlice2 = 360 / wedgeQty2;
		//float start_degSlice2 = 270 - (degSlice2 / 2);
		float start_degSlice2 = 270;
		// calculates where to put the images
		double rSlice2 = (2 * Math.PI) / wedgeQty2;
		//double rStart2 = (2 * Math.PI) * (0.75) - (rSlice2 / 2);
		double rStart2 = (2 * Math.PI) * (0.75);

		this.Wedges2 = new MyRadialMenuWedge[wedgeQty2];
		this.iconRect2 = new Rect[wedgeQty2];

		for (int i = 0; i < Wedges2.length; i++) {
			this.Wedges2[i] = new MyRadialMenuWedge(xPosition, yPosition,
					r2MinSize, r2MaxSize, (i * degSlice2) + start_degSlice2,
					degSlice2);
			float xCenter = (float) (Math.cos(((rSlice2 * i) + (rSlice2 * 0.5))
					+ rStart2)
					* (r2MaxSize + r2MinSize) / 2)
					+ xPosition;
			float yCenter = (float) (Math.sin(((rSlice2 * i) + (rSlice2 * 0.5))
					+ rStart2)
					* (r2MaxSize + r2MinSize) / 2)
					+ yPosition;

			int h = MaxIconSize;
			int w = MaxIconSize;
			if (entry.getChildren().get(i).getIcon() != 0) {
				Drawable drawable = getResources().getDrawable(
						entry.getChildren().get(i).getIcon());
				h = getIconSize(drawable.getIntrinsicHeight(), MinIconSize,
						MaxIconSize);
				w = getIconSize(drawable.getIntrinsicWidth(), MinIconSize,
						MaxIconSize);
			}
			this.iconRect2[i] = new Rect((int) xCenter - w / 2, (int) yCenter
					- h / 2, (int) xCenter + w / 2, (int) yCenter + h / 2);
		}
		this.wedge2Data = entry;
		invalidate(); // re-draws the picture
	}

	private void determineHeaderBox() {
		this.headerTextLeft = xPosition - this.textRect.width() / 2;
		this.headerTextBottom = yPosition - (MaxSize) - headerBuffer
				- this.textRect.bottom;
		int offset = MaxSize;
		if (offset < this.textRect.width() / 2) {
			offset = this.textRect.width() / 2 + scalePX(3);
		}
		this.textBoxRect.set(
				(xPosition - (offset)),
				(int) (yPosition - (MaxSize) - headerBuffer
						- this.textRect.height() - scalePX(3)),
				(xPosition + (offset)),
				(yPosition - (MaxSize) - headerBuffer + scalePX(3)));

	}

	/******************************************************************************************************************************
	 * ADD ITEM METHODS
	 ******************************************************************************************************************************/
	
	/**
	 * This method allows the user to add an array of menu items.
	 * @param menuItems - List object of MyRadialMenuItem.
	 * @return
	 */
	public void addMenuEntry(List<MyRadialMenuItem> menuItems) {
		menuEntries.addAll(menuItems);
		determineWedges();
	}
	
	/**
	 *  This method allows the user to add a menu item.
	 * @param menuItem - Object of MyRadialMenuItem.
	 * @return
	 */
	public void addMenuEntry(MyRadialMenuItem menuItem) {
		menuEntries.add(menuItem);
		determineWedges();
	}
	
	/******************************************************************************************************************************
	 * SET METHODS
	 ******************************************************************************************************************************/
	
	/**
	 * <strong> Optional </strong>
	 * This method allows the user to add the central menu item.
	 * @param menuItem - Object of MyRadialMenuItem.
	 * @return
	 */
	public void setCenterCircle(MyRadialMenuItem menuItem) {
		centerCircle = menuItem;
	}

	/**
	 * <strong> Optional </strong>
	 * Set the middle ring radius of the radial menu widget.
	 * @param InnerRadius - Inner border radius.
	 * @param OuterRadius - Outer border radius.
	 */
	public void setInnerRingRadius(int InnerRadius, int OuterRadius) {
		this.MinSize = scalePX(InnerRadius);
		this.MaxSize = scalePX(OuterRadius);
		determineWedges();
	}

	/**
	 * <strong> Optional </strong>
	 * Set the outer ring radius of the radial menu widget.
	 * @param InnerRadius - Inner border radius.
	 * @param OuterRadius - Outer border radius.
	 */
	public void setOuterRingRadius(int InnerRadius, int OuterRadius) {
		this.r2MinSize = scalePX(InnerRadius);
		this.r2MaxSize = scalePX(OuterRadius);
		determineWedges();
	}

	/**
	 * <strong> Optional </strong>
	 * This method set the radius of the centre circle.
	 * @param centerRadius - Radius of the circle.
	 */
	public void setCenterCircleRadius(int centerRadius) {
		this.cRadius = scalePX(centerRadius);
		determineWedges();
	}

	/**
	 * Set the menu items text size.
	 * @param TextSize - Text size of the menu items.
	 */
	public void setTextSize(int TextSize) {
		this.textSize = scalePX(TextSize);
		this.animateTextSize = this.textSize;
	}

	/**
	 * Set the menu item icon size.
	 * @param minIconSize - Minimum scaled size.
	 * @param maxIconSize - Maximum scaled size.
	 */
	public void setIconSize(int minIconSize, int maxIconSize) {
		this.MinIconSize = scalePX(minIconSize);
		this.MaxIconSize = scalePX(maxIconSize);
		determineWedges();
	}

	/**
	 * 
	 * @param x
	 * @param y
	 */
	public void setCenterLocation(int x, int y) {
		this.xPosition = x;
		this.yPosition = y;
		determineWedges();
		helper.onOpenAnimation(this, xPosition, yPosition, xSource, ySource);
	}

	/**
	 * 
	 * @param x
	 * @param y
	 */
	public void setSourceLocation(int x, int y) {
		this.xSource = x;
		this.ySource = y;
		helper.onOpenAnimation(this, xPosition, yPosition, xSource, ySource);
	}
	
	/**
	 * @deprecated
	 * @param showSourceLocation
	 */
	public void setShowSourceLocation(boolean showSourceLocation) {
		this.showSource = showSourceLocation;
		helper.onOpenAnimation(this, xPosition, yPosition, xSource, ySource);
	}

	/**
	 * Set the widget animation speed.
	 * @param millis - Time in milliseconds.
	 */
	public void setAnimationSpeed(long millis) {
		helper.onOpenAnimation(this, xPosition, yPosition, xSource, ySource,
				millis);
	}

	/**
	 * Set the radial menu inner ring color.
	 * @param color - Color value .
	 * @param alpha - Alpha blend value.
	 */
	public void setInnerRingColor(int color, int alpha) {
		this.defaultColor = color;
		this.defaultAlpha = alpha;
	}
	
	/**
	 * Set the radial menu outer ring color.
	 * @param color - Color value .
	 * @param alpha - Alpha blend value.
	 */
	public void setOuterRingColor(int color, int alpha) {
		this.wedge2Color = color;
		this.wedge2Alpha = alpha;
	}

	/**
	 * Set the radial widget outline color.
	 * @param color - Color value .
	 * @param alpha - Alpha blend value.
	 */
	public void setOutlineColor(int color, int alpha) {
		this.outlineColor = color;
		this.outlineAlpha = alpha;
	}

	/**
	 * Set the widget on select color.
	 * @param color - Color value .
	 * @param alpha - Alpha blend value.
	 */
	public void setSelectedColor(int color, int alpha) {
		this.selectedColor = color;
		this.selectedAlpha = alpha;
	}

	/**
	 * Set the widget on disabled color.
	 * @param color - Color value .
	 * @param alpha - Alpha blend value.
	 */
	public void setDisabledColor(int color, int alpha) {
		this.disabledColor = color;
		this.disabledAlpha = alpha;
	}

	/**
	 * Set the widget text color.
	 * @param color - Text color
	 * @param alpha - Text alpha belnd value
	 */
	public void setTextColor(int color, int alpha) {
		this.textColor = color;
		this.textAlpha = alpha;
	}

	/**
	 * <strong> Optional </strong>
	 * Display a header with text along with the displayed radial menu.
	 * @param header - Header text to be displayed.
	 * @param TextSize -  Text size.
	 */
	public void setHeader(String header, int TextSize) {
		this.headerString = header;
		this.headerTextSize = scalePX(TextSize);
		HeaderBoxBounded = false;
	}

	/**
	 * <strong> Optional </strong>
	 * Display a header with text along with the displayed radial menu. This method helps in configuring the display background.
	 * @param TextColor
	 * @param TextAlpha
	 * @param BgColor
	 * @param BgAlpha
	 */
	public void setHeaderColors(int TextColor, int TextAlpha, int BgColor,
			int BgAlpha) {
		this.headerTextColor = TextColor;
		this.headerTextAlpha = TextAlpha;
		this.headerBackgroundColor = BgColor;
		this.headerBackgroundAlpha = BgAlpha;
	}
	
	/**
	 * Shows the radial menu widget.
	 * @param anchor - View to be anchored to.
	 * @param posX - Position X. Pass 0 if not needed.
	 * @param posY - Position Y. Pass 0 if not needed.
	 */
	public void show(View anchor, int posX, int posY) {
		mWindow.setContentView(this);
		mWindow.showAtLocation(anchor, Gravity.NO_GRAVITY, posX, posY);
	}
	
	/**
	 * Shows the radial menu widget.
	 * @param anchor - View to be anchored to.
	 */
	public void show(View anchor) {
		mWindow.setContentView(this);
		mWindow.showAtLocation(anchor, Gravity.NO_GRAVITY, this.xSource, this.ySource);
	}
	
	/**
	 * Dismisses the radial menu widget.
	 */
	public void dismiss() {
		if(mWindow != null)
			mWindow.dismiss();
	}
}
