using System;
using System.IO;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Xml;
using System.Xml.XPath;
using System.Xml.Schema;
namespace NameDrawing
{
public partial class drawinNames : Form
{
public drawinNames()
{
InitializeComponent();
}
public publicData pd = new publicData();
//
// Draw Names
//
public bool doTheNameDraw()
{
//
// It can be that we get to the "bottom of the hat" and the only name left is yours or your spouses!
// So in this case we have to start over
// And this may go on and on there is no 100% guarentee that it will halt.
//
pd.iOuterRepeats = pd.iInnerRepeats = 0;
while (1==1)
{
pd.iOuterRepeats++;
if (pd.iOuterRepeats >= 100)
{
return false;
}
//
// Initialize This Year's Picks To "NOT PICKED"
//
for (int iIndex = 1; iIndex < pd.iNumberOfNames + 1; iIndex++)
{
pd.pParticipantList[iIndex].iThisYearsPick = 0;
pd.pParticipantList[iIndex].bChosen = false;
}
//
// Install The Cheats
//
for (int iIndex = 0; iIndex < pd.iCheatCount; iIndex++)
{
if (pd.cThisYearsCheats[iIndex].sCheatType.CompareTo("MustPick") == 0)
{
int iName = pd.cThisYearsCheats[iIndex].iCheatsName;
int iThisYearsPick = pd.cThisYearsCheats[iIndex].iCheatsPick;
pd.pParticipantList[iName].iThisYearsPick = iThisYearsPick;
pd.pParticipantList[iThisYearsPick].bChosen = true;
}
}
//
// Draw Names For The Rest
//
for (int iIndex = 1; iIndex < pd.iNumberOfNames + 1; iIndex++)
{
//
// If this person already has picked a name then move on
//
if (pd.pParticipantList[iIndex].iThisYearsPick != 0)
{
continue;
}
pd.iInnerRepeats = 0;
while (1 == 1)
{
pd.iInnerRepeats++;
if (pd.iInnerRepeats > 100)
{
break;
}
//
// Pick A Name Out Of The Hat
//
int iThisYearsPick = pd.rand.Next(1, pd.iNumberOfNames + 1);
//
// You Can Not Pick Yourself
//
if (iThisYearsPick == iIndex)
{
continue;
}
//
// You Can Not Pick Someone Who Has Already Been Picked
//
if (pd.pParticipantList[iThisYearsPick].bChosen == true)
{
continue;
}
//
// You Can Not Pick Your Spouse
//
if (pd.pParticipantList[iIndex].iSpouse == iThisYearsPick)
{
continue;
}
//
// You Can Not Pick A Name You Have Drawn Before
//
bool bNeverPickedThisOneBefore = true;
for (int iIndex2 = 0; iIndex2 < pd.iHistoryCount; iIndex2++)
{
if (pd.hHistoryList[iIndex2].ph[iIndex-1].iPicked == iThisYearsPick)
{
bNeverPickedThisOneBefore = false;
break;
}
}
if (bNeverPickedThisOneBefore == false)
{
continue;
}
//
// You Can Not Pick A Name You Are Forbidden To Pick
//
bool bMadeAForbiddenPick = false;
for (int iIndex2 = 0; iIndex2 < pd.iCheatCount; iIndex2++)
{
if ((pd.cThisYearsCheats[iIndex2].sCheatType.CompareTo("MustNotPick") == 0) && // This is a MustNotPick cheat
(pd.cThisYearsCheats[iIndex2].iCheatsName == iIndex) && // This cheat applies this participant
(pd.cThisYearsCheats[iIndex2].iCheatsPick == iThisYearsPick)) // This cheat applies
{
bMadeAForbiddenPick = true;
break;
}
}
if (bMadeAForbiddenPick == true)
{
continue;
}
//
// Found A Pick
//
pd.pParticipantList[iIndex].iThisYearsPick = iThisYearsPick;
pd.pParticipantList[iThisYearsPick].bChosen = true;
break;
}
if (pd.iInnerRepeats > 100)
{
break;
}
}
if (pd.iInnerRepeats > 100)
{
continue;
}
break;
}
return true;
}
public bool doIsTheSecretSantaValid(int iTarget)
{
bool bReturnValue = true;
for (int iIndex = 0; iIndex < pd.iCheatCount; iIndex++)
{
if ((pd.cThisYearsCheats[iIndex].sCheatType.CompareTo("MayNotBeSecretSanta") == 0) && (iTarget == iIndex))
{
bReturnValue = false;
break;
}
}
return bReturnValue;
}
//
// Choose The Secret Santa And The Target;
//
public bool doPickSecretSanta()
{
// Look In The Cheat Sheet To See If SS Target Is Predetermined
// The way this works is some person's pick can be desiginated to be the SS target.
int iTarget = 0;
bool bTargetDetermined = false;
for (int iIndex = 0; iIndex < pd.iCheatCount; iIndex++)
{
if (pd.cThisYearsCheats[iIndex].sCheatType.CompareTo("TheSecretSantaTarget") == 0)
{
bTargetDetermined = true;
iTarget = pd.pParticipantList[pd.cThisYearsCheats[iIndex].iCheatsName].iThisYearsPick;
}
}
pd.iSanta = pd.iTarget = pd.iSSRedraw = 0;
while (1==1)
{
pd.iSanta = pd.rand.Next(1, pd.iNumberOfNames + 1);
// Select The Target (Unless It Is Predetermined)
if (bTargetDetermined)
{
pd.iTarget = iTarget;
}
else
{
pd.iTarget = pd.rand.Next(1, pd.iNumberOfNames + 1);
}
//
// If The Target is precluded from being the Secret Santa Then Skip this person
//
if (doIsTheSecretSantaValid(pd.iTarget) == false)
{
continue;
}
// If Santa Opted Out This Year Then he/she Also Opt Out Of Being The Secret Santa
// OR
// If Santa Target Opted Out This Year Then he/she Also Opt Out Of Being The Secret Santa Target
if ((pd.pParticipantList[pd.iSanta].iThisYearsPick == pd.iSanta) ||
(pd.pParticipantList[pd.iTarget].iThisYearsPick == pd.iTarget) )
{
continue;
}
//
// Target & Santa Can Not Be Same Person
//
if (pd.iSanta == pd.iTarget)
{
pd.iSSRedraw++;
continue;
}
//
// Target & Santa Can Not Be Spouses
//
if (pd.pParticipantList[pd.iSanta].iSpouse == pd.iTarget)
{
pd.iSSRedraw++;
continue;
}
//
// Secret Santa Target Can Not Be The Person Who's Name You Drew
//
if (pd.pParticipantList[pd.iSanta].iThisYearsPick == pd.iTarget)
{
pd.iSSRedraw++;
continue;
}
//
// Search The History Validating that the target and santa do not repeat
//
bool bFoundARepeat = false;
for (int iIndex = 0; ((iIndex < pd.iHistoryCount) && (false == bFoundARepeat)); iIndex++)
{
for (int iIndex2 = 0; ((iIndex2 < pd.hHistoryList[iIndex].iParticipantCount) && (false == bFoundARepeat)); iIndex2++)
{
if ((true == pd.hHistoryList[iIndex].ph[iIndex2].bSanta) &&
(pd.hHistoryList[iIndex].ph[iIndex2].iName == pd.iSanta) || (pd.iTarget == pd.hHistoryList[iIndex].ph[iIndex2].iSantaTarget))
{
bFoundARepeat = true;
break; // Found A Repeat We Need To Pick Again
}
}
if (bFoundARepeat)
{
break; // Found A Repeat We Need To Pick Again
}
}
if (false == bFoundARepeat)
{
break; // This Pair Is Unique Done
}
pd.iSSRedraw++; // Try Again
}
//
// Replace '$' with the iSanta.sName and the '*' with the iTarget.sName
//
pd.sSecretSantaMsg = pd.sSecretSantaMsg.Replace("$", pd.pParticipantList[pd.iSanta].sName);
pd.sSecretSantaMsg = pd.sSecretSantaMsg.Replace("*", pd.pParticipantList[pd.iTarget].sName);
return true;
}
//
// Draw Names
//
private void drawNames_Click(object sender, EventArgs e)
{
writeScript.Enabled = true;
outPutBox.BeginUpdate();
outPutBox.Items.Clear();
outPutBox.EndUpdate();
if ((false == doTheNameDraw()) || (false == doPickSecretSanta()))
{
outPutBox.BeginUpdate();
outPutBox.Items.Add("executeTheDraw FAILED (try again?) ");
outPutBox.Items.Add("iOuterRepeats = " + pd.iOuterRepeats + " iSSRedraw = " + pd.iSSRedraw);
outPutBox.EndUpdate();
}
else
{
if (true == showResults.Checked)
{
outPutBox.BeginUpdate();
outPutBox.Items.Add("iOuterRepeats = " + pd.iOuterRepeats + " iSSRedraw = " + pd.iSSRedraw);
for (int iIndex = 1; iIndex < pd.iNumberOfNames + 1; iIndex++)
{
int iThisYearsPick = pd.pParticipantList[iIndex].iThisYearsPick;
if (iIndex != pd.iSanta)
{
outPutBox.Items.Add("Year=:" + pd.sYear + " " + pd.pParticipantList[iIndex].sName + " Picks: " + pd.pParticipantList[iThisYearsPick].sName);
}
else
{
outPutBox.Items.Add("Year=:" + pd.sYear + " " + pd.pParticipantList[iIndex].sName + " Picks: " + pd.pParticipantList[iThisYearsPick].sName + " SecretSantaTarget: " + pd.pParticipantList[pd.iTarget].sName);
}
}
outPutBox.EndUpdate();
}
}
}
//
// Load The Data
//
private void loadXMLFile_Click(object sender, EventArgs e)
{
//
// Initialize The Random Number Picker
//
pd.rand = new Random();
//
// Initialize The Location Of The Data Files
//
fbdFindDataFileFolder.Description = "Browse To The Folder That Contains The Data Files";
fbdFindDataFileFolder.ShowNewFolderButton = false;
fbdFindDataFileFolder.RootFolder = Environment.SpecialFolder.MyComputer;
if (fbdFindDataFileFolder.ShowDialog() == DialogResult.OK)
{
pd.sDataFolder = fbdFindDataFileFolder.SelectedPath;
}
else
{
return;
}
drawNames.Enabled = true;
XmlSchemaSet sc = new XmlSchemaSet();
sc.Add("urn:drawingnames-schema", pd.sDataFolder + "\\drawing_names.xsd");
XmlReaderSettings settings = new XmlReaderSettings();
settings.ValidationType = ValidationType.Schema;
settings.Schemas = sc;
settings.ProhibitDtd = false;
settings.ValidationEventHandler += new ValidationEventHandler(ValidationCallBack);
XmlReader reader = XmlReader.Create(pd.sDataFolder + "\\drawing_names.xml", settings);
while (reader.Read())
{
if (reader.Name.Equals("thisYearsSecretSantaMessage"))
{
pd.sSecretSantaMsg = reader.GetAttribute("sMessage");
pd.sYear = reader.GetAttribute("sYear");
}
else if (reader.Name.Equals("thisYearsCheatSheet") && (reader.NodeType == XmlNodeType.Element))
{
pd.iCheatCount = Convert.ToInt32(reader.GetAttribute("nCheatCount"));
pd.cThisYearsCheats = new cheat[pd.iCheatCount];
for (int iIndex = 0; iIndex < pd.iCheatCount; iIndex++)
{
while (reader.Read())
{
if (reader.Name.Equals("cheat"))
{
pd.cThisYearsCheats[iIndex].iCheatsName = Convert.ToInt32(reader.GetAttribute("nCheatsName"));
pd.cThisYearsCheats[iIndex].iCheatsPick = Convert.ToInt32(reader.GetAttribute("nCheatNamePicks"));
pd.cThisYearsCheats[iIndex].sCheatsDescription = reader.GetAttribute("sDescription");
pd.cThisYearsCheats[iIndex].sCheatType = reader.GetAttribute("sCheatType");
break;
}
}
}
}
else if (reader.Name.Equals("historyLog") && (reader.NodeType == XmlNodeType.Element))
{
pd.iHistoryCount = Convert.ToInt32(reader.GetAttribute("nYearCount"));
pd.hHistoryList = new history[pd.iHistoryCount];
for (int iIndex = 0; iIndex < pd.iHistoryCount; iIndex++)
{
while (reader.Read())
{
if (reader.Name.Equals("year") && (reader.NodeType == XmlNodeType.Element))
{
pd.hHistoryList[iIndex].iYearNumber = Convert.ToInt32(reader.GetAttribute("nYearNumber"));
pd.hHistoryList[iIndex].iParticipantCount = Convert.ToInt32(reader.GetAttribute("nameCount"));
participantHistory[] phph = new participantHistory[pd.hHistoryList[iIndex].iParticipantCount + 1];
pd.hHistoryList[iIndex].ph = phph;
for (int iIndexP = 0; iIndexP < pd.hHistoryList[iIndex].iParticipantCount; iIndexP++)
{
while (reader.Read())
{
if (reader.Name.Equals("participantHistory"))
{
pd.hHistoryList[iIndex].ph[iIndexP].iName = Convert.ToInt32(reader.GetAttribute("nIndex"));
pd.hHistoryList[iIndex].ph[iIndexP].iPicked = Convert.ToInt32(reader.GetAttribute("nPick"));
pd.hHistoryList[iIndex].ph[iIndexP].bSanta = Convert.ToBoolean(reader.GetAttribute("bSanta"));
if (pd.hHistoryList[iIndex].ph[iIndexP].bSanta)
{
pd.hHistoryList[iIndex].ph[iIndexP].iSantaTarget = Convert.ToInt32(reader.GetAttribute("nSantaTarget"));
}
break;
}
}
}
break;
}
}
}
}
else if (reader.Name.Equals("nameList") && (reader.NodeType == XmlNodeType.Element))
{
pd.iNumberOfNames = Convert.ToInt32(reader.GetAttribute("nListLength"));
pd.pParticipantList = new participant[pd.iNumberOfNames + 1];
for (int iIndex = 0; iIndex < pd.iNumberOfNames; iIndex++)
{
while (reader.Read())
{
if (reader.Name.Equals("participantData"))
{
int iLocation = Convert.ToInt32(reader.GetAttribute("nIndex"));
pd.pParticipantList[iLocation].iSpouse = Convert.ToInt32(reader.GetAttribute("sSpouse"));
pd.pParticipantList[iLocation].sName = reader.GetAttribute("sName");
pd.pParticipantList[iLocation].sPassPhrase = reader.GetAttribute("sPassPhrase");
pd.pParticipantList[iLocation].sDrawMessage = reader.GetAttribute("sDrawMessage");
pd.pParticipantList[iLocation].sSantaMessage = reader.GetAttribute("sMessageSanta");
break;
}
}
}
}
}
reader.Close();
//
// Display The Data If User Indicates To Do So
//
if (true == showResults.Checked)
{
displayXMLContent();
}
}
//
// In Case The XML File Violates The XSD Schema
//
public void ValidationCallBack(object sender, ValidationEventArgs args)
{
pd.isValid = false;
outPutBox.BeginUpdate();
outPutBox.Items.Add("Validation event\n" + args.Message);
outPutBox.EndUpdate();
}
//
// Display Input Data
//
public void displayXMLContent()
{
outPutBox.BeginUpdate();
outPutBox.Items.Add("sSecretSantaMsg ..... " + pd.sSecretSantaMsg);
outPutBox.Items.Add("iCheatCount ......... " + pd.iCheatCount);
for (int iIndex = 0; iIndex < pd.iCheatCount; iIndex++)
{
outPutBox.Items.Add("iCheatsName ......... " + pd.cThisYearsCheats[iIndex].iCheatsName);
outPutBox.Items.Add("iCheatsPick ......... " + pd.cThisYearsCheats[iIndex].iCheatsPick);
outPutBox.Items.Add("sCheatsDescription .. " + pd.cThisYearsCheats[iIndex].sCheatsDescription);
}
outPutBox.Items.Add("iHistoryCount ...... " + pd.iHistoryCount);
for (int iIndex = 0; iIndex < pd.iHistoryCount; iIndex++)
{
outPutBox.Items.Add("iYearNumber ......... " + pd.hHistoryList[iIndex].iYearNumber);
for (int iIndex2 = 1; iIndex2 <= pd.hHistoryList[iIndex].iParticipantCount; iIndex2++)
{
outPutBox.Items.Add("iName ............... " + pd.hHistoryList[iIndex].ph[iIndex2].iName);
outPutBox.Items.Add("iPicked ............. " + pd.hHistoryList[iIndex].ph[iIndex2].iPicked);
outPutBox.Items.Add("bSanta .............. " + pd.hHistoryList[iIndex].ph[iIndex2].bSanta);
outPutBox.Items.Add("iSantaTarget ........ " + pd.hHistoryList[iIndex].ph[iIndex2].iSantaTarget);
}
}
outPutBox.Items.Add("iNumberOfNames ..... " + pd.iNumberOfNames);
for (int iIndex = 0; iIndex < pd.iNumberOfNames; iIndex++)
{
outPutBox.Items.Add("sName ............... " + pd.pParticipantList[iIndex].sName);
outPutBox.Items.Add("iSpouse ............. " + pd.pParticipantList[iIndex].iSpouse);
outPutBox.Items.Add("sPassPhrase ......... " + pd.pParticipantList[iIndex].sPassPhrase);
outPutBox.Items.Add("sDrawMessage ........ " + pd.pParticipantList[iIndex].sDrawMessage);
outPutBox.Items.Add("sSantaMessage ....... " + pd.pParticipantList[iIndex].sSantaMessage);
}
outPutBox.EndUpdate();
}
//
// A Test Of The Crypt Function
//
private void bCrypt_Click(object sender, EventArgs e)
{
tbCryptText.Text = Crypt(tbClearText.Text, tbPassPhrase.Text);
}
//
// Return An Encrypted Version Of sClearText Using sPassPhrase.
//
public string Crypt(string sClearText, string sPassPhrase)
{
Char[] cMyAlphabet = new Char[] { '$', 'A', 'a', '1', 'B', 'b', '2', 'C', 'c', '3', 'D', 'd', '4', 'E', 'e', '5', 'F', 'f', '6', 'G', 'g', '7', 'H', 'h', '8', 'I', 'i', '9', 'J', 'j', '0', 'K', 'k', ' ', 'L', 'l', 'M', 'm', 'N', 'n', 'O', 'o', 'P', 'p', 'Q', 'q', 'R', 'r', 'S', 's', 'T', 't', 'U', 'u', 'V', 'v', 'W', 'w', 'X', 'x', 'Y', 'y', 'Z', 'z' };
string sMyAlphabet;
string sCryptText = "";
sMyAlphabet = "$Aa1Bb2Cc3Dd4Ee5Ff6Gg7Hh8Ii9Jj0Kk LlMmNnOoPpQqRrSsTtUuVvWwXxYyZz";
char[] cCryptText = new char[sClearText.Length];
char[] cClearText = new char[sClearText.Length];
cClearText = sClearText.ToCharArray();
char[] cPassPhrase = new char[sPassPhrase.Length];
cPassPhrase = sPassPhrase.ToCharArray();
//
// Patch Up The Pass Phrase If Necessary
//
int iIllegalCharacterIndex = 1; // Use This Location In myAlphebet To Replace Illegal Characters In The Pass Phrase
for (int iIndex = 0; iIndex < sPassPhrase.Length; iIndex++)
{
if (false == sMyAlphabet.Contains(cPassPhrase[iIndex]))
{
cPassPhrase[iIndex] = cMyAlphabet[iIllegalCharacterIndex];
iIllegalCharacterIndex++;
if (iIllegalCharacterIndex > sMyAlphabet.Length)
{
iIllegalCharacterIndex = 1;
}
}
}
//
// Create The Encrypted Version Of The Clear Text Message
//
int iLocInAlphabet;
int iLocInPassPhrase;
int iLocCryptCharacter;
for (int iIndex = 0; iIndex < sClearText.Length; iIndex++)
{
// find the location in the alphabet of (this) character in the clear text message
iLocInAlphabet = sMyAlphabet.IndexOf(cClearText[iIndex]);
// find the location in the alphabet of (this) character in the pass pharse (modulo the lenght of the pass phrase which could be shorter than the clear text message)
iLocInPassPhrase = sMyAlphabet.IndexOf(cPassPhrase[iIndex % sPassPhrase.Length]);
// XOR the two values together (modulo the length of the alphebet)
iLocCryptCharacter = (iLocInAlphabet ^ iLocInPassPhrase) % sMyAlphabet.Length;
// The resulting value is the encrypted value.
cCryptText[iIndex] = cMyAlphabet[iLocCryptCharacter];
}
//
// Convert Encrypted Character Array To A String
//
for (int iIndex = 0; iIndex < sClearText.Length; iIndex++)
{
sCryptText = sCryptText + cCryptText[iIndex].ToString();
}
return sCryptText;
}
//
// Create The Crypt.js Java Script
//
public void writeScript_Click(object sender, EventArgs e)
{
bViewPage.Enabled = true;
//
// Encrypt The Secret Santa Message
//
pd.sCryptSecretSantaMsg = Crypt(pd.sSecretSantaMsg, pd.pParticipantList[pd.iSanta].sPassPhrase);
//
// Create The Encrypted Version Of The Announcement Messages For Each participant
//
for (int iIndex = 1; iIndex < pd.iNumberOfNames+1; iIndex++)
{
pd.pParticipantList[iIndex].sCryptPick = Crypt(pd.pParticipantList[pd.pParticipantList[iIndex].iThisYearsPick].sDrawMessage, pd.pParticipantList[iIndex].sPassPhrase);
if (iIndex == pd.iSanta)
{
pd.pParticipantList[iIndex].sCryptSSPick = pd.sCryptSecretSantaMsg;
}
else
{
pd.pParticipantList[iIndex].sCryptSSPick = Crypt(pd.pParticipantList[iIndex].sSantaMessage, pd.pParticipantList[iIndex].sPassPhrase);
}
}
//
// Write Top Part Of The Script.
//
StreamWriter fCryptJsLines = new StreamWriter(pd.sDataFolder + "\\crypt.js", false);
StreamReader fCryptJsTop = new StreamReader(pd.sDataFolder+"\\crypt_top.js");
string sCryptJsTopLine;
while(null != (sCryptJsTopLine = fCryptJsTop.ReadLine()))
{
fCryptJsLines.WriteLine(sCryptJsTopLine);
}
fCryptJsTop.Close();
//
// Write The Middle Part Of The Script
//
for (int iIndex = 1; iIndex < pd.iNumberOfNames; iIndex++)
{
fCryptJsLines.WriteLine(" '" + pd.pParticipantList[iIndex].sCryptPick + "',");
fCryptJsLines.WriteLine(" '" + pd.pParticipantList[iIndex].sCryptSSPick + "',");
}
fCryptJsLines.WriteLine(" '" + pd.pParticipantList[pd.iNumberOfNames].sCryptPick + "',");
fCryptJsLines.WriteLine(" '" + pd.pParticipantList[pd.iNumberOfNames].sCryptSSPick + "'");
//
// Write The Bottom Part Of The Script
//
StreamReader fCryptJsBottom = new StreamReader(pd.sDataFolder+"\\crypt_bottom.js");
string sCryptJsBottomLine;
while (null != (sCryptJsBottomLine = fCryptJsBottom.ReadLine()))
{
fCryptJsLines.WriteLine(sCryptJsBottomLine);
}
fCryptJsBottom.Close();
fCryptJsLines.Close();
return;
}
//
// Bring Up The Page That Uses The Crypt.JS
//
private void bViewPage_Click(object sender, EventArgs e)
{
string sPage = pd.sDataFolder + "\\index.html";
wbWindow.Navigate( new Uri(sPage));
}
}
}