package com.adamnickle.deck.Interfaces;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import com.adamnickle.deck.Game.Card;
import com.adamnickle.deck.Game.CardHolder;
import com.adamnickle.deck.Game.GameMessage;
import com.adamnickle.deck.GameActivity;
import java.io.File;
import java.io.InvalidClassException;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.concurrent.ArrayBlockingQueue;
import de.keyboardsurfer.android.widget.crouton.Style;
import ru.noties.debug.Debug;
public abstract class GameConnection implements ConnectionListener
{
public static final String MOCK_SERVER_ADDRESS = "mock_server_address";
public static final String MOCK_SERVER_NAME = "Server Host";
protected final ConnectionFragment mConnectionFragment;
protected final LinkedList<GameConnectionListener> mListeners;
private final ArrayBlockingQueue<GameMessage> mMessages;
private final MessageHandlingThread mMessageHandlingThread;
public GameConnection( ConnectionFragment connectionFragment )
{
mConnectionFragment = connectionFragment;
mListeners = new LinkedList< GameConnectionListener >();
mMessages = new ArrayBlockingQueue< GameMessage >( 10 );
mMessageHandlingThread = new MessageHandlingThread();
}
private class MessageHandlingThread extends Thread
{
private boolean mHandling = true;
@Override
public void run()
{
while( mHandling )
{
try
{
final GameMessage message = mMessages.take();
Debug.d( "HANDLING MESSAGE: " + message.getMessageType().name() );
final String originalSenderID = message.getOriginalSenderID();
final String receiverID = message.getReceiverID();
final GameConnectionListener listener = findAppropriateListener( message );
if( listener != null )
{
GameConnection.this.onMessageHandle( listener, originalSenderID, receiverID, message );
}
}
catch( InterruptedException e )
{
Debug.e( e );
}
}
}
public void cancel()
{
mHandling = false;
this.interrupt();
}
}
public void addGameConnectionListener( GameConnectionListener listener )
{
mListeners.addFirst( listener );
}
public GameConnectionListener findAppropriateListener( GameMessage message )
{
for( GameConnectionListener listener : mListeners )
{
if( listener.canHandleMessage( message ) )
{
return listener;
}
}
return null;
}
public boolean isServer()
{
return mConnectionFragment.getConnectionType() == ConnectionFragment.ConnectionType.SERVER;
}
public boolean isGameStarted()
{
return mConnectionFragment.getState() != ConnectionFragment.State.NONE;
}
public String getLocalPlayerID()
{
return mConnectionFragment.getLocalDeviceID();
}
public String getDefaultLocalPlayerName()
{
return mConnectionFragment.getLocalDeviceName();
}
public boolean isPlayerID( String ID )
{
return mConnectionFragment.isPlayerID( ID );
}
/*******************************************************************
* ConnectionListener Methods
*******************************************************************/
@Override
public final void onMessageReceive( String senderID, int bytes, byte[] allData )
{
final byte[] data = Arrays.copyOf( allData, bytes );
final GameMessage message;
try
{
message = GameMessage.deserializeMessage( data );
}
catch( InvalidClassException e )
{
if( !isServer() )
{
final Activity activity = mConnectionFragment.getActivity();
activity.setResult( GameActivity.RESULT_INVALID_VERSIONS, new Intent( GameActivity.class.getName() ) );
activity.finish();
}
return;
}
try
{
Debug.d( "RECEIVED MESSAGE: " + message.getMessageType().name() );
mMessages.put( message );
}
catch( InterruptedException e )
{
e.printStackTrace();
}
}
@Override
public void onMessageHandle( GameConnectionListener listener, String originalSenderID, String receiverID, GameMessage message )
{
switch( message.getMessageType() )
{
case MESSAGE_NEW_PLAYER:
{
listener.onCardHolderConnect( originalSenderID, message.getPlayerName() );
break;
}
case MESSAGE_SET_NAME:
{
final String newName = message.getPlayerName();
listener.onCardHolderNameReceive( originalSenderID, newName );
break;
}
case MESSAGE_PLAYER_LEFT:
{
listener.onCardHolderDisconnect( originalSenderID );
break;
}
case MESSAGE_RECEIVE_CARD:
{
final Card card = message.getCard();
listener.onCardReceive( originalSenderID, receiverID, card );
break;
}
case MESSAGE_RECEIVE_CARDS:
{
final Card[] cards = message.getCards();
listener.onCardsReceive( originalSenderID, receiverID, cards );
break;
}
case MESSAGE_CLEAR_CARDS:
{
listener.onClearCards( originalSenderID, receiverID );
break;
}
case MESSAGE_CARD_HOLDERS:
{
final CardHolder[] players = message.getCardHolders();
for( GameConnectionListener listener2 : mListeners )
{
listener2.onReceiveCardHolders( originalSenderID, receiverID, players );
}
break;
}
case MESSAGE_REMOVE_CARD:
{
final Card card = message.getCard();
listener.onCardRemove( originalSenderID, receiverID, card );
break;
}
case MESSAGE_REMOVE_CARDS:
{
final Card[] cards = message.getCards();
listener.onCardsRemove( originalSenderID, receiverID, cards );
break;
}
case MESSAGE_GAME_OPEN:
{
final Card[] cards = message.getCards();
listener.onGameOpen( originalSenderID, receiverID, cards );
break;
}
}
}
@Override
public void onNotification( String notification, Style style )
{
for( GameConnectionListener listener : mListeners )
{
listener.onNotification( notification, style );
}
}
@Override
public void onConnectionStarted()
{
for( GameConnectionListener listener : mListeners )
{
listener.onGameStarted();
}
}
@Override
public void onConnectionStateChange( ConnectionFragment.State newState )
{
if( newState == ConnectionFragment.State.NONE )
{
if( mMessageHandlingThread.isAlive() )
{
Debug.d( "THREAD CANCELLED" );
mMessageHandlingThread.cancel();
}
}
else
{
if( !mMessageHandlingThread.isAlive() )
{
Debug.d( "THREAD STARTED" );
try
{
mMessageHandlingThread.start();
}
catch( IllegalThreadStateException e )
{
Debug.d( "Thread already started." );
}
}
}
for( GameConnectionListener listener : mListeners )
{
listener.onConnectionStateChange( newState );
}
}
@Override
public void onConnectionFailed()
{
for( GameConnectionListener listener : mListeners )
{
listener.onNotification( "Could not connect.", Style.CONFIRM );
}
}
/*******************************************************************
* GameConnection Methods
*******************************************************************/
public abstract void startGame();
public abstract boolean saveGame( Context context, String saveName );
public abstract boolean openGameSave( Context context, File gameSave );
public abstract void sendMessageToDevice( GameMessage message, String senderID, String receiverID );
public void sendCard( String senderID, String receiverID, Card card, String removedFromID )
{
final GameMessage message = new GameMessage( GameMessage.MessageType.MESSAGE_RECEIVE_CARD, senderID, receiverID );
message.putCard( card );
message.putRemovedFromID( removedFromID );
this.sendMessageToDevice( message, senderID, receiverID );
}
public void sendCards( String senderID, String receiverID, Card[] cards )
{
final GameMessage message = new GameMessage( GameMessage.MessageType.MESSAGE_RECEIVE_CARDS, senderID, receiverID );
message.putCards( cards );
this.sendMessageToDevice( message, senderID, receiverID );
}
public void removeCard( String removerID, String removedFromID, Card card )
{
final GameMessage message = new GameMessage( GameMessage.MessageType.MESSAGE_REMOVE_CARD, removerID, removedFromID );
message.putCard( card );
this.sendMessageToDevice( message, removerID, removedFromID );
}
public void removeCards( String removerID, String removedFromID, Card[] cards )
{
final GameMessage message = new GameMessage( GameMessage.MessageType.MESSAGE_REMOVE_CARDS, removerID, removedFromID );
message.putCards( cards );
this.sendMessageToDevice( message, removerID, removedFromID );
}
public void clearCards( String commandingDeviceID, String toBeClearedDeviceID )
{
final GameMessage message = new GameMessage( GameMessage.MessageType.MESSAGE_CLEAR_CARDS, commandingDeviceID, toBeClearedDeviceID );
this.sendMessageToDevice( message, commandingDeviceID, toBeClearedDeviceID );
}
public void sendGameOpen( String senderID, String receiverID, Card[] cards )
{
final GameMessage message = new GameMessage( GameMessage.MessageType.MESSAGE_GAME_OPEN, senderID, receiverID );
message.putCards( cards );
this.sendMessageToDevice( message, senderID, receiverID );
}
public void sendCardHolderName( String senderID, String receiverID, String name )
{
final GameMessage message = new GameMessage( GameMessage.MessageType.MESSAGE_SET_NAME, senderID, receiverID );
message.putName( name );
this.sendMessageToDevice( message, senderID, receiverID );
}
public void sendCardHolders( String senderID, String receiverID, CardHolder[] cardHolders )
{
final GameMessage message = new GameMessage( GameMessage.MessageType.MESSAGE_CARD_HOLDERS, senderID, receiverID );
message.putCardHolders( cardHolders );
this.sendMessageToDevice( message, senderID, receiverID );
}
}