/*
 * Copyright 2011 gitblit.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.
 */
package com.gitblit.wicket.pages;

import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.wicket.PageParameters;
import org.apache.wicket.behavior.HeaderContributor;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.panel.Fragment;

import com.gitblit.Keys;
import com.gitblit.models.Activity;
import com.gitblit.models.Menu.ParameterMenuItem;
import com.gitblit.models.NavLink.DropDownPageMenuNavLink;
import com.gitblit.models.Metric;
import com.gitblit.models.NavLink;
import com.gitblit.models.RepositoryModel;
import com.gitblit.utils.ActivityUtils;
import com.gitblit.utils.StringUtils;
import com.gitblit.wicket.CacheControl;
import com.gitblit.wicket.CacheControl.LastModified;
import com.gitblit.wicket.WicketUtils;
import com.gitblit.wicket.charting.Chart;
import com.gitblit.wicket.charting.Charts;
import com.gitblit.wicket.charting.Flotr2Charts;
import com.gitblit.wicket.panels.ActivityPanel;

/**
 * Activity Page shows a list of recent commits across all visible Gitblit
 * repositories.
 *
 * @author James Moger
 *
 */

@CacheControl(LastModified.ACTIVITY)
public class ActivityPage extends RootPage {

	public ActivityPage(PageParameters params) {
		super(params);
		setupPage("", "");

		// parameters
		int daysBack = WicketUtils.getDaysBack(params);
		if (daysBack < 1) {
			daysBack = app().settings().getInteger(Keys.web.activityDuration, 7);
		}
		String objectId = WicketUtils.getObject(params);

		// determine repositories to view and retrieve the activity
		List<RepositoryModel> models = getRepositories(params);
		List<Activity> recentActivity = ActivityUtils.getRecentActivity(
				app().settings(),
				app().repositories(),
				models,
				daysBack,
				objectId,
				getTimeZone());

		String headerPattern;
		if (daysBack == 1) {
			// today
			if (recentActivity.size() == 0) {
				headerPattern = getString("gb.todaysActivityNone");
			} else {
				headerPattern = getString("gb.todaysActivityStats");
			}
		} else {
			// multiple days
			if (recentActivity.size() == 0) {
				headerPattern = getString("gb.recentActivityNone");
			} else {
				headerPattern = getString("gb.recentActivityStats");
			}
		}

		if (recentActivity.size() == 0) {
			// no activity, skip graphs and activity panel
			add(new Label("subheader", MessageFormat.format(headerPattern,
					daysBack)));
			add(new Label("chartsPanel").setVisible(false));
			add(new Label("activityPanel"));
		} else {
			// calculate total commits and total authors
			int totalCommits = 0;
			Set<String> uniqueAuthors = new HashSet<String>();
			for (Activity activity : recentActivity) {
				totalCommits += activity.getCommitCount();
				uniqueAuthors.addAll(activity.getAuthorMetrics().keySet());
			}
			int totalAuthors = uniqueAuthors.size();

			// add the subheader with stat numbers
			add(new Label("subheader", MessageFormat.format(headerPattern,
					daysBack, totalCommits, totalAuthors)));

			// create the activity charts
			if (app().settings().getBoolean(Keys.web.generateActivityGraph, true)) {
				Charts charts = createCharts(recentActivity);
				add(new HeaderContributor(charts));
				add(new Fragment("chartsPanel", "chartsFragment", this));
			} else {
				add(new Label("chartsPanel").setVisible(false));
			}

			// add activity panel
			add(new ActivityPanel("activityPanel", recentActivity));
		}
	}

	@Override
	protected boolean reusePageParameters() {
		return true;
	}

	@Override
	protected void addDropDownMenus(List<NavLink> navLinks) {
		DropDownPageMenuNavLink filters = new DropDownPageMenuNavLink("gb.filters",
				ActivityPage.class);

		PageParameters currentParameters = getPageParameters();
		int daysBack = app().settings().getInteger(Keys.web.activityDuration, 7);
		if (currentParameters != null && !currentParameters.containsKey("db")) {
			currentParameters.put("db", daysBack);
		}

		// preserve time filter options on repository choices
		filters.menuItems.addAll(getRepositoryFilterItems(currentParameters));

		// preserve repository filter options on time choices
		filters.menuItems.addAll(getTimeFilterItems(currentParameters));

		if (filters.menuItems.size() > 0) {
			// Reset Filter
			filters.menuItems.add(new ParameterMenuItem(getString("gb.reset")));
		}
		navLinks.add(filters);
	}

	/**
	 * Creates the daily activity line chart, the active repositories pie chart,
	 * and the active authors pie chart
	 *
	 * @param recentActivity
	 * @return
	 */
	private Charts createCharts(List<Activity> recentActivity) {
		// activity metrics
		Map<String, Metric> repositoryMetrics = new HashMap<String, Metric>();
		Map<String, Metric> authorMetrics = new HashMap<String, Metric>();

		// aggregate repository and author metrics
		for (Activity activity : recentActivity) {

			// aggregate author metrics
			for (Map.Entry<String, Metric> entry : activity.getAuthorMetrics().entrySet()) {
				String author = entry.getKey();
				if (!authorMetrics.containsKey(author)) {
					authorMetrics.put(author, new Metric(author));
				}
				authorMetrics.get(author).count += entry.getValue().count;
			}

			// aggregate repository metrics
			for (Map.Entry<String, Metric> entry : activity.getRepositoryMetrics().entrySet()) {
				String repository = StringUtils.stripDotGit(entry.getKey());
				if (!repositoryMetrics.containsKey(repository)) {
					repositoryMetrics.put(repository, new Metric(repository));
				}
				repositoryMetrics.get(repository).count += entry.getValue().count;
			}
		}

		// build charts
		Charts charts = new Flotr2Charts();

		// sort in reverse-chronological order and then reverse that
		Collections.sort(recentActivity);
		Collections.reverse(recentActivity);

		// daily line chart
		Chart chart = charts.createLineChart("chartDaily", getString("gb.dailyActivity"), "day",
				getString("gb.commits"));
		SimpleDateFormat df = new SimpleDateFormat("MMM dd");
		df.setTimeZone(getTimeZone());
		for (Activity metric : recentActivity) {
			chart.addValue(metric.startDate, metric.getCommitCount());
		}
		charts.addChart(chart);

		// active repositories pie chart
		chart = charts.createPieChart("chartRepositories", getString("gb.activeRepositories"),
				getString("gb.repository"), getString("gb.commits"));
		for (Metric metric : repositoryMetrics.values()) {
			chart.addValue(metric.name, metric.count);
		}
		chart.setShowLegend(false);
		String url = urlFor(SummaryPage.class, null).toString() + "?r=";
		chart.setClickUrl(url);
		charts.addChart(chart);

		// active authors pie chart
		chart = charts.createPieChart("chartAuthors", getString("gb.activeAuthors"),
				getString("gb.author"), getString("gb.commits"));
		for (Metric metric : authorMetrics.values()) {
			chart.addValue(metric.name, metric.count);
		}
		chart.setShowLegend(false);
		charts.addChart(chart);

		return charts;
	}
}
