Click here to Skip to main content
15,883,938 members
Articles / Desktop Programming / Windows Forms

Reputationator - CP Narcissists Rejoice! Part 1 of 4

Rate me:
Please Sign up or sign in to vote.
4.93/5 (35 votes)
30 Aug 2011CPOL22 min read 58.6K   882   41  
Keep more detailed track of your Codeproject reputation points.
#define __SCRAPING_ALLOWED__
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
using System.ComponentModel;

using ReputationLib;

namespace RepWPF
{
	/// <summary>
	/// Interaction logic for MainWindow.xaml
	/// </summary>
	public partial class MainWindow : Window
	{
		private bool   m_initialized = false;
		private string comma         = CultureInfo.CurrentCulture.NumberFormat.NumberGroupSeparator;

		//--------------------------------------------------------------------------------
		public MainWindow()
		{
			string[] args = Environment.GetCommandLineArgs();

			// Parameters to adjust database - because args[0] is the name of this 
			// program, we can safely ignore it, but that also means we have to account 
			// for it before trying to retrieve the real commandline arguments.
			if (args.Length > 1)
			{
				for (int i = 1; i < args.Length; i++)
				{
					string arg = args[i];
					switch (arg.ToLower())
					{
						case "db1" :
						case "/db1" :
						case "-db1" :
							Globals.AdjustExistingDbTotals = true;
							break;
					}
				}
			}

			RepSettings.Default.Reload();
			Globals.UserID           = RepSettings.Default.UserID;
			Globals.ConnectionString = RepSettings.Default.ConnectionString;

			InitializeComponent();

			// retrieve our data from the database
#if __SCRAPING_ALLOWED__
			WpfGlobals.Scraper.Reputations.GetData();
#else
			WpfGlobals.Scraper.Reputations.TestFill(new DateTime(2011, 7, 1), 7741);
#endif

			// add event handlers  for the scraper
			WpfGlobals.Scraper.ScrapeComplete += new ScraperEventHandler(Scraper_ScrapeComplete);
			WpfGlobals.Scraper.ScrapeFail     += new ScraperEventHandler(Scraper_ScrapeFail);
			WpfGlobals.Scraper.ScrapeProgress += new ScraperEventHandler(Scraper_ScrapeProgress);
		}

		//--------------------------------------------------------------------------------
		~MainWindow()
		{
			AddControlEventHandlers(false);

			WpfGlobals.Scraper.ScrapeComplete -= new ScraperEventHandler(Scraper_ScrapeComplete);
			WpfGlobals.Scraper.ScrapeFail     -= new ScraperEventHandler(Scraper_ScrapeFail);
			WpfGlobals.Scraper.ScrapeProgress -= new ScraperEventHandler(Scraper_ScrapeProgress);
		}

		//--------------------------------------------------------------------------------
		private void Window_Loaded(object sender, RoutedEventArgs e)
		{
			InitControls();
			AddControlEventHandlers(true);
			m_initialized = true;
			RenderChart();
			CalculateTopSection();
		}

		#region "ChartConfig panel events"
		//--------------------------------------------------------------------------------
		void checkBoxTrendLines_Unchecked(object sender, RoutedEventArgs e)
		{
			if (m_initialized)
			{
				RenderChart();
			}
		}

		//--------------------------------------------------------------------------------
		void checkBoxTrendLines_Checked(object sender, RoutedEventArgs e)
		{
			if (m_initialized)
			{
				RenderChart();
			}
		}

		//--------------------------------------------------------------------------------
		void comboTimePeriod_SelectionChanged(object sender, SelectionChangedEventArgs e)
		{
			if (m_initialized)
			{
				RenderChart();
			}
		}

		//--------------------------------------------------------------------------------
		void comboChart_SelectionChanged(object sender, SelectionChangedEventArgs e)
		{
			if (m_initialized)
			{
				RenderChart();
			}
		}

		//--------------------------------------------------------------------------------
		void checkedLBCategories_CheckedChanged(object sender, Microsoft.Windows.Controls.CheckListBoxCheckedChangedEventArgs e)
		{
			if (m_initialized)
			{
				RenderChart();
			}
		}
		#endregion "ChartConfig panel events"

		#region "Stated Goal panel"
		//--------------------------------------------------------------------------------
		/// <summary>
		/// Fired when the user selects a new goal date (via the calendar dropdown) in 
		/// the stated goal panel.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		void dateTimePickerGoalDate_ValueChanged(object sender, SelectionChangedEventArgs e)
		{
		}

		//--------------------------------------------------------------------------------
		/// <summary>
		/// Fired when the user clicks the recalculate button in the stated goal panel.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		void buttonRecalcGoal_Click(object sender, RoutedEventArgs e)
		{
			int goalPoints;
			string text = this.StatedGoalPanel.textBoxGoalPoints.Text.Replace(comma, "").Replace(",", "").Replace(".", "");
			if (int.TryParse(text, out goalPoints))
			{
				DateTime goalDate     = this.StatedGoalPanel.dateTimePickerGoalDate.SelectedDate.Value.Date;
				DateTime now          = DateTime.Now.Date;
				int      latestValue  = WpfGlobals.Scraper.Reputations.GetLatestPointValue(RepCategory.Total);
				int      avgValue     = WpfGlobals.Scraper.Reputations.GetDailyAverage(RepCategory.Total);
				TimeSpan span         = goalDate - now;
				int      futurePoints = latestValue + (avgValue * span.Days);
				int      pointsDiff   = futurePoints - goalPoints;

				// this needs to be calculated based on trend information instead of the 
				// current average.
				if (pointsDiff > 1000)
				{
					this.StatedGoalPanel.labelGoalStatus.Content = "Excellent";
				}
				else if (pointsDiff > -1000 && pointsDiff < 1000)
				{
					this.StatedGoalPanel.labelGoalStatus.Content = "Good";
				}
				else
				{
					this.StatedGoalPanel.labelGoalStatus.Content = "Poor";
				}
			}
		}

		//--------------------------------------------------------------------------------
		/// <summary>
		/// Fired when the user changes the contents of the goal points in the stated 
		/// goal panel.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		void textBoxGoalPoints_TextChanged(object sender, TextChangedEventArgs e)
		{
			string  validchars = "0123456789,";
			TextBox textbox    = sender as TextBox;
			string  text       = textbox.Text.Replace(comma, "").Replace(",", "").Replace(".", ""); ;
			int     points     = 0;
			if (!string.IsNullOrEmpty(text))
			{
				char lastChar      = text.Last();
				if (!validchars.Contains(lastChar))
				{
					text = text.Substring(0, text.Length - 1);
				}
				if (!string.IsNullOrEmpty(text))
				{
					points = Convert.ToInt32(text);
					text = string.Format("{0:#,#}", points);
				}
				if (textbox.Text != text)
				{
					textbox.Text = text;
					if (!string.IsNullOrEmpty(text))
					{
						textbox.SelectionStart = text.Length - 1;
					}
				}
			}
			this.StatedGoalPanel.buttonRecalcGoal.IsEnabled = (points > 0);
		}
		#endregion "Stated Goal panel"

		#region "Config panel"
		//--------------------------------------------------------------------------------
		/// <summary>
		/// Fired when the user changes the contents of the userID textbox in the config 
		/// panel.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		void textBoxUserID_TextChanged(object sender, TextChangedEventArgs e)
		{
			string  validchars = "0123456789,";
			TextBox textbox    = sender as TextBox;
			string text = textbox.Text;
			int id = 0;
			if (!string.IsNullOrEmpty(text))
			{
				char lastChar      = text.Last();
				if (!validchars.Contains(lastChar))
				{
					text = text.Substring(0, text.Length - 1);
				}
				if (!string.IsNullOrEmpty(text))
				{
					id = Convert.ToInt32(text);
				}
				if (textbox.Text != text)
				{
					textbox.Text = text;
					if (!string.IsNullOrEmpty(text))
					{
						textbox.SelectionStart = text.Length - 1;
					}
				}
			}
#if (__SCRAPING_ALLOWED__)
			this.ConfigPanel.buttonGetData.IsEnabled = (id > 0);
#else
			this.ConfigPanel.buttonGetData.IsEnabled = false;
#endif
		}

		//--------------------------------------------------------------------------------
		/// <summary>
		/// Fired when the user clicks the manage service button in the configpanel.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		void buttonManageSvc_Click(object sender, RoutedEventArgs e)
		{
			ExternalProcess.Run("RepSvcManager.exe", "", true);
		}

		//--------------------------------------------------------------------------------
		/// <summary>
		/// Fired when the user clicks the Get Data button in the config panel.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		void buttonGetData_Click(object sender, RoutedEventArgs e)
		{
			if (!string.IsNullOrEmpty(ConfigPanel.textBoxUserID.Text))
			{
				Globals.ConnectionString = RepSettings.Default.ConnectionString;
				int userID;
				string text = this.ConfigPanel.textBoxUserID.Text;
				if (!string.IsNullOrEmpty(text) && Int32.TryParse(text, out userID))
				{
					RepSettings.Default.UserID = userID;
					Globals.UserID = RepSettings.Default.UserID;
				}
				WpfGlobals.Scraper.ScrapeWebPage();
			}
		}
		#endregion "Config panel"

		#region "Main Scraper events"
		//--------------------------------------------------------------------------------
		/// <summary>
		/// Fired when the main scraper sends a scrape completed event.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		void Scraper_ScrapeComplete(object sender, ScrapeEventArgs e)
		{
			Dispatcher.Invoke(DispatcherPriority.Normal, (Action)delegate
			{
				WpfGlobals.Scraper.Reputations.CalcChangedValues();
				CalculateTopSection();
				RenderChart(); // runs on UI thread
			});
		}

		//--------------------------------------------------------------------------------
		/// <summary>
		/// Fired when the main scraper sends a scrape failed event.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		void Scraper_ScrapeFail(object sender, ScrapeEventArgs e)
		{
		}

		//--------------------------------------------------------------------------------
		/// <summary>
		/// Fired when the main scraper sends a progress event (not used in this app).
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		void Scraper_ScrapeProgress(object sender, ScrapeEventArgs e)
		{
			throw new NotImplementedException();
		}
		#endregion "Main Scraper events"

		#region "Leader scraper events"
		//--------------------------------------------------------------------------------
		/// <summary>
		/// Fired when the leader scrape fails
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		void leaderScraper_ScrapeFail(object sender, ScrapeEventArgs e)
		{
			ScrapeLeader scraper = sender as ScrapeLeader;
			Dispatcher.Invoke(DispatcherPriority.Normal, (Action)delegate
			{
				UpdateLeaderInfo(sender as ScrapeLeader, false);
			});
			scraper.ScrapeFail -= new ScraperEventHandler(leaderScraper_ScrapeFail);
		}


		//--------------------------------------------------------------------------------
		/// <summary>
		/// Fired when the leader scrape completes successfully
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		void leaderScraper_ScrapeComplete(object sender, ScrapeEventArgs e)
		{
			ScrapeLeader scraper = sender as ScrapeLeader;
			Dispatcher.Invoke(DispatcherPriority.Normal, (Action)delegate
			{
				UpdateLeaderInfo(sender as ScrapeLeader, true);
			});
			scraper.ScrapeComplete -= new ScraperEventHandler(leaderScraper_ScrapeComplete);
		}
		#endregion "Leader scraper events"


		#region "Other methods (initialization)"
		//--------------------------------------------------------------------------------
		/// <summary>
		/// Adds event handlers for all of the necessary child controls of the compoent 
		/// user controls.
		/// </summary>
		/// <param name="add"></param>
		private void AddControlEventHandlers(bool add)
		{
			// I wanted to handle all of the control events in the main window class, so 
			// all of the controls have the FieldModifier="public" attribute.  I know - 
			// this isn't very OOPtastic, but it's a helluva lot more convenient.
			if (add)
			{
				ConfigPanel.buttonGetData.Click       += new RoutedEventHandler(buttonGetData_Click);
				ConfigPanel.buttonManageSvc.Click     += new RoutedEventHandler(buttonManageSvc_Click);
				ConfigPanel.textBoxUserID.TextChanged += new TextChangedEventHandler(textBoxUserID_TextChanged);

				StatedGoalPanel.textBoxGoalPoints.TextChanged              += new TextChangedEventHandler(textBoxGoalPoints_TextChanged);
				StatedGoalPanel.buttonRecalcGoal.Click                     += new RoutedEventHandler(buttonRecalcGoal_Click);
				StatedGoalPanel.dateTimePickerGoalDate.SelectedDateChanged += new EventHandler<SelectionChangedEventArgs>(dateTimePickerGoalDate_ValueChanged);

				ChartConfigPanel.checkedLBCategories.CheckedChanged += new Microsoft.Windows.Controls.CheckListBoxCheckedChangedEventHandler(checkedLBCategories_CheckedChanged);
				ChartConfigPanel.comboChart.SelectionChanged        += new SelectionChangedEventHandler(comboChart_SelectionChanged);
				ChartConfigPanel.comboTimePeriod.SelectionChanged   += new SelectionChangedEventHandler(comboTimePeriod_SelectionChanged);
				ChartConfigPanel.checkBoxTrendLines.Checked         += new RoutedEventHandler(checkBoxTrendLines_Checked);
				ChartConfigPanel.checkBoxTrendLines.Unchecked       += new RoutedEventHandler(checkBoxTrendLines_Unchecked);

				ConfigPanel.buttonGetData.IsEnabled = false;
#if (!__SCRAPING_ALLOWED__)
				ConfigPanel.buttonGetData.IsEnabled = false;
				ConfigPanel.textBoxUserID.IsEnabled = false;
#endif
			}
			else
			{
				ConfigPanel.buttonGetData.Click       -= new RoutedEventHandler(buttonGetData_Click);
				ConfigPanel.buttonManageSvc.Click     -= new RoutedEventHandler(buttonManageSvc_Click);
				ConfigPanel.textBoxUserID.TextChanged -= new TextChangedEventHandler(textBoxUserID_TextChanged);

				StatedGoalPanel.textBoxGoalPoints.TextChanged              -= new TextChangedEventHandler(textBoxGoalPoints_TextChanged);
				StatedGoalPanel.buttonRecalcGoal.Click                     -= new RoutedEventHandler(buttonRecalcGoal_Click);
				StatedGoalPanel.dateTimePickerGoalDate.SelectedDateChanged -= new EventHandler<SelectionChangedEventArgs>(dateTimePickerGoalDate_ValueChanged);

				ChartConfigPanel.checkedLBCategories.CheckedChanged -= new Microsoft.Windows.Controls.CheckListBoxCheckedChangedEventHandler(checkedLBCategories_CheckedChanged);
				ChartConfigPanel.comboChart.SelectionChanged        -= new SelectionChangedEventHandler(comboChart_SelectionChanged);
				ChartConfigPanel.comboTimePeriod.SelectionChanged   -= new SelectionChangedEventHandler(comboTimePeriod_SelectionChanged);
				ChartConfigPanel.checkBoxTrendLines.Checked         -= new RoutedEventHandler(checkBoxTrendLines_Checked);
				ChartConfigPanel.checkBoxTrendLines.Unchecked       -= new RoutedEventHandler(checkBoxTrendLines_Unchecked);
			}
		}

		//--------------------------------------------------------------------------------
		/// <summary>
		/// Initializes the child controls in the required control panels.
		/// </summary>
		private void InitControls()
		{
			StatedGoalPanel.dateTimePickerGoalDate.SelectedDate       = DateTime.Now.Date;
			StatedGoalPanel.dateTimePickerGoalDate.SelectedDateFormat = DatePickerFormat.Short;
			ChartConfigPanel.datePickerFrom.SelectedDate              = DateTime.Now.Date;
			ChartConfigPanel.datePickerFrom.SelectedDateFormat        = DatePickerFormat.Short;
			ChartConfigPanel.datePickerTo.SelectedDate                = DateTime.Now.Date;
			ChartConfigPanel.datePickerTo.SelectedDateFormat          = DatePickerFormat.Short;
			ConfigPanel.textBoxUserID.Text                            = Globals.UserID.ToString();
		}
		#endregion "Other methods (initialization)"

		#region "Other methods (calculation and display)"
		//--------------------------------------------------------------------------------
		/// <summary>
		/// Renders the desired chart with the selected criteria.
		/// </summary>
		private void RenderChart()
		{
			// get the selected display categories
			DisplayCategories categories = new DisplayCategories();
			foreach (CLBCategoryItem item in WpfGlobals.CLBCategories)
			{
				if (item.IsChecked)
				{
					categories.Add(item.EnumValue);
				}
			}

			string chartName  = ((ComboBoxItem)(this.ChartConfigPanel.comboChart.SelectedItem)).Content.ToString();
			string timePeriod = ((ComboBoxItem)(this.ChartConfigPanel.comboTimePeriod.SelectedItem)).Content.ToString();
			DateTime from = (timePeriod == "Specified Period") ? (DateTime)this.ChartConfigPanel.datePickerFrom.SelectedDate : new DateTime(0);
			DateTime to   = (timePeriod == "Specified Period") ? (DateTime)this.ChartConfigPanel.datePickerTo.SelectedDate : DateTime.Now;

			this.ChartPanel.ShowChart(chartName, timePeriod, from.Date, to.Date, categories, (bool)(this.ChartConfigPanel.checkBoxTrendLines.IsChecked));
		}

		//--------------------------------------------------------------------------------
		/// <summary>
		/// Recalclates the data displayed in the listviews in the current and earned 
		/// period points panels.
		/// </summary>
		private void CalculateTopSection()
		{
			// recalculate the current points and daily averages for each category
			WpfGlobals.CurrentPoints.Clear();
			WpfGlobals.EarnedPoints.Clear();

			foreach (RepCategory category in Enum.GetValues(typeof(RepCategory)))
			{
				if (category != RepCategory.Unknown)
				{
					WpfGlobals.CurrentPoints.Add(new CurrentPointsItem()
					{
						CategoryName = category.ToString(),
						PointsAvg    = string.Format("{0:#,#}", WpfGlobals.Scraper.Reputations.GetDailyAverage(category)),
						PointsValue  = string.Format("{0:#,#}", WpfGlobals.Scraper.Reputations.GetLatestPointValue(category))
					});
				}
			}

			// Calcuate the points for the current week, month, and year, and project how 
			// many points the user will have at the end of those periods
			foreach (RepPeriod period in Enum.GetValues(typeof(RepPeriod)))
			{
				int value;
				int projected;
				WpfGlobals.Scraper.Reputations.GetCurrentPeriodPoints(period, RepCategory.Total, out value, out projected);
				WpfGlobals.EarnedPoints.Add(new EarnedPointsItem()
				{
					PeriodName = period.ToString(),
					PointsProjected = string.Format("{0:#,#}", projected),
					PointsValue     = string.Format("{0:#,#}", value)
				});
			}

#if __SCRAPING_ALLOWED__
			ScrapeLeader scraper = new ScrapeLeader();
			scraper.ScrapeComplete += new ScraperEventHandler(leaderScraper_ScrapeComplete);
			scraper.ScrapeFail     += new ScraperEventHandler(leaderScraper_ScrapeFail);
			scraper.ScrapeWebPage();
#else
			UpdateLeaderInfo(null, false);
#endif
		}

		//--------------------------------------------------------------------------------
		/// <summary>
		/// Calculates the date at which the user will overtake the user  who is 
		/// currently in first place in the points.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="success"></param>
		void UpdateLeaderInfo(ScrapeLeader sender, bool success)
		{
			// get our existing data
			string   savedName   = RepSettings.Default.LeaderName;
			int      savedPoints = RepSettings.Default.LeaderPoints;
			DateTime savedDate   = RepSettings.Default.LeaderDate;
			// If the name is empty or not the same as what was already there, assume 
			// we need ro save everything
			bool     virgin      = (string.IsNullOrEmpty(savedName) || savedName != sender.LeaderName);

			if (success)
			{
				if (Globals.UserID == (Convert.ToInt32(sender.LeaderID)))
				{
					this.LeaderPanel.labelOvertake.Text = "YOU'RE THE CURRENT POINTS LEADER!!!";
				}
				else
				{
					if (virgin)
					{
						// save our current date and scraped points for use in the calcs
						savedDate                        = DateTime.Now.Date;
						savedPoints                      = sender.LeaderPoints;
						// and save everything in the config file
						RepSettings.Default.LeaderName   = sender.LeaderName;
						RepSettings.Default.LeaderDate   = savedDate;
						RepSettings.Default.LeaderPoints = savedPoints;
						RepSettings.Default.Save();
					}

					// math
					bool evenAvg      = false;
					int  overtakeDays = 0;
					{
						// get user's current points
						int yourPoints        = WpfGlobals.Scraper.Reputations.GetLatestPointValue(RepCategory.Total);
						// determine the difference between the users points and the leaders points. This is 
						// the number of points the user has to make up.
						int pointsDelta       = sender.LeaderPoints - yourPoints;
						TimeSpan span         = DateTime.Now - savedDate;
						int      leaderAvgPts = 0;
						int      yourAvgPts   = 0;
						if (span.TotalDays > 0)
						{
							leaderAvgPts = (int)(Math.Ceiling((sender.LeaderPoints - savedPoints) / span.TotalDays));
							yourAvgPts   = WpfGlobals.Scraper.Reputations.GetDailyAverage(RepCategory.Total);
							evenAvg      = (yourAvgPts == leaderAvgPts);
							overtakeDays = (int)(Math.Ceiling((double)pointsDelta / (yourAvgPts - leaderAvgPts)));
						}
					}

					if (overtakeDays > 0)
					{
						DateTime overtakeDate = DateTime.Now.AddDays(overtakeDays);
						this.LeaderPanel.labelOvertake.Text = string.Format("You will overtake {0} ({1:#,##0} pts) on {2}", sender.LeaderName, sender.LeaderPoints, overtakeDate.ToString("dd MMM yyyy"));
					}
					else
					{
						if (evenAvg)
						{
							this.LeaderPanel.labelOvertake.Text = string.Format("Forget it. {0} ({1:#,##0} pts) is matching your pace. You'll never catch him if you don't participate more.", sender.LeaderName, sender.LeaderPoints);
						}
						else
						{
							this.LeaderPanel.labelOvertake.Text = string.Format("Forget it. {0} ({1:#,##0} pts) is pulling away from you. You'll never catch him at the rate you're going.", sender.LeaderName, sender.LeaderPoints);
						}
					}
				}
			} // if (success)
			else
			{
				this.LeaderPanel.labelOvertake.Text = "Leader info scrape failed. No data.";
			}
		}
		#endregion "Other methods (calculation and display)"
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) Paddedwall Software
United States United States
I've been paid as a programmer since 1982 with experience in Pascal, and C++ (both self-taught), and began writing Windows programs in 1991 using Visual C++ and MFC. In the 2nd half of 2007, I started writing C# Windows Forms and ASP.Net applications, and have since done WPF, Silverlight, WCF, web services, and Windows services.

My weakest point is that my moments of clarity are too brief to hold a meaningful conversation that requires more than 30 seconds to complete. Thankfully, grunts of agreement are all that is required to conduct most discussions without committing to any particular belief system.

Comments and Discussions