view rep/Editor.java @ 319:dfed28488274

*** empty log message ***
author kono
date Thu, 09 Oct 2008 17:26:55 +0900
parents dc57e24ea3df
children 1e605880d49e
line wrap: on
line source

package rep;

import java.util.LinkedList;
import java.util.List;
import rep.channel.REPSocketChannel;
import rep.handler.PacketSet;
import rep.optimizers.*;
import rep.translater.TranslaterImp1;

public class Editor extends Forwarder {

	private TranslaterImp1 translater;
	private List<REPCommand> sentList = new LinkedList<REPCommand>();
	// REPCommands we are going to send to the next editor
	private REPCommandOptimizer optimizer;
	//private REPCommand quit2 = null;
	private SessionManager manager;
	private REPCommand quit2=null;

	public Editor(SessionManager manager,boolean doOptimize,int editorNo){
		super(manager);
		this.manager = manager;
		eid = editorNo;
		translater = new TranslaterImp1(eid);
		if (doOptimize) optimizer = new DeleteInsertOptimizer(); //タカノがつくったおぷてぃまいざ
		else            optimizer = new NullOptimizer();         //なにもしないけどOptimizer.
		
	}

	public Editor(SessionManager manager,int editorNo, REPSocketChannel<REPCommand> channel){
		this(manager,false,editorNo);
		this.channel = channel;
		setHostAndPort(channel);
	}

	public void translate(Forwarder nextEditor, REPCommand command){
		if(command.eid == nextEditor.getEID()){
			if(checkReturnedCommand(command)){
				// エディタからのコマンドが元のエディタに戻ってきた
				// START_MERGE を送る
				REPCommand cmd = new REPCommand(REP.SMCMD_START_MERGE,command.sid,REP.SM_EID.id,seq(),0,"");
				nextEditor.send(cmd);
				// Session Manager 側で、このeditorへの他のeditorからの
				// 入力を止めて、merge にそなえる。merge は、eidtor 側から
				// ACKが来てから始まる。
				return;
			} else assert(false);
		} else if(command.eid == eid){
				//エディタからの新たな編集コマンド
				sentList.add(command);
				assert(sentList.size()<limit);
				translater.transSendCmd(command);
				nextEditor.send(command);
				return;
		}else if(command.eid == REP.MERGE_EID.id){
			//マージコマンドが返ってきた
			if(translater.checkMergeConflict(command)){
				//マージ中にエディタからの割り込みがあった場合
				if (optimizedSend(translater.getMergeAgain())) {
					return;
				}
			}
			if(!isMerging()) {
				endMerge();
			}
		}else{
			//他のエディタからの編集コマンド
			if(!isMerging()) {
				translater.transReceiveCmd(nextEditor,command);
				return;
			}
			manager.addWaitingCommand(new PacketSet(getChannel(), this, command));
		}
		return;
	}
	
	boolean merge(Editor editor,REPCommand command) {
		REPCommand prev = translater.prev();
		if(prev==null) return false;
		assert(prev.eid==command.eid);
		//マージして送信
		return translater.catchOwnCommand(editor);
	}

	boolean checkReturnedCommand(REPCommand command) {
		if(sentList.size() > 0){
			if(sentList.get(0).seq == command.seq){
				sentList.remove(0);
				if (quit2!=null&&sentList.size()==0) {
					send(quit2);
					manager.remove(this);
				}
				return true;
			}else{
				System.err.println("Editor.checkReturnedCommand() : command = " + command);
				assert(false);
			}
		}
		return false;
	}

	@Override
	public void setQuit2(REPCommand cmd) {
		if (sentList.size()==0) {
			send(cmd);
			manager.remove(this);
		}
		// do not send quit2 until we received all pending
		// command
		quit2 = cmd;
	}
	
	private void setHostAndPort(REPSocketChannel<REPCommand> myChannel2) {
		//host = myChannel2.socket().getRemoteSocketAddress().toString();
		
	}




	@Override
	public void setEID(int eid) {
		this.eid = eid;
		translater.setEid(eid);
	}
	
	public String toString(){
		return ("Editor eid="+eid+" sid="+sid+" " + host  + ":" + file);
	}

	public boolean isMerging() {
		return translater.isMerging();
	}
	public boolean hasSession() {
		return sid != -1;
	}
	public void setSID(int sessionID) {
		sid   = sessionID;
	}
	
	/**
	 * Sent optimized merged command list
	 * @param output
	 * @return if any sent commands output 
	 */
	public boolean optimizedSend(LinkedList<REPCommand> output) {
		List<REPCommand> output1 = optimizer.optimize(output);
		if (output1.size()==0) return false;
		for(REPCommand c:output1) {
			REPCommand m = new REPCommand(c);
			m.setEID(REP.MERGE_EID.id);
			m.setSEQID(seq());
			send(m);
		}				
		return true;
	}

	void endMerge() {
		REPCommand mergeEnd = new REPCommand(REP.SMCMD_END_MERGE,eid,sid,seq(),0,"");
		send(mergeEnd);
	}

	@Override
	public boolean manage(REPCommand receivedCommand) {
	
		switch(receivedCommand.cmd){
		// Editor Command
		
		case REPCMD_DELETE:
		case REPCMD_INSERT:
		case REPCMD_NOP:
		{
			translate(next, receivedCommand);
			break;
		}
		
		case SMCMD_QUIT:
		{
			next.send(receivedCommand);
			break;
		}
		case SMCMD_QUIT_2:
		{
			Forwarder editor1 = getNextForwarder();
			// don't send quit2 to the editor until all pending
			// merge is processed.
			editor1.setQuit2(receivedCommand);
			break;
		}
		default:
			return false;
		}
		return true;
	}
	
	
}