<commit_before>// CloudCoder - a web-based pedagogical programming environment
// Copyright (C) 2011-2013, <NAME> <<EMAIL>>
// Copyright (C) 2011-2013, <NAME> <<EMAIL>>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

package org.cloudcoder.app.client.page;

import org.cloudcoder.app.client.model.CourseSelection;
import org.cloudcoder.app.client.model.Section;
import org.cloudcoder.app.client.model.Session;
import org.cloudcoder.app.client.model.StatusMessage;
import org.cloudcoder.app.client.rpc.RPC;
import org.cloudcoder.app.client.view.PageNavPanel;
import org.cloudcoder.app.client.view.StatusMessageView;
import org.cloudcoder.app.client.view.StudentProgressView;
import org.cloudcoder.app.shared.model.Course;
import org.cloudcoder.app.shared.model.Problem;
import org.cloudcoder.app.shared.util.Publisher;
import org.cloudcoder.app.shared.util.Subscriber;
import org.cloudcoder.app.shared.util.SubscriptionRegistrar;

import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.DockLayoutPanel;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.InlineLabel;
import com.google.gwt.user.client.ui.IsWidget;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.LayoutPanel;
import com.google.gwt.user.client.ui.ListBox;

/**
 * Page for displaying statistics for a given {@link Problem}.
 * 
 * @author <NAME>
 */
public class StatisticsPage extends CloudCoderPage {
	
	private class UI extends Composite implements Subscriber {
		private static final double STATS_OPTION_PANEL_HEIGHT_PX = 28.0;

		private PageNavPanel pageNavPanel;
		private Label problemLabel;
		private StatusMessageView statusMessageView;
		private StudentProgressView studentProgressView;
		private ListBox chooseSectionBox;

		public UI() {
			DockLayoutPanel dockLayoutPanel = new DockLayoutPanel(Unit.PX);

			// North panel: problem label, page nav panel, stats options (TODO)
			LayoutPanel northPanel = new LayoutPanel();
			
			// page nav panel
			this.pageNavPanel = new PageNavPanel();
			northPanel.add(pageNavPanel);
			northPanel.setWidgetRightWidth(pageNavPanel, 0.0, Unit.PX, PageNavPanel.WIDTH_PX, Unit.PX);
			northPanel.setWidgetTopHeight(pageNavPanel, 0.0, Unit.PX, PageNavPanel.HEIGHT_PX, Unit.PX);
			
			// label to display the problem name
			this.problemLabel = new Label("");
			problemLabel.setStyleName("cc-problemName", true);
			northPanel.add(problemLabel);
			northPanel.setWidgetLeftRight(problemLabel, 0.0, Unit.PX, PageNavPanel.WIDTH_PX, Unit.PX);
			northPanel.setWidgetTopHeight(problemLabel, 0.0, Unit.PX, 22.0, Unit.PX);
			
			// stats options (choose section, sorting, download CSV)
			FlowPanel statsOptionPanel = new FlowPanel();
			InlineLabel chooseSectionLabel = new InlineLabel("Section: ");
			statsOptionPanel.add(chooseSectionLabel);
			this.chooseSectionBox = new ListBox();
			chooseSectionBox.setWidth("80px");
			chooseSectionBox.addChangeHandler(new ChangeHandler() {
				@Override
				public void onChange(ChangeEvent event) {
					handleSectionChange();
				}
			});
			statsOptionPanel.add(chooseSectionBox);
			
			northPanel.add(statsOptionPanel);
			northPanel.setWidgetLeftRight(statsOptionPanel, 0.0, Unit.PX, 0.0, Unit.PX);
			northPanel.setWidgetBottomHeight(statsOptionPanel, 0.0, Unit.PX, STATS_OPTION_PANEL_HEIGHT_PX, Unit.PX);
			
			dockLayoutPanel.addNorth(northPanel, PageNavPanel.HEIGHT_PX + STATS_OPTION_PANEL_HEIGHT_PX);
			
			// South panel: just a status message view
			statusMessageView = new StatusMessageView();
			dockLayoutPanel.addSouth(statusMessageView, StatusMessageView.HEIGHT_PX);
			
			// Center panel: stats view
			LayoutPanel centerPanel = new LayoutPanel();
			this.studentProgressView = new StudentProgressView();
			centerPanel.add(studentProgressView);
			centerPanel.setWidgetLeftRight(studentProgressView, 0.0, Unit.PX, 0.0, Unit.PX);
			centerPanel.setWidgetTopBottom(studentProgressView, 10.0, Unit.PX, 10.0, Unit.PX);
			dockLayoutPanel.add(centerPanel);
			
			initWidget(dockLayoutPanel);
		}

		protected void handleSectionChange() {
			int selected = chooseSectionBox.getSelectedIndex();
			if (selected >= 0) {
				String choice = chooseSectionBox.getItemText(selected);
				
				// Add a Section object to the session.
				// The StudentProgressView listens for these events,
				// and updates the results appropriately.
				if (choice.equals("All")) {
					getSession().add(new Section()); // all sections
				} else {
					int section = Integer.parseInt(choice);
					getSession().add(new Section(section));
				}
			}
		}

		public void activate(final Session session, final SubscriptionRegistrar subscriptionRegistrar) {
			// Initially, results for all sections are shown
			session.add(new Section());
			
			// Activate views
			statusMessageView.activate(session, subscriptionRegistrar);
			studentProgressView.activate(session, subscriptionRegistrar);
			
			// Set title<commit_msg>Added a download button to download data as CSV<commit_after>// CloudCoder - a web-based pedagogical programming environment
// Copyright (C) 2011-2013, <NAME> <<EMAIL>>
// Copyright (C) 2011-2013, <NAME> <<EMAIL>>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

package org.cloudcoder.app.client.page;

import org.cloudcoder.app.client.model.CourseSelection;
import org.cloudcoder.app.client.model.Section;
import org.cloudcoder.app.client.model.Session;
import org.cloudcoder.app.client.model.StatusMessage;
import org.cloudcoder.app.client.rpc.RPC;
import org.cloudcoder.app.client.view.PageNavPanel;
import org.cloudcoder.app.client.view.StatusMessageView;
import org.cloudcoder.app.client.view.StudentProgressView;
import org.cloudcoder.app.shared.model.Course;
import org.cloudcoder.app.shared.model.Problem;
import org.cloudcoder.app.shared.util.Publisher;
import org.cloudcoder.app.shared.util.Subscriber;
import org.cloudcoder.app.shared.util.SubscriptionRegistrar;

import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
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.DockLayoutPanel;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.InlineHTML;
import com.google.gwt.user.client.ui.InlineLabel;
import com.google.gwt.user.client.ui.IsWidget;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.LayoutPanel;
import com.google.gwt.user.client.ui.ListBox;

/**
 * Page for displaying statistics for a given {@link Problem}.
 * 
 * @author <NAME>
 */
public class StatisticsPage extends CloudCoderPage {
	
	private class UI extends Composite implements Subscriber {
		private static final double STATS_OPTION_PANEL_HEIGHT_PX = 28.0;

		private PageNavPanel pageNavPanel;
		private Label problemLabel;
		private StatusMessageView statusMessageView;
		private StudentProgressView studentProgressView;
		private Button downloadCsvButton;
		private ListBox chooseSectionBox;

		public UI() {
			DockLayoutPanel dockLayoutPanel = new DockLayoutPanel(Unit.PX);

			// North panel: problem label, page nav panel, stats options (TODO)
			LayoutPanel northPanel = new LayoutPanel();
			
			// page nav panel
			this.pageNavPanel = new PageNavPanel();
			northPanel.add(pageNavPanel);
			northPanel.setWidgetRightWidth(pageNavPanel, 0.0, Unit.PX, PageNavPanel.WIDTH_PX, Unit.PX);
			northPanel.setWidgetTopHeight(pageNavPanel, 0.0, Unit.PX, PageNavPanel.HEIGHT_PX, Unit.PX);
			
			// label to display the problem name
			this.problemLabel = new Label("");
			problemLabel.setStyleName("cc-problemName", true);
			northPanel.add(problemLabel);
			northPanel.setWidgetLeftRight(problemLabel, 0.0, Unit.PX, PageNavPanel.WIDTH_PX, Unit.PX);
			northPanel.setWidgetTopHeight(problemLabel, 0.0, Unit.PX, 22.0, Unit.PX);
			
			// stats options (choose section, sorting, download CSV)
			FlowPanel statsOptionPanel = new FlowPanel();
			InlineLabel chooseSectionLabel = new InlineLabel("Section: ");
			statsOptionPanel.add(chooseSectionLabel);
			this.chooseSectionBox = new ListBox();
			chooseSectionBox.setWidth("80px");
			chooseSectionBox.addChangeHandler(new ChangeHandler() {
				@Override
				public void onChange(ChangeEvent event) {
					handleSectionChange();
				}
			});
			statsOptionPanel.add(chooseSectionBox);
			statsOptionPanel.add(new InlineHTML(" "));
			this.downloadCsvButton = new Button("Download");
			downloadCsvButton.addClickHandler(new ClickHandler() {
				@Override
				public void onClick(ClickEvent event) {
					handleDownloadCsv();
				}
			});
			statsOptionPanel.add(downloadCsvButton);
			
			// Create a hidden iframe element for the CSV download
			InlineHTML iframe = new InlineHTML("<iframe id=\"ccCsvDownload\" style=\"height: 1px; width: 1px; display: none;\"></iframe>");
			statsOptionPanel.add(iframe);
			
			northPanel.add(statsOptionPanel);
			northPanel.setWidgetLeftRight(statsOptionPanel, 0.0, Unit.PX, 0.0, Unit.PX);
			northPanel.setWidgetBottomHeight(statsOptionPanel, 0.0, Unit.PX, STATS_OPTION_PANEL_HEIGHT_PX, Unit.PX);
			
			dockLayoutPanel.addNorth(northPanel, PageNavPanel.HEIGHT_PX + STATS_OPTION_PANEL_HEIGHT_PX);
			
			// South panel: just a status message view
			statusMessageView = new StatusMessageView();
			dockLayoutPanel.addSouth(statusMessageView, StatusMessageView.HEIGHT_PX);
			
			// Center panel: stats view
			LayoutPanel centerPanel = new LayoutPanel();
			this.studentProgressView = new StudentProgressView();
			centerPanel.add(studentProgressView);
			centerPanel.setWidgetLeftRight(studentProgressView, 0.0, Unit.PX, 0.0, Unit.PX);
			centerPanel.setWidgetTopBottom(studentProgressView, 10.0, Unit.PX, 10.0, Unit.PX);
			dockLayoutPanel.add(centerPanel);
			
			initWidget(dockLayoutPanel);
		}

		protected void handleSectionChange() {
			int selected = chooseSectionBox.getSelectedIndex();
			if (selected >= 0) {
				String choice = chooseSectionBox.getItemText(selected);
				
				// Add a Section object to the session.
				// The StudentProgressView listens for these events,
				// and updates the results appropriately.
				if (choice.equals("All")) {
					getSession().add(new Section()); // all sections
				} else {
					int section = Integer.parseInt(choice);
					getSession().add(new Section(section));
				}
			}
		}

		protected void handleDownloadCsv() {
			// Redirect to the /admin/problems servlet with the chosen
			// course/problem/section
			// TODO: handle section
			Problem problem = getSession().get(Problem.class);
			String url = GWT.getHostPageBaseURL() + "admin/problems/" + problem.getCourseId() + "/" + problem.getProblemId();
			GWT.log("Redirecting iframe to " + url);
			doDownloadCsv(url);
		}
		
		private native void doDownloadCsv(String url) /*-{
			var elt = $doc.getElementById("ccCsvDownload");
			elt.src = url;
		}-*/;

		public void activate(final Session session, final SubscriptionRegistrar subscriptionRegistrar) {
			// Initially, results for all sections are shown
			session.add(new Section());
			
			// Activate views
			statusMessageView.activate(session, subscriptionRegistrar);
			studentProgressView.activate(session, subscriptionRegistrar);
			
			// Set title
{'fraction_non_alphanumeric': 0.10770773860041663, 'fraction_numerical': 0.007869763135560528, 'mean_word_length': 4.400833333333333, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 16, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5563159', 'n_tokens_mistral': 4475, 'n_tokens_neox': 3908, 'n_words': 934}