view src/sample/merge/TranslaterImp1.java @ 104:a2089a730a2e

change Translater class to interface.
author kent
date Sat, 22 Dec 2007 21:10:46 +0900
parents
children 2e649cd44078
line wrap: on
line source

package sample.merge;

import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import java.util.Stack;

import remoteeditor.command.REPCommand;
import remoteeditor.network.REP;

public class TranslaterImp1 implements Translater{
	//List <REPCommand> userList;
	//List <REPCommand> tokenList;
	private LinkedList<REPCommand> sentCmds;
	//private LinkedList<REPCommand> unMergedCmds;
	private Stack<REPCommand> unMergedCmds;
	public int eid;

	public TranslaterImp1(int _eid){
		eid = _eid;
		sentCmds = new LinkedList<REPCommand>();
		unMergedCmds = new Stack<REPCommand>();
	}

	/**
	 * Translate cmd When the editor send REPCommand.
	 * but now, Only adding cmd to the queue is available.
	 * @param cmd
	 * @return translated command.
	 */
	public REPCommand transSendCmd(REPCommand cmd){
		sentCmds.add(cmd);
		unMergedCmds.push(cmd);
		return cmd;
	}
	/**
	 * Dequeue command cmd that was returned.
	 * @param cmd
	 */
	public REPCommand[] catchOwnCommand(REPCommand cmd){
		ArrayList<REPCommand> returnCmds = new ArrayList<REPCommand>();
		ArrayList<REPCommand> cmds = new ArrayList<REPCommand>();
		// ringである以上、戻ってきたコマンドは確実にキューsentCmdsの先頭にある事を期待している
		//REPCommand cmd0 = sentCmds.poll();
		//assert cmd0.seq!=cmd.seq;
		assert cmd.eid==eid;

		/* スタックから全部取り出してマージする まだマージできないやつはまたスタックへ戻す  */
		while ( !unMergedCmds.isEmpty() ){
			REPCommand cmd0 = unMergedCmds.pop();
			returnCmds.add( createUndo(cmd0) );
			cmds.add(cmd0);
		}
		//if (cmds.size()==0) return null;
		returnCmds.addAll( sortCmds(cmds) );
		return returnCmds.toArray(new REPCommand[0]);
	}

	private REPCommand createUndo(REPCommand cmd){
		//REPCommand retCmd = cmd.clone();
		REPCommand retCmd = new REPCommand(cmd.cmd, cmd.sid, cmd.eid, cmd.seq, cmd.lineno, cmd.string.length(), cmd.string);

		if (cmd.cmd==REP.REPCMD_INSERT) retCmd.cmd=REP.REPCMD_DELETE;
		else if (cmd.cmd==REP.REPCMD_DELETE) retCmd.cmd=REP.REPCMD_INSERT;
		return retCmd;
	}

	private ArrayList<REPCommand> sortCmds(ArrayList<REPCommand> cmds) {
		ArrayList<REPCommand> sortedCmds = new ArrayList<REPCommand>();
		REPCommand cmd0;
		int prevEid=0;
		int i,j;

		/* EID,SEQの低い順に、各EID毎に1個だけ選択しcmdsに格納  */
		while ( null != (cmd0=getPrecedence(cmds, prevEid+1)) ){
			sortedCmds.add(cmd0);
			cmds.remove(cmd0);
			prevEid = cmd0.eid;
		}

		/* lineno の大きい順にソート  */
		for (i=0; i<sortedCmds.size(); i++){
			int k=i;
			for (j=i+1; j<sortedCmds.size(); j++){
				if ( sortedCmds.get(k).lineno > sortedCmds.get(j).lineno ) continue;
				else if ( sortedCmds.get(k).lineno < sortedCmds.get(j).lineno 
						|| sortedCmds.get(k).eid > sortedCmds.get(j).eid )
					   /* deleteとinsertの場合などはeidによらず、順序を強制する必要があるかも  */
					k=j;
			}
			cmd0 = sortedCmds.get(i);
			sortedCmds.set(i, sortedCmds.get(k));
			sortedCmds.set(k, cmd0);
		}
		return sortedCmds;
	}

	/* search cmd. ordering by  min EID that is lower lowEid and min SEQ.  */
	private REPCommand getPrecedence(ArrayList<REPCommand> cmds, int lowEid) {
		int cEid, cSeq;
		cEid=cSeq=Integer.MAX_VALUE;
		REPCommand  ret=null;
		for (int i=0; i<cmds.size(); i++){
			REPCommand tmp = cmds.get(i);
			if ( tmp.eid<lowEid ) continue;
			else if ( tmp.eid>cEid ) continue;
			else if ( tmp.eid==cEid ) {
				if ( tmp.seq>cSeq ) continue;
				cSeq=tmp.seq;
				ret = tmp;
			} else { /* tmp.eid<cEid */
				cEid = tmp.eid;
				cSeq = tmp.seq;
				ret = tmp;
			}
			//if ( cEid>cmds.get(i) && cmds.get(i)>lowEid )
		}
		return ret;
	}

	/**
	 * Translate Command cmd that was received from SeMa.
	 * @param cmd the command to be translated.
	 * @return translated commannd.
	 */
	public REPCommand[] transReceiveCmd(REPCommand cmd){
		int i=0;
		REPCommand cmds[];
		if (cmd.eid==eid){
			return catchOwnCommand(cmd);
		}

		for (REPCommand cmd0 : unMergedCmds){
			if (cmd0.eid==cmd.eid) i++;
		}

		if ( sentCmds.size()<i ){
			cmds = new REPCommand[2];
			String str = "NO OPERATION";
			cmds[0] = new REPCommand(REP.REPCMD_NOP, 0, eid, 0, 0, str.length(), str);
			cmds[1] = cmd;
			//unMergedCmds.push(cmds[0]);
			unMergedCmds.push(cmd);
			sentCmds.add(cmds[0]);
			return cmds;
		}

		unMergedCmds.push(cmd); /* but.. */
		cmds = new REPCommand[1];
		cmds[0] = cmd;
		return cmds;
	}

	public void setEid(int _eid){
		eid = _eid;
	}
}