2022-08-30 15:00:58 +00:00
using SharpChat.Packet ;
using System ;
using System.Collections.Generic ;
using System.Linq ;
namespace SharpChat {
public class ChannelException : Exception { }
public class ChannelExistException : ChannelException { }
public class ChannelInvalidNameException : ChannelException { }
public class ChannelManager : IDisposable {
2023-02-07 15:01:56 +00:00
private readonly List < ChatChannel > Channels = new ( ) ;
2022-08-30 15:00:58 +00:00
public readonly ChatContext Context ;
public bool IsDisposed { get ; private set ; }
public ChannelManager ( ChatContext context ) {
Context = context ;
}
private ChatChannel _DefaultChannel ;
public ChatChannel DefaultChannel {
get {
2023-02-07 15:01:56 +00:00
if ( _DefaultChannel = = null )
2022-08-30 15:00:58 +00:00
_DefaultChannel = Channels . FirstOrDefault ( ) ;
return _DefaultChannel ;
}
set {
2023-02-07 15:01:56 +00:00
if ( value = = null )
2022-08-30 15:00:58 +00:00
return ;
2023-02-07 15:01:56 +00:00
if ( Channels . Contains ( value ) )
2022-08-30 15:00:58 +00:00
_DefaultChannel = value ;
}
}
public void Add ( ChatChannel channel ) {
2023-02-07 15:01:56 +00:00
if ( channel = = null )
2022-08-30 15:00:58 +00:00
throw new ArgumentNullException ( nameof ( channel ) ) ;
2023-02-07 15:01:56 +00:00
if ( ! channel . Name . All ( c = > char . IsLetter ( c ) | | char . IsNumber ( c ) | | c = = '-' ) )
2022-08-30 15:00:58 +00:00
throw new ChannelInvalidNameException ( ) ;
2023-02-07 15:01:56 +00:00
if ( Get ( channel . Name ) ! = null )
2022-08-30 15:00:58 +00:00
throw new ChannelExistException ( ) ;
// Add channel to the listing
Channels . Add ( channel ) ;
// Set as default if there's none yet
2023-02-07 15:01:56 +00:00
if ( _DefaultChannel = = null )
2022-08-30 15:00:58 +00:00
_DefaultChannel = channel ;
// Broadcast creation of channel
2023-02-07 15:01:56 +00:00
foreach ( ChatUser user in Context . Users . OfHierarchy ( channel . Rank ) )
2022-08-30 15:00:58 +00:00
user . Send ( new ChannelCreatePacket ( channel ) ) ;
}
public void Remove ( ChatChannel channel ) {
2023-02-07 15:01:56 +00:00
if ( channel = = null | | channel = = DefaultChannel )
2022-08-30 15:00:58 +00:00
return ;
// Remove channel from the listing
Channels . Remove ( channel ) ;
// Move all users back to the main channel
// TODO: Replace this with a kick. SCv2 supports being in 0 channels, SCv1 should force the user back to DefaultChannel.
2023-02-07 15:01:56 +00:00
foreach ( ChatUser user in channel . GetUsers ( ) ) {
2022-08-30 15:00:58 +00:00
Context . SwitchChannel ( user , DefaultChannel , string . Empty ) ;
}
// Broadcast deletion of channel
2023-02-07 15:01:56 +00:00
foreach ( ChatUser user in Context . Users . OfHierarchy ( channel . Rank ) )
2022-08-30 15:00:58 +00:00
user . Send ( new ChannelDeletePacket ( channel ) ) ;
}
public bool Contains ( ChatChannel chan ) {
2023-02-07 15:01:56 +00:00
if ( chan = = null )
2022-08-30 15:00:58 +00:00
return false ;
2023-02-07 15:01:56 +00:00
lock ( Channels )
2022-08-30 15:00:58 +00:00
return Channels . Contains ( chan ) | | Channels . Any ( c = > c . Name . ToLowerInvariant ( ) = = chan . Name . ToLowerInvariant ( ) ) ;
}
public void Update ( ChatChannel channel , string name = null , bool? temporary = null , int? hierarchy = null , string password = null ) {
2023-02-07 15:01:56 +00:00
if ( channel = = null )
2022-08-30 15:00:58 +00:00
throw new ArgumentNullException ( nameof ( channel ) ) ;
2023-02-07 15:01:56 +00:00
if ( ! Channels . Contains ( channel ) )
2022-08-30 15:00:58 +00:00
throw new ArgumentException ( @"Provided channel is not registered with this manager." , nameof ( channel ) ) ;
string prevName = channel . Name ;
int prevHierarchy = channel . Rank ;
bool nameUpdated = ! string . IsNullOrWhiteSpace ( name ) & & name ! = prevName ;
2023-02-07 15:01:56 +00:00
if ( nameUpdated ) {
if ( ! name . All ( c = > char . IsLetter ( c ) | | char . IsNumber ( c ) | | c = = '-' ) )
2022-08-30 15:00:58 +00:00
throw new ChannelInvalidNameException ( ) ;
2023-02-07 15:01:56 +00:00
if ( Get ( name ) ! = null )
2022-08-30 15:00:58 +00:00
throw new ChannelExistException ( ) ;
channel . Name = name ;
}
2023-02-07 15:01:56 +00:00
if ( temporary . HasValue )
2022-08-30 15:00:58 +00:00
channel . IsTemporary = temporary . Value ;
2023-02-07 15:01:56 +00:00
if ( hierarchy . HasValue )
2022-08-30 15:00:58 +00:00
channel . Rank = hierarchy . Value ;
2023-02-07 15:01:56 +00:00
if ( password ! = null )
2022-08-30 15:00:58 +00:00
channel . Password = password ;
// Users that no longer have access to the channel/gained access to the channel by the hierarchy change should receive delete and create packets respectively
2023-02-07 15:01:56 +00:00
foreach ( ChatUser user in Context . Users . OfHierarchy ( channel . Rank ) ) {
2022-08-30 15:00:58 +00:00
user . Send ( new ChannelUpdatePacket ( prevName , channel ) ) ;
2023-02-07 15:01:56 +00:00
if ( nameUpdated )
2022-08-30 15:00:58 +00:00
user . ForceChannel ( ) ;
}
}
public ChatChannel Get ( string name ) {
2023-02-07 15:01:56 +00:00
if ( string . IsNullOrWhiteSpace ( name ) )
2022-08-30 15:00:58 +00:00
return null ;
return Channels . FirstOrDefault ( x = > x . Name . ToLowerInvariant ( ) = = name . ToLowerInvariant ( ) ) ;
}
public IEnumerable < ChatChannel > GetUser ( ChatUser user ) {
2023-02-07 15:01:56 +00:00
if ( user = = null )
2022-08-30 15:00:58 +00:00
return null ;
return Channels . Where ( x = > x . HasUser ( user ) ) ;
}
public IEnumerable < ChatChannel > OfHierarchy ( int hierarchy ) {
2023-02-07 15:01:56 +00:00
lock ( Channels )
2022-08-30 15:00:58 +00:00
return Channels . Where ( c = > c . Rank < = hierarchy ) . ToList ( ) ;
}
2023-02-07 15:01:56 +00:00
~ ChannelManager ( ) {
DoDispose ( ) ;
}
2022-08-30 15:00:58 +00:00
2023-02-07 15:01:56 +00:00
public void Dispose ( ) {
DoDispose ( ) ;
GC . SuppressFinalize ( this ) ;
}
2022-08-30 15:00:58 +00:00
2023-02-07 15:01:56 +00:00
private void DoDispose ( ) {
if ( IsDisposed )
2022-08-30 15:00:58 +00:00
return ;
IsDisposed = true ;
Channels . Clear ( ) ;
}
}
}