package org.sfm.csv.parser;


public final class CharConsumer {

	public static final int IN_QUOTE = 4;
	public static final int IN_CR = 2;
	public static final int QUOTE = 1;
	public static final int NONE = 0;

	public static final int TURN_OFF_IN_CR_MASK = ~IN_CR;
	public static final int ALL_QUOTES = QUOTE | IN_QUOTE;

	
	private int currentState = NONE;

	private final CharsCellHandler handler;

	public CharConsumer(CharsCellHandler handler) {
		this.handler = handler;
	}
	
	public boolean next(CharBuffer csvBuffer) {
		while(csvBuffer.hasContent()) {
			char c = csvBuffer.getNextChar();
			switch (c) {
			case ',':
				newCellIfNotInQuote(csvBuffer);
				turnOffCrFlag();
				break;
			case '"':
				quote(csvBuffer);
				turnOffCrFlag();
				break;
			case '\n':
				boolean cont = handleEndOfLineLF(csvBuffer);
				turnOffCrFlag();
				if (!cont) {
					return false;
				}
				break;
			case '\r':
				if (!handleEndOfLineCR(csvBuffer)) {
					return false;
				}
				break;
			default:
				turnOffCrFlag();
			}
		}
		return true;
	}

	private int turnOffCrFlag() {
		return currentState = currentState & TURN_OFF_IN_CR_MASK;
	}

	private void newCellIfNotInQuote(CharBuffer csvBuffer) {
		if (isInQuote())
			return;
		
		newCell(csvBuffer, 1);
	}



	private boolean isInQuote() {
		return currentState == IN_QUOTE;
	}
	
	private boolean handleEndOfLineLF(CharBuffer csvBuffer) {
		boolean b = true;
		if (!isInQuote()) {
			if (currentState != IN_CR) {
				b = endOfRow(csvBuffer);
			} else {
				// we had a preceding cr so shift the marl
				csvBuffer.mark();
			}
		}
		return b;
	}

	private boolean handleEndOfLineCR(CharBuffer csvBuffer) {
		boolean b = true;
		if (!isInQuote()) {
			b = endOfRow(csvBuffer);
			currentState = IN_CR;
		}
		return b;
	}

	private boolean endOfRow(CharBuffer csvBuffer) {
		newCell(csvBuffer, 1);
		return handler.endOfRow();
	}

	private void quote(CharBuffer csvBuffer) {
		if (csvBuffer.isAllConsumed()) {
			currentState = IN_QUOTE;
		} else {
			currentState = currentState ^ ALL_QUOTES;
		}
	}

	private void newCell(CharBuffer csvBuffer, int shift) {;
		handler.newCell(csvBuffer.getCharBuffer(), csvBuffer.getMark(), csvBuffer.getLengthFromMark() - shift);
		csvBuffer.mark();
		currentState = NONE;
	}

	public void finish(CharBuffer csvBuffer) {
		if (!csvBuffer.isAllConsumed()) {
			newCell(csvBuffer, 0);
		}
		handler.end();
	}

}

@@ -657,37 +657,16 @@
 uffer);%0A
-%09%09%09%09turnOffCrFlag();%0A
 %09%09%09%09brea
@@ -660,32 +660,32 @@
 er);%0A%09%09%09%09break;%0A
+
 %09%09%09case '%22':%0A%09%09%09
@@ -703,37 +703,16 @@
 uffer);%0A
-%09%09%09%09turnOffCrFlag();%0A
 %09%09%09%09brea
@@ -736,23 +736,13 @@
 %09%09%09%09
-boolean cont = 
+if (!
 hand
@@ -769,44 +769,8 @@
 fer)
-;%0A%09%09%09%09turnOffCrFlag();%0A%09%09%09%09if (!cont
 ) %7B%0A
@@ -1168,16 +1168,35 @@
 er, 1);%0A
+%09%09turnOffCrFlag();%0A
 %09%7D%0A%0A%0A%0A%09p
@@ -1508,32 +1508,51 @@
 ark();%0A%09%09%09%7D%0A%09%09%7D%0A
+%09%09turnOffCrFlag();%0A
 %09%09return b;%0A%09%7D%0A%0A
@@ -1996,20 +1996,39 @@
 QUOTES;%0A
-
 %09%09%7D%0A
+%09%09turnOffCrFlag();%0A
 %09%7D%0A%0A%09pri

simplify loop