package org.gcube.portlet.user.userstatisticsportlet.client;

import org.gcube.portlet.user.userstatisticsportlet.client.resources.Images;
import org.gcube.portlet.user.userstatisticsportlet.client.ui.CommentsAndLikesWidget;
import org.gcube.portlet.user.userstatisticsportlet.client.ui.StatisticWidget;
import org.gcube.portlet.user.userstatisticsportlet.shared.PostsStatsBean;
import org.gcube.portlet.user.userstatisticsportlet.shared.UserInformation;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.i18n.client.NumberFormat;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.Label;
/**
 * Panel to show received user's statistics
 * 
 * @author Costantino Perciante at ISTI-CNR
 */
public class StatisticsPanel extends Composite {

	/**
	 * Create a remote service proxy to talk to the server-side statistics service.
	 */
	private final UserStatisticsServiceAsync statisticsService = GWT.create(UserStatisticsService.class);

	/**
	 * Path of the image to be shown during loading
	 */
	public static final String imagePath = GWT.getModuleBaseURL() + "../images/statistics-loader.gif";

	/**
	 * alert icon to be show if some statistic is not available
	 */
	public static final String alertIconPath = GWT.getModuleBaseURL() + "../images/icon-alert.png";

	/**
	 * tooltip for the above image
	 */
	private static final String ALERT_MESSAGE = "Information not available at the moment.";

	/**
	 * Title of the page
	 */
	public static final String DISPLAY_NAME =  "Your Stats ";

	/**
	 * Labels
	 */
	private final static String POSTS_LABEL = "Posts";
	private final static String STORAGE_LABEL = "Total Space Used";
	private final static String LIKES_COMMENTS_LABEL = "You got";
	private final static String PROFILE_STRENGTH_LABEL = "Profile Strength";

	/**
	 * profile url
	 */
	private final static String profileAccount = "https://dev.d4science.org/group/data-e-infrastructure-gateway/profile";

	/**
	 * profile button label
	 */
	private final static String IMPROVE_BUTTON_LABEL = "Improve";

	/**
	 * threshold for improving profile button
	 */
	private final static int profileImproveThreshold = 50;

	/**
	 * Information about the context of the running portlet
	 */
	private boolean isRoot;

	/**
	 * Image to be shown during loading
	 */
	private Image loadingImage;

	/**
	 * FlowPanel to contain the statistics
	 */
	private FlowPanel mainPanel = new FlowPanel();

	public StatisticsPanel() {

		//init this object
		super();
		initWidget(mainPanel);

		// set style of the main panel
		mainPanel.setStyleName("user-stats-frame");

		//init image loader
		loadingImage = new Image(imagePath);
		loadingImage.setStyleName("loading-image-center");

		//show loader, waiting for the answer coming by the server
		showLoader();

		// request user's information
		statisticsService.getUserSettings(new AsyncCallback<UserInformation>() {

			@Override
			public void onFailure(Throwable arg0) {

				showError();

			}

			@Override
			public void onSuccess(UserInformation information) {

				// remove loading image
				mainPanel.remove(loadingImage);

				// check which kind of information we have to show
				isRoot = information.isRoot();

				if(!isRoot){

					// add the border to the panel and the VRE name
					mainPanel.addStyleName("user-stats-frame-border");
					final HTML name = new HTML(DISPLAY_NAME + " in " + information.getActualVre());		
					name.setStyleName("user-stats-title");
					mainPanel.add(name);

				}

				// user image 
				Images image = GWT.create(Images.class);
				Image userImage = new Image(image.avatarLoader());

				// check if the user has an avatar
				if(information.getUrlAvatar() == null)
					userImage.setResource(image.avatarDefaultImage());
				else
					userImage.setUrl(information.getUrlAvatar());

				// set the style for the user image
				userImage.setStyleName("user-image");

				// set url to change avatar
				final String urlAccount = information.getAccountURL();

				if(urlAccount != null){
					userImage.addClickHandler(new ClickHandler() {
						@Override
						public void onClick(ClickEvent ev) {
							Window.Location.assign(urlAccount);
						}
					});
					userImage.setTitle("Edit your avatar");
					userImage.addStyleName("user-image-editable");
				}

				// add image to mainPanel
				mainPanel.add(userImage);

				// feeds
				final StatisticWidget feeds = new StatisticWidget();
				feeds.setHeader(POSTS_LABEL);

				if(isRoot)
					feeds.setToolTip("Your posts during the last year.");
				else
					feeds.setToolTip("Your posts during the last year in this VRE.");


				// add loading image that will be replaced by the incoming values
				Image postsLoader = new Image(imagePath);
				postsLoader.setStyleName("loading-image-center-small");
				feeds.appendToPanel(postsLoader);

				// append widget
				mainPanel.add(feeds);

				// likes & comments
				final StatisticWidget likesAndComments = new StatisticWidget();
				likesAndComments.setHeader(LIKES_COMMENTS_LABEL);

				if(isRoot)
					likesAndComments.setToolTip("Likes and post replies you got during the last year.");
				else
					likesAndComments.setToolTip("Likes and post replies you got during the last year in this VRE.");

				// add loading image that will be replaced by the incoming values
				Image commentsLikesLoader = new Image(imagePath);
				commentsLikesLoader.setStyleName("loading-image-center-small");
				likesAndComments.appendToPanel(commentsLikesLoader);

				// append widget
				mainPanel.add(likesAndComments);

				// the storage and the profile strength(only in root)
				final StatisticWidget storage =  new StatisticWidget();
				final StatisticWidget profileStrength = new StatisticWidget();

				if(isRoot){

					storage.setHeader(STORAGE_LABEL);
					storage.setToolTip("Total amount of space used in the infrastructure.");

					// add loading image that will be replaced by the incoming values
					Image totalSpaceLoader = new Image(imagePath);
					totalSpaceLoader.setStyleName("loading-image-center-small");
					storage.appendToPanel(totalSpaceLoader);

					mainPanel.add(storage);

					profileStrength.setHeader(PROFILE_STRENGTH_LABEL);
					profileStrength.setToolTip("Your profile strength.");

					// add loading image that will be replaced by the incoming values
					Image profileStrengthLoader = new Image(imagePath);
					profileStrengthLoader.setStyleName("loading-image-center-small");
					profileStrength.appendToPanel(profileStrengthLoader);

					// add to the panel 
					mainPanel.add(profileStrength);

					// async requests that must be performed in root context
					statisticsService.getTotalSpaceInUse(new AsyncCallback<String>() {

						@Override
						public void onFailure(Throwable arg0) {

							appendAlertIcon(storage);

						}

						@Override
						public void onSuccess(String spaceInUse) {

							if(spaceInUse == null){
								appendAlertIcon(storage);
								return;
							}

							storage.clearPanelValues();
							Label storageValue = new Label(spaceInUse);
							storageValue.setStyleName("statistic-value");
							storage.appendToPanel(storageValue);

						}
					});

					statisticsService.getProfileStrength(new AsyncCallback<Integer>() {

						@Override
						public void onFailure(Throwable arg0) {

							appendAlertIcon(profileStrength);

						}

						@Override
						public void onSuccess(Integer profileStrengthInt) {

							if(profileStrengthInt < 0){

								appendAlertIcon(profileStrength);
								return;

							}

							// clear panel
							profileStrength.clearPanelValues();
							final Label profileStrengthLabel = new Label(profileStrengthInt + "%");
							profileStrengthLabel.setStyleName("statistic-value");

							profileStrength.appendToPanel(profileStrengthLabel);

							// in case too low information within the user profile
							if(profileStrengthInt < profileImproveThreshold){

								final Button improveProfileButton = new Button(IMPROVE_BUTTON_LABEL);
								improveProfileButton.setTitle("Improve your profile.");

								improveProfileButton.addClickHandler(new ClickHandler() {

									@Override
									public void onClick(ClickEvent arg0) {

										// redirect
										Window.Location.assign(profileAccount);

									}
								});

								profileStrengthLabel.setStyleName("statistic-value-inline");
								improveProfileButton.setStyleName("button-improve-profile");
								profileStrength.appendToPanel(improveProfileButton);
							}

						}

					});

				}

				// retrieve othe information about number of feeds and post replies/likes
				statisticsService.getPostsStats(new AsyncCallback<PostsStatsBean>(){

					public void onFailure(Throwable arg0) {

						appendAlertIcon(feeds);
						appendAlertIcon(likesAndComments);

					}

					public void onSuccess(PostsStatsBean postsBean) {

						// if there are no statistics
						if(postsBean == null){

							appendAlertIcon(feeds);
							appendAlertIcon(likesAndComments);
							return;

						}

						// update feeds number
						feeds.clearPanelValues();
						Label numberOfFeedsLabel = new Label(formattedNumbers(postsBean.getFeedsNumber()));
						if(isRoot)
						numberOfFeedsLabel.setTitle("Your posts during the last year (" + postsBean.getFeedsNumber() + ")."); 
						else
							numberOfFeedsLabel.setTitle("Your posts during the last year in this VRE (" + postsBean.getFeedsNumber() + ").");
						numberOfFeedsLabel.setStyleName("statistic-value");
						feeds.appendToPanel(numberOfFeedsLabel);

						// updates comments and likes
						likesAndComments.clearPanelValues();
						CommentsAndLikesWidget content = new CommentsAndLikesWidget();

						String urlLikesIcon = GWT.getModuleBaseURL() + "../images/star_blue.png";
						if(isRoot)
							content.setLikes(
									urlLikesIcon, 
									formattedNumbers(postsBean.getLikesReceived()), 
									"Likes you got during the last year.",
									"Likes you got during the last year (" + postsBean.getLikesReceived() + ").");
						else
							content.setLikes(
									urlLikesIcon, 
									formattedNumbers(postsBean.getLikesReceived()), 
									"Likes you got during the last year in this VRE",
									"Likes you got during the last year in this VRE (" + postsBean.getLikesReceived() + ").");

						String urlCommentsIcon = GWT.getModuleBaseURL() + "../images/comment_edit.png";
						if(isRoot)
							content.setComments(
									urlCommentsIcon, 
									formattedNumbers(postsBean.getCommentsReceived()), 
									"Post replies you got during the last year.",
									"Post replies you got during the last year (" + postsBean.getCommentsReceived() + ").");
						else
							content.setComments(
									urlCommentsIcon, 
									formattedNumbers(postsBean.getCommentsReceived()), 
									"Post replies you got during the last year in this VRE.",
									"Post replies you got during the last year in this VRE (" + postsBean.getCommentsReceived() + ").");

						likesAndComments.appendToPanel(content);
					}

				});

			}
		});

	}
	/**
	 * Show loading image
	 */
	private void showLoader() {
		mainPanel.clear();
		mainPanel.add(loadingImage);
	}

	/**
	 * Error when is not possible to receive data or the received data is null
	 */
	private void showError() {
		mainPanel.clear();
		HTML messageError = new HTML(
				"Sorry but it is not possible to retrieve your statistics at the moment. Retry later."
				);
		messageError.setStyleName("error-msg");
		mainPanel.add(messageError);
	}

	/**
	 * Add alert icon/message for this statistic
	 * @param w
	 */
	private void appendAlertIcon(StatisticWidget w) {

		w.clearPanelValues();
		Image alert = new Image(alertIconPath);
		alert.setTitle(ALERT_MESSAGE);
		alert.setStyleName("alert-icon-center");
		w.appendToPanel(alert);

	}

	/**
	 * Format a given value and append k, M, G
	 * @param value
	 * @return
	 */
	private String formattedNumbers(long value){

		String formattedString = null;

		double v = value;
		double k = (double)value/1000.0;
		double m = (double)value/1_000_000.0;
		double g = (double)value/1_000_000_000.0;

		NumberFormat dec = NumberFormat.getFormat("###.###");

		if ( g >= 1.0 ) {
			formattedString = dec.format(g).concat("G");
		} else if ( m >= 1.0 ) {
			formattedString = dec.format(m).concat("M");
		} else if ( k >= 1.0 ) {
			formattedString = dec.format(k).concat("K");
		} else {
			formattedString = dec.format(v).concat("");
		}

		return formattedString;
	}
}
