package org.prevayler.implementation.replication;
import java.io.IOException;
import org.prevayler.foundation.network.ObjectSocket;
import org.prevayler.implementation.Capsule;
import org.prevayler.implementation.TransactionTimestamp;
import org.prevayler.implementation.publishing.POBox;
import org.prevayler.implementation.publishing.TransactionPublisher;
import org.prevayler.implementation.publishing.TransactionSubscriber;

/** 
 * Reserved for future implementation.
 */
class ServerConnection extends Thread implements TransactionSubscriber {
  static final String SUBSCRIBER_UP_TO_DATE="SubscriberUpToDate";
  static final String REMOTE_TRANSACTION="RemoteTransaction";
  private final TransactionPublisher _publisher;
  private Capsule _remoteCapsule;
  private final ObjectSocket _remote;
  private final Thread _clockTickSender=createClockTickSender();
  ServerConnection(  TransactionPublisher publisher,  ObjectSocket remoteSocket) throws IOException {
    _publisher=publisher;
    _remote=remoteSocket;
    setDaemon(true);
    start();
  }
  public void run(){
    try {
      long initialTransaction=((Long)_remote.readObject()).longValue();
      POBox poBox=new POBox(this);
      _publisher.subscribe(poBox,initialTransaction);
      poBox.waitToEmpty();
      send(SUBSCRIBER_UP_TO_DATE);
      startSendingClockTicks();
      while (true)       publishRemoteTransaction();
    }
 catch (    IOException ex) {
      close();
    }
catch (    ClassNotFoundException ex) {
      close();
    }
  }
  private void startSendingClockTicks(){
    _clockTickSender.setDaemon(true);
    _clockTickSender.start();
  }
  private Thread createClockTickSender(){
    return new Thread(){
      public void run(){
        try {
          while (true) {
synchronized (_remote) {
              _remote.writeObject(_publisher.clock().time());
            }
            Thread.sleep(1000);
          }
        }
 catch (        InterruptedException ix) {
        }
catch (        IOException iox) {
          close();
        }
      }
    }
;
  }
  void publishRemoteTransaction() throws IOException, ClassNotFoundException {
    _remoteCapsule=(Capsule)_remote.readObject();
    try {
      _publisher.publish(_remoteCapsule);
    }
 catch (    RuntimeException rx) {
      send(rx);
    }
catch (    Error error) {
      send(error);
    }
  }
  public void receive(  TransactionTimestamp tt){
    if (tt.capsule() == _remoteCapsule)     tt=new TransactionTimestamp(null,tt.systemVersion(),tt.executionTime());
    try {
synchronized (_remote) {
        _remote.writeObject(tt);
      }
    }
 catch (    IOException ex) {
      close();
    }
  }
  private synchronized void close(){
    _clockTickSender.interrupt();
    this.interrupt();
    _publisher.cancelSubscription(this);
  }
  private void send(  Object object){
synchronized (_remote) {
      try {
        _remote.writeObject(object);
      }
 catch (      IOException e) {
        e.printStackTrace();
      }
    }
  }
}
