//
//  SFSRoom.m
//  SFS2X
//
//  Original development by Infosfer Game Technologies Ltd. | http://www.infosfer.com.
//
//  Maintained and developed by A51 Integrated.
//  Copyright 2012 A51 Integrated | http://a51integrated.com. All rights reserved.
//

#import "SFSRoom.h"
#import "ISFSArray.h"
#import "RoomVariable.h"
#import "SFSUserManager.h"
#import "SFSRoomVariable.h"
#import "ArrayUtil.h"
#import "SFSException.h"
#import "MMORoom.h"

@implementation SFSRoom

@dynamic id;
@dynamic name;
@dynamic groupId;
@dynamic isJoined;
@dynamic isGame;
@dynamic isHidden;
@dynamic isPasswordProtected;
@dynamic isManaged;
@dynamic maxUsers;
@dynamic maxSpectators;
@dynamic userCount;
@dynamic spectatorCount;
@dynamic properties;
@dynamic roomManager;
@dynamic capacity;
@dynamic playerList;
@dynamic userList;
@dynamic spectatorList;



-(id)initWithId:(NSInteger)id name:(NSString *)name groupId:(NSString *)groupId {

	if ((self = [super init])) {
		_id = id;
		self.name = name;
		_groupId = groupId;
		_isJoined = NO;
		_isGame = NO;
		_isHidden = NO;
		_isManaged = YES;
		
		_userCount = 0;
		_spectatorCount = 0;
		
		_variables = [NSMutableDictionary dictionary];
		_properties = [NSDictionary dictionary];
		_userManager = [[SFSUserManager alloc] initWithSfs:nil];
	}
	
	return self;
}

+(id <Room>)fromSFSArray:(id <ISFSArray>)sfsa
{
    BOOL isMMORoom = [sfsa size] == 14;
    id <Room> newRoom;
    
    if (isMMORoom)
    {
        newRoom = [[MMORoom alloc] initWithId:[sfsa getInt:0]
                                         name:[sfsa getUtfString:1]
                                      groupId:[sfsa getUtfString:2]];
    }
    else
    {
        newRoom = [[SFSRoom alloc] initWithId:[sfsa getInt:0]
                                         name:[sfsa getUtfString:1]
                                      groupId:[sfsa getUtfString:2]];
    }
    
	[newRoom setIsGame:[sfsa getBool:3]];
	[newRoom setIsHidden:[sfsa getBool:4]];
	[newRoom setIsPasswordProtected:[sfsa getBool:5]];
	[newRoom setUserCount:[sfsa getShort:6]];
	[newRoom setMaxUsers:[sfsa getShort:7]];
	
	
	id <ISFSArray> varsList = [sfsa getSFSArray:8];
	
	if ([varsList size] > 0)
    {
		NSMutableArray *vars = [NSMutableArray array];
		
		for (int j = 0; j < [varsList size]; j++) {
			id <RoomVariable> roomVariable = [SFSRoomVariable fromSFSArray:[varsList getSFSArray:j]];
			[vars addObject:roomVariable];
		}
		[newRoom setVariables:vars];
	}
	
	if ([newRoom isGame])
    {
		
		[newRoom setSpectatorCount:[sfsa getShort:9]];
		[newRoom setMaxSpectators:[sfsa getShort:10]];
		
	}
    
    if (isMMORoom)
    {
        MMORoom* mmoRoom = (MMORoom*) newRoom;
        mmoRoom.defaultAOI = [Vec3D fromArray:[sfsa getElementAt:11]];
        
        // Check if map limits are non null
        if (![sfsa isNull:13])
        {
            mmoRoom.lowerMapLimit = [Vec3D fromArray:[sfsa getElementAt:12]];
            mmoRoom.higherMapLimit = [Vec3D fromArray:[sfsa getElementAt:13]];
        }
    }
	
	return newRoom;
}


#pragma mark -
#pragma mark Room protocol  

-(NSInteger)id {
	return _id;
}

-(NSString *)name {
	return _name;
}
-(void)setName:(NSString *)value {
	_name = value;
}

-(NSString *)groupId {
	return _groupId;
}

-(BOOL)isJoined {
	return _isJoined;
}
-(void)setIsJoined:(BOOL)value {
	_isJoined = value;
}

-(BOOL)isGame {
	return _isGame;
}
-(void)setIsGame:(BOOL)value {
	_isGame = value;
}

-(BOOL)isHidden {
	return _isHidden;
}
-(void)setIsHidden:(BOOL)value {
	_isHidden = value;
}

-(BOOL)isPasswordProtected {
	return _isPasswordProtected;
}
-(void)setIsPasswordProtected:(BOOL)value {
	_isPasswordProtected = value;
}

-(BOOL)isManaged {
	return _isManaged;
}
-(void)setIsManaged:(BOOL)value {
	_isManaged = value;
}

-(NSInteger)userCount
{
	if (!_isJoined)
    {
		return _userCount;
	}
	else
    {
        if(_isGame)
        {
            return [[self playerList] count];
        }
        else
        {
            return [_userManager userCount];
        }
	}
}

-(void)setUserCount:(NSInteger)value {
	_userCount = value;
}

-(NSInteger)maxUsers {
	return _maxUsers;
}
-(void)setMaxUsers:(NSInteger)value {
	_maxUsers = value;
}

-(NSInteger)spectatorCount
{
    if(!_isGame)
    {
        return 0;
    }
    
	if (_isJoined)
    {
		return [[self spectatorList] count];
	}
	else
    {
		return _spectatorCount;
	}
}


-(void)setSpectatorCount:(NSInteger)value {
	_spectatorCount = value;
}

-(NSInteger)maxSpectators {
	return _maxSpectators;
}

-(void)setMaxSpectators:(NSInteger)value {
	_maxSpectators = value;
}

-(void)addUser:(id <User>)user {
	[_userManager addUser:user];
}

-(void)removeUser:(id <User>)user {
	[_userManager removeUser:user];
}

-(BOOL)containsUser:(id <User>)user {
	return [_userManager containsUser:user];
}

-(id <User>)getUserByName:(NSString *)name {
	return [_userManager getUserByName:name];
}

-(id <User>)getUserById:(NSInteger)id {
	return [_userManager getUserById:id];
}

-(NSArray *)userList {
	return [_userManager getUserList];
}
-(NSArray *)playerList
{
	NSMutableArray *playerList = [NSMutableArray array];
	
	for (id user in [_userManager getUserList])
    {
		if ([user conformsToProtocol:@protocol(User)])
        {
			if ([(id <User>)user isPlayerInRoom:self])
				[playerList addObject:user];
		}
	}
	
	return playerList;
}

-(NSArray *)spectatorList
{
	NSMutableArray *spectatorList = [NSMutableArray array];
	
	for (id user in [_userManager getUserList])
    {
		if ([user conformsToProtocol:@protocol(User)])
        {
			if ([(id <User>)user isSpectatorInRoom:self])
				[spectatorList addObject:user];
		}
	}
	
	return spectatorList;
}

-(id <RoomVariable>)getVariable:(NSString *)name
{
    @synchronized (_variables)
    {
        return [_variables objectForKey:name];
    }
}

-(NSArray *)getVariables
{
    @synchronized (_variables)
    {
         return [ArrayUtil objToArray:_variables];
    }
}

-(void)setVariable:(id <RoomVariable>)roomVariable
{
    @synchronized (_variables)
    {
        if ([roomVariable isNull])
            [_variables removeObjectForKey:[roomVariable name]];
        
        else
            [_variables setObject:roomVariable forKey:[roomVariable name]];
    }

}

-(void)setVariables:(NSArray *)roomVariables
{
	
	for (id roomVar in roomVariables)
    {
		if ([roomVar conformsToProtocol:@protocol(RoomVariable)])
			[self setVariable:roomVar];
	}
	
}

-(BOOL)containsVariable:(NSString *)name
{
    @synchronized (_variables)
    {
        return [_variables objectForKey:name] != nil;
    }
}

-(NSDictionary *)properties {
	return _properties;
}
-(void)setProperties:(NSDictionary *)value {
	_properties = value;
}

-(id <IRoomManager>)roomManager {
	return _roomManager;
}
-(void)setRoomManager:(id <IRoomManager>)manager {
	if (_roomManager != nil) {
		@throw [SFSException exceptionWithReason:[NSString stringWithFormat:@"Room manager already assigned. Room: %ld", (long)_id]];
	}
	
	_roomManager = manager;
}

-(NSInteger)capacity {
	return _maxUsers + _maxSpectators;
}

-(void)setPasswordProtected:(BOOL)isProtected {
	_isPasswordProtected = isProtected;
}

-(NSString *)description {
	return [NSString stringWithFormat:@"[Room: %@, Id: %ld, GroupId: %@]", _name, (long)_id, _groupId];
}

-(void)merge:(id<Room>)anotherRoom;
{
    /*
     * If the Room was already joined it should be up to date to the latest changes
     * both in terms of users and Room variables.
     *
     * When the Room is not joined instead we reset the User and RoomVar list and rebuild it with the new data
     */
    
    if (![self isJoined])
    {
        //[self setProperties:[anotherRoom properties]];
        
        @synchronized (_variables)
        {
            // Clear all vars
            [_variables removeAllObjects];
            
            // Copy variables
            for (id roomVar in [anotherRoom getVariables])
            {
                if ([roomVar conformsToProtocol:@protocol(RoomVariable)])
                    [self setVariable:roomVar];
            }
            
            // Delegate copying users
            [_userManager replaceAll:[anotherRoom userList]];
        }
    }
}

#pragma mark -

@end
