public class MIDIConnectionEndEvent {
    public final Bundle rinfo;

    public MIDIConnectionEndEvent(Bundle b) {
        rinfo = b;
    }

} public class MIDIConnectionRequestReceivedEvent {
    public final Bundle rinfo;

    public MIDIConnectionRequestReceivedEvent(final Bundle r) {
        rinfo = r;
    }

} public class MIDIConnectionRequestRejectedEvent {
    public final Bundle rinfo;

    public MIDIConnectionRequestRejectedEvent(final Bundle r) {
        rinfo = r;
    }

} public class MIDIConnectionSentRequestEvent {

    public final Bundle rinfo;

    public MIDIConnectionSentRequestEvent(final Bundle r) {
        rinfo = r;
    }
} public class ConnectionEstablishedEvent {
    public final Bundle rinfo;

    public ConnectionEstablishedEvent(final Bundle r) {
        rinfo = r;
    }
} public class ConnectionFailedEvent {
    public final Bundle rinfo;
    public final MIDIFailCode code;
    public final int initiator_code;

    public ConnectionFailedEvent(final MIDIFailCode c, final Bundle r) {
        code = c;
        rinfo = r;
        initiator_code = 0;
    }

    public ConnectionFailedEvent(final MIDIFailCode c, final Bundle r, final int i) {
        code = c;
        rinfo = r;
        initiator_code = i;
    }
} public class StreamConnectedEvent {

    public int initiator_token;

    public StreamConnectedEvent(int token) {
        initiator_token = token;
    }
} public class StreamDisconnectEvent {

    public final int stream_ssrc;
    public final int initiator_token;
    public final Bundle rinfo;

    public StreamDisconnectEvent(int ssrc) {
        stream_ssrc = ssrc;
        initiator_token = 0;
        rinfo = null;
    }
    public StreamDisconnectEvent(int ssrc, int token) {
        stream_ssrc = ssrc;
        initiator_token = token;
        rinfo = null;
    }
    public StreamDisconnectEvent(int ssrc, Bundle b) {
        stream_ssrc = ssrc;
        initiator_token = 0;
        rinfo = b;
    }
    public StreamDisconnectEvent(int ssrc, int token, Bundle b) {
        stream_ssrc = ssrc;
        initiator_token = token;
        rinfo = b;
    }

} public class SyncronizeStartedEvent {

    public final Bundle rinfo;

    public SyncronizeStartedEvent(final Bundle r) {
        rinfo = r;
    }

} public class SyncronizeStoppedEvent {
    public final Bundle rinfo;

    public SyncronizeStoppedEvent(final Bundle r) {
        rinfo = r;
    }

} public static final String RINFO_FAIL = "failed";
import android.os.Bundle;
import android.util.Log;
import com.disappointedpig.midi.events.MIDIConnectionEndEvent;
import com.disappointedpig.midi.events.MIDIConnectionRequestReceivedEvent;
import com.disappointedpig.midi.events.MIDIConnectionRequestRejectedEvent;
import com.disappointedpig.midi.events.MIDIConnectionSentRequestEvent;
import com.disappointedpig.midi.internal_events.ConnectionEstablishedEvent;
import com.disappointedpig.midi.internal_events.ConnectionFailedEvent;
import com.disappointedpig.midi.internal_events.StreamConnectedEvent;
import com.disappointedpig.midi.internal_events.StreamDisconnectEvent;
import com.disappointedpig.midi.internal_events.SyncronizeStartedEvent;
import com.disappointedpig.midi.internal_events.SyncronizeStoppedEvent;
import org.greenrobot.eventbus.EventBus;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import static com.disappointedpig.midi.MIDIConstants.RINFO_FAIL;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.MINUTES;
import static java.util.concurrent.TimeUnit.SECONDS;
            default:
//                Log.d("MIDIStream", "unhandled command");
                break;
        }
    }



    private void handleInvitation(MIDIControl control, Bundle rinfo) {
        if(rinfo1 == null) {
            rinfo1 = (Bundle) rinfo.clone();
            this.initiator_token = control.initiator_token;
            this.name = control.name;
            this.ssrc = control.ssrc;
            rinfo1.putString(com.disappointedpig.midi.MIDIConstants.RINFO_NAME, control.name);
            EventBus.getDefault().post(new MIDIConnectionRequestReceivedEvent(rinfo1));
        } else if(rinfo.getInt(com.disappointedpig.midi.MIDIConstants.RINFO_PORT) == rinfo1.getInt(com.disappointedpig.midi.MIDIConstants.RINFO_PORT)) {
            return;
        } else if(rinfo2 == null) {
            rinfo2 = (Bundle) rinfo.clone();
            this.isConnected = true;

        } else {
            return;
        }

// this needs work...
        if(MIDISession.getInstance().isHostConnectionAllowed(rinfo)) {
            this.sendInvitationAccepted(rinfo);
        } else {
            this.sendInvitationRejected(rinfo);
        }
    }

    private void handleInvitationAccepted(MIDIControl control, Bundle rinfo) {
        Log.d(TAG,"handleInvitationAccepted "+rinfo.toString());
        if (!this.isConnected && this.rinfo1 == null) {
            Log.d(TAG,"cancel connectFuture");
            connectFuture.cancel(true);
            Log.d(TAG,"set rinfo1 "+rinfo.toString());
            rinfo1 = (Bundle) rinfo.clone();
            rinfo1.putString(com.disappointedpig.midi.MIDIConstants.RINFO_NAME,control.name);
            rinfo.putInt(com.disappointedpig.midi.MIDIConstants.RINFO_PORT,rinfo.getInt(com.disappointedpig.midi.MIDIConstants.RINFO_PORT)+1);
            connectTaskCount = 0;
            connect(rinfo);
        } else if(!this.isConnected && rinfo2 == null) {
            Log.d(TAG,"cancel connectFuture");
            connectFuture.cancel(true);
            connectTaskCount = 0;

            this.isConnected = true;
            this.name = control.name;
            this.ssrc = control.ssrc;
            Log.d(TAG,"set rinfo2 "+rinfo.toString());
            rinfo2 = (Bundle) rinfo.clone();
            EventBus.getDefault().post(new StreamConnectedEvent(this.initiator_token));
            resetSyncService(syncServicePrimaryFrequency);
        } else {
            Log.d("MIDI2Stream","unhandled invitation accept");
        }
    }

    private void resetCheckConnectionService() {
        if(checkConnectionFuture != null) {
            checkConnectionFuture.cancel(true);
        }

        CheckConnectionTask t = new CheckConnectionTask();
        checkConnectionFuture = checkConnectionService.scheduleAtFixedRate(t, 0, 30000, MILLISECONDS);

    }

    private void resetSyncService(int time) {
        if(!primarySyncComplete) {
            EventBus.getDefault().post(new SyncronizeStartedEvent(this.rinfo1));
        }
        if(syncFuture != null) {
            syncFuture.cancel(true);
        }

        SyncTask t = new SyncTask();
        syncFuture = syncService.scheduleAtFixedRate(t, 0, time, MILLISECONDS);

    }

    private void handleInvitationRejected(MIDIControl control, Bundle rinfo) {
        connectFuture.cancel(true);


        EventBus.getDefault().post(new ConnectionFailedEvent(MIDIFailCode.REJECTED_INVITATION,rinfo,control.initiator_token));
        EventBus.getDefault().post(new MIDIConnectionRequestRejectedEvent(rinfo));
    }

    private void handleEnd() {
        this.isConnected = false;
        // shutdown sync
        if(connectFuture != null && !connectFuture.isCancelled()) {
            connectFuture.cancel(true);
        }
        if(syncFuture != null && !syncFuture.isCancelled()) {
            syncFuture.cancel(true);
        }
        if(checkConnectionFuture != null && !checkConnectionFuture.isCancelled()) {
            checkConnectionFuture.cancel(true);
        }
//        if(MIDISession.getInstance().getAutoReconnect()) {
//            Bundle rinfo = (Bundle) rinfo1.clone();
//            rinfo1 = rinfo2 = null;
//            sendInvitation(rinfo);
//            syncStarted = false;
//            syncFailCount = 0;
//            syncCount = 0;
//            this.isInitiator = false;
//            connectFuture = null;
//            checkConnectionFuture = null;
//            syncFuture = null;
//            primarySyncComplete = false;
//            return;
//        }
//        EventBus.getDefault().post(new MIDIConnectionEndEvent(this.rinfo1));
        EventBus.getDefault().post(new StreamDisconnectEvent(ssrc,(Bundle)this.rinfo1.clone()));