From 786f765f05b560e14099b31a778a83b9f27b4979 Mon Sep 17 00:00:00 2001
From: Starbeamrainbowlabs <sbrl@starbeamrainbowlabs.com>
Date: Thu, 9 Feb 2017 22:24:17 +0000
Subject: [PATCH] We're almsot there~\!

---
 ...StateMessage.cs => ClientStatesMessage.cs} |   4 +-
 Nibriboard/Client/NibriClient.cs              |   7 +-
 Nibriboard/ClientFiles/CursorSyncer.js        |   2 +
 Nibriboard/Nibriboard.csproj                  |   4 +-
 Nibriboard/Utilities/ColourHSL.cs             | 168 ++++++++++++++++++
 Nibriboard/Utilities/ToStringJsonConverter.cs |  38 ++++
 6 files changed, 217 insertions(+), 6 deletions(-)
 rename Nibriboard/Client/Messages/{ClientStateMessage.cs => ClientStatesMessage.cs} (79%)
 create mode 100644 Nibriboard/Utilities/ColourHSL.cs
 create mode 100644 Nibriboard/Utilities/ToStringJsonConverter.cs

diff --git a/Nibriboard/Client/Messages/ClientStateMessage.cs b/Nibriboard/Client/Messages/ClientStatesMessage.cs
similarity index 79%
rename from Nibriboard/Client/Messages/ClientStateMessage.cs
rename to Nibriboard/Client/Messages/ClientStatesMessage.cs
index 6a15a63..c1457ad 100644
--- a/Nibriboard/Client/Messages/ClientStateMessage.cs
+++ b/Nibriboard/Client/Messages/ClientStatesMessage.cs
@@ -8,11 +8,11 @@ namespace Nibriboard.Client.Messages
 	/// <summary>
 	/// Represents an update of where a group of connected clients are.
 	/// </summary>
-	public class ClientStateMessage : Message
+	public class ClientStatesMessage : Message
 	{
 		public List<ClientState> ClientStates = new List<ClientState>();
 
-		public ClientStateMessage()
+		public ClientStatesMessage()
 		{
 		}
 	}
diff --git a/Nibriboard/Client/NibriClient.cs b/Nibriboard/Client/NibriClient.cs
index 8e53ca5..20ff5c7 100644
--- a/Nibriboard/Client/NibriClient.cs
+++ b/Nibriboard/Client/NibriClient.cs
@@ -185,7 +185,8 @@ namespace Nibriboard.Client
 			AbsoluteCursorPosition = message.AbsCursorPosition;
 
 			// Send the update to the other clients
-			ClientStateMessage updateMessage = new ClientStateMessage();
+			// TODO: Buffer these updates and send them about 5 times a second
+			ClientStatesMessage updateMessage = new ClientStatesMessage();
 			updateMessage.ClientStates.Add(this.GenerateStateSnapshot());
 			manager.Broadcast(this, updateMessage);
 
@@ -198,9 +199,9 @@ namespace Nibriboard.Client
 		/// Automatically omits information about the current client.
 		/// </summary>
 		/// <returns>The client state update message.</returns>
-		protected ClientStateMessage GenerateClientStateUpdate()
+		protected ClientStatesMessage GenerateClientStateUpdate()
 		{
-			ClientStateMessage result = new ClientStateMessage();
+			ClientStatesMessage result = new ClientStatesMessage();
 			foreach (NibriClient client in manager.Clients)
 			{
 				// Don't include ourselves in the update message!
diff --git a/Nibriboard/ClientFiles/CursorSyncer.js b/Nibriboard/ClientFiles/CursorSyncer.js
index 4ceea18..9e125c5 100644
--- a/Nibriboard/ClientFiles/CursorSyncer.js
+++ b/Nibriboard/ClientFiles/CursorSyncer.js
@@ -9,6 +9,8 @@ class CursorSyncer
 		// The target frequency in fps at we should send sursor updates.
 		this.cursorUpdateFrequency = syncFrequency;
 		
+		this.otherClients = [];
+		
 		// Register ourselves to start sending cursor updates once the ripple
 		// link connects
 		this.rippleLink.on("connect", this.setup.bind(this));
diff --git a/Nibriboard/Nibriboard.csproj b/Nibriboard/Nibriboard.csproj
index 7535247..571d2fb 100644
--- a/Nibriboard/Nibriboard.csproj
+++ b/Nibriboard/Nibriboard.csproj
@@ -75,10 +75,12 @@
     <Compile Include="Client\Messages\Message.cs" />
     <Compile Include="Client\Messages\HandshakeRequestMessage.cs" />
     <Compile Include="Client\Messages\CursorPositionMessage.cs" />
-    <Compile Include="Client\Messages\ClientStateMessage.cs" />
     <Compile Include="RippleSpace\ClientState.cs" />
     <Compile Include="Utilities\Rectangle.cs" />
     <Compile Include="Utilities\Vector2.cs" />
+    <Compile Include="Client\Messages\ClientStatesMessage.cs" />
+    <Compile Include="Utilities\ColourHSL.cs" />
+    <Compile Include="Utilities\ToStringJsonConverter.cs" />
   </ItemGroup>
   <ItemGroup>
     <EmbeddedResource Include="ClientFiles\index.html" />
diff --git a/Nibriboard/Utilities/ColourHSL.cs b/Nibriboard/Utilities/ColourHSL.cs
new file mode 100644
index 0000000..d6fd33c
--- /dev/null
+++ b/Nibriboard/Utilities/ColourHSL.cs
@@ -0,0 +1,168 @@
+﻿using System;
+
+namespace SBRL.Utilities
+{
+	class ColourHSL 
+	{
+		/// <summary>
+		/// A random number generator.Used to generate random colours in RandomSaturated().
+		/// </summary>
+		private static Random random = new Random();
+
+		#region Properties
+
+		/// <summary>
+		/// The hue of the colour, between 0 and 360.
+		/// </summary>
+		public float Hue { get; set; }
+		/// <summary>
+		/// The saturation of the colour, between 0 and 100.
+		/// </summary>
+		public float Saturation { get; set; }
+		/// <summary>
+		/// The lightness of the colour, between 0 and 100.
+		/// </summary>
+		public float Lightness { get; set; }
+		/// <summary>
+		/// The opacity of the colour, between 0 and 1.
+		/// </summary>
+		public float Alpha { get; set; }
+
+		#endregion
+
+		#region Aliases
+
+		/// <summary>
+		/// Alias of Hue.
+		/// </summary>
+		public float H {
+			get { return Hue; }
+			set { Hue = value; }
+		}
+		/// <summary>
+		/// Alias of Saturation.
+		/// </summary>
+		public float S {
+			get { return Saturation; }
+			set { Saturation = value; }
+		}
+		/// <summary>
+		/// Alias of Lightness.
+		/// </summary>
+		public float L {
+			get { return Lightness; }
+			set { Lightness = value; }
+		}
+		/// <summary>
+		/// Alias of Alpha.
+		/// </summary>
+		public float A {
+			get { return Alpha; }
+			set { Alpha = value; }
+		}
+
+		#endregion
+
+		/// <summary>
+		/// Whether this colour is opaque or not.
+		/// </summary>
+		public bool IsOpaque {
+			get {
+				return Alpha == 1;
+			}
+		}
+
+		/// <summary>
+		/// Whether this colour is translucent or not.
+		/// </summary>
+		public bool IsTranslucent {
+			get {
+				return !IsOpaque && !IsTransparent;
+			}
+		}
+
+		/// <summary>
+		/// Whether this colour is completely transparent or not.
+		/// </summary>
+		public bool IsTransparent {
+			get {
+				return Alpha == 0;
+			}
+		}
+
+		/// <summary>
+		/// Whether this colour is currently valid or not. A valid colour has a hue of 0-360,
+		/// a saturation of 0-100, a lightness of 0-100, and an opacity of 0-1.
+		/// </summary>
+		public bool IsValidColour
+		{
+			get {
+				return Hue >= 0 && Hue <= 360 &&
+					Saturation >= 0 && Saturation <= 100 &&
+					Lightness >= 0 && Lightness <= 100 &&
+					Alpha >= 0 && Alpha <= 1;
+			}
+		}
+
+		/// <summary>
+		/// Initializes a new ColourHSL instance, with the colour set to bright white.
+		/// </summary>
+		public ColourHSL() : this(0, 100, 100, 1)
+		{
+		}
+		/// <summary>
+		/// Initializes a new <see cref="SBRL.Utilities.ColourHSL"/>  class instance.
+		/// </summary>
+		/// <param name="inHue">The hue of the colour.</param>
+		/// <param name="inSaturation">The saturation of the colour.</param>
+		/// <param name="inLightness">The lightness of the colour.</param>
+		public ColourHSL(float inHue, float inSaturation, float inLightness) : this(inHue, inSaturation, inLightness, 1)
+		{
+		}
+		/// <summary>
+		/// Initializes a new <see cref="SBRL.Utilities.ColourHSL"/>  class instance.
+		/// </summary>
+		/// <param name="inHue">The hue of the colour.</param>
+		/// <param name="inSaturation">The saturation of the colour.</param>
+		/// <param name="inLightness">The lightness of the colour.</param>
+		/// <param name="inAlpha">The opacity of the colour.</param>
+		public ColourHSL(float inHue, float inSaturation, float inLightness, float inAlpha)
+		{
+			Hue = inHue;
+			Saturation = inSaturation;
+			Lightness = inLightness;
+			Alpha = inAlpha;
+		}
+
+		/// <summary>
+		/// Returns a random bright colour.
+		/// </summary>
+		public static ColourHSL RandomSaturated()
+		{
+			ColourHSL result = new ColourHSL() {
+				Hue = random.Next(0, 360),
+				Lightness = random.Next(45, 55),
+				Saturation = random.Next(90, 100)
+			};
+		}
+
+		#region Overrides
+
+		/// <summary>
+		/// Returns a <see cref="string"/> that represents this <see cref="SBRL.Utilities.ColourHSL"/> instance.
+		/// </summary>
+		/// <returns>A <see cref="string"/> that represents this <see cref="SBRL.Utilities.ColourHSL"/> instance.</returns>
+		public override string ToString()
+		{
+			string format = string.Empty;
+			if (IsOpaque)
+				format = "hsl({0}, {1}%, {2}%)";
+			else
+				format = "hsla({0}, {1}%, {2}%, {3})";
+			
+			return string.Format(format, Hue, Saturation, Lightness, Math.Round(Alpha, 3));
+		}
+
+		#endregion
+	}
+}
\ No newline at end of file
diff --git a/Nibriboard/Utilities/ToStringJsonConverter.cs b/Nibriboard/Utilities/ToStringJsonConverter.cs
new file mode 100644
index 0000000..16f0049
--- /dev/null
+++ b/Nibriboard/Utilities/ToStringJsonConverter.cs
@@ -0,0 +1,38 @@
+﻿using System;
+
+using Newtonsoft.Json;
+
+/// <summary>
+/// Contains a number classes that I (SBRL) have found on the internet.
+/// While they have usually been adapted from one form or another, full credit is always given.
+/// </summary>
+namespace SBRL.Utilities.Solutions
+{
+	/// <summary>
+	/// A JsonConverter that converts properties to a string via their inbuilt ToString() method.
+	/// From http://stackoverflow.com/a/22355712/1460422 by 
+	/// </summary>
+	class ToStringJsonConverter : JsonConverter
+	{
+		public override bool CanConvert(Type objectType)
+		{
+			return true;
+		}
+
+		public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
+		{
+			writer.WriteValue(value.ToString());
+		}
+
+		public override bool CanRead
+		{
+			get { return false; }
+		}
+
+		public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
+		{
+			throw new NotImplementedException();
+		}
+	}
+}
+
