using RBG_Server;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
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;
namespace RBG_Server_WPF
{
///
/// Interaction logic for ConnectionPage.xaml
///
public partial class ConnectionPage : Page
{
public ConnectionPage()
{
InitializeComponent();
}
// ************************************************************
// ****************** Visibility Toggles **********************
// ************************************************************
#region visibility toggles
private void HostButton_Click(object sender, RoutedEventArgs e)
{
// Draw host window
ServerGrid.Visibility = Visibility.Visible;
ServerSelectPanel.Visibility = Visibility.Collapsed;
}
private void ConnectButton_Click(object sender, RoutedEventArgs e)
{
// Draw client window
ClientGrid.Visibility = Visibility.Visible;
ServerSelectPanel.Visibility = Visibility.Collapsed;
}
private void BackButton_Click(object sender, RoutedEventArgs e)
{
// Hide host view, show connect view
ServerGrid.Visibility = Visibility.Collapsed;
ServerSelectPanel.Visibility = Visibility.Visible;
}
private void ClientBackButton_Click(object sender, RoutedEventArgs e)
{
ClientGrid.Visibility = Visibility.Collapsed;
ServerSelectPanel.Visibility = Visibility.Visible;
}
#endregion
// ************************************************************
// *************** Client Connection Logic *******************
// ************************************************************
#region client connection logic
TcpClient client;
///
/// Connect to server buttonm runs an asynchronous task that attempts to connect to a server,
/// and load the thumbnails from the server
///
private void ClientServerConnectButton_Click(object sender, RoutedEventArgs e)
{
// Run an async connection task
// This task establishes a connection, then
Task clientConnect = new(async () =>
{
client = new();
try
{
await client.ConnectAsync(ServerAddressConnectBox.Text, int.Parse(ServerPortConnectBox.Text));
if (client.Connected)
{
// Invoke the display to update
Dispatcher.Invoke(() =>
{
StatusTextBlock.Text = "Connected!";
StatusTextBlock.Foreground = new SolidColorBrush(Color.FromRgb(255, 255, 255));
});
// Run image downloading for the sprite
// This task is contained in the CommunicationHandler class
Progress progress = new Progress();
Task t = App.Context.GameCommunicationHandler.InitDataLoader(client.GetStream(), progress);
progress.ProgressChanged += Progress_ProgressChanged;
t.Start(); // t is asynchronous; we don't need to monitor/await progress as it fires its progress through the assigned handler
// We should, however, ensure that we don't make requests on client until progress is completed (which can be monitored via
// the Progress object)
}
else
{
Dispatcher.Invoke(() =>
{
StatusTextBlock.Text = "Connection Failed";
StatusTextBlock.Foreground = new SolidColorBrush(Color.FromRgb(255, 0, 0));
});
}
}
catch (Exception ex)
{
Dispatcher.Invoke(() =>
{
StatusTextBlock.Text = ex.Message[..(128 < ex.Message.Length ? 128 : ex.Message.Length)];
StatusTextBlock.Foreground = new SolidColorBrush(Color.FromRgb(255, 0, 0));
});
client?.Dispose();
}
});
}
///
/// Progress callback, that responds to changes in the state of the task
///
///
///
///
private void Progress_ProgressChanged(object sender, CommunicationHandler.ProgressData e)
{
// Load iamges as they arrive
if (e.CurrentActivity == CommunicationHandler.ProgressData.Activity.ImageDownloaded)
{
// Show the user the total number of images downloaded
Dispatcher.Invoke(() => StatusTextBlock.Text = $"Downloaded {e.Progress} of {App.Context.GameCommunicationHandler.ImageList.Count} images.");
// Attempt to retrieve the image data
if(App.Context.GameCommunicationHandler.ImageCollection.TryGetValue(e.Message, out CachedByteArray cachedByteArray))
{
BitmapImage image = new();
image.BeginInit();
image.StreamSource = new MemoryStream(cachedByteArray, false);
image.EndInit();
if (e.Message == App.Context.GameCommunicationHandler.BoardName)
{
// Set the board image to `image`
_ = Dispatcher.Invoke(() => BoardPreviewImage.Source = image);
}
else
{
// Create a new image object
Image spriteImage = new()
{
Source = image
};
// Image is a sprite, load it
LoadedSpriteGrid loadedSprite = null;
foreach (LoadedSpriteGrid item in ClientLoadedSprites.Children)
{
// If the image already exists, replace the current image with the new one
if (item.Equals(e.Message))
{
loadedSprite = item;
// Set the image to the new loaded image
Dispatcher.Invoke(() => loadedSprite.FrameImage = spriteImage);
break;
}
}
if (loadedSprite == null)
{
loadedSprite = new LoadedSpriteGrid(spriteImage, e.Message);
// Listen to any selection event
loadedSprite.MouseDown += SpriteImage_Tapped;
loadedSprite.TouchDown += SpriteImage_Tapped;
loadedSprite.StylusDown += SpriteImage_Tapped;
// Add the loaded image into the view
Dispatcher.Invoke(() => ClientLoadedSprites.Children.Add(loadedSprite));
}
}
}
}
}
LoadedSpriteGrid currentlySelected = null;
private void SpriteImage_Tapped(object sender, InputEventArgs e)
{
currentlySelected.frame.BorderThickness = new Thickness(0, 0, 0, 0);
currentlySelected = sender as LoadedSpriteGrid;
currentlySelected.frame.BorderThickness = new Thickness(3, 3, 3, 3);
// Finally, enable the button
CheckEnableVis();
}
///
/// Every check required to enable the 'Join Server' button
///
private void CheckEnableVis()
{
if (currentlySelected != null && PlayerNameBox.Text != "" && client.Connected)
ClientStartGameButton.IsEnabled = true;
else
ClientStartGameButton.IsEnabled = false;
}
///
/// Layout that comprises of a Border containing an Image
///
internal class LoadedSpriteGrid : Grid
{
string imageName;
public Border frame;
public Image FrameImage { get; set; }
public LoadedSpriteGrid(Image spriteImage, string imageName)
{
FrameImage = spriteImage;
frame = new();
frame.Child = FrameImage;
frame.BorderThickness = new Thickness(0, 0, 0, 0);
frame.BorderBrush = new SolidColorBrush(Color.FromArgb(255, 0, 100, 200));
Children.Add(frame);
this.imageName = imageName;
}
///
/// Gets if the two grids are referencing the same image (regardless of the loaded mip level)
///
///
///
public new bool Equals(object obj)
{
if (obj == null || GetType() != obj.GetType())
{
return false;
}
string otherName = ((LoadedSpriteGrid)obj).imageName.Replace(App.MIP_LOW, "").Replace(App.MIP_MEDIUM, "").Replace(App.MIP_HIGH, "").Replace(App.MIP_RAW, "");
string tName = imageName.Replace(App.MIP_LOW, "").Replace(App.MIP_MEDIUM, "").Replace(App.MIP_HIGH, "").Replace(App.MIP_RAW, "");
return tName.Equals(otherName);
}
}
private void PlayerNameBox_LostFocus(object sender, RoutedEventArgs e)
{
CheckEnableVis();
}
#endregion
// ************************************************************
// *************** Server Connection Logic *******************
// ************************************************************
#region server connection logic
#endregion
}
}