/*
 * Copyright 2013 Yuichiro Moriguchi
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.morilib.nina;

import java.io.Reader;

/**
 *
 *
 * @author MORIGUCHI, Yuichiro 2013/10/14
 */
public class NinaFrameReader extends Reader {

	private static enum E {
		INIT, CHR0, CRLF, EOF, FIN
	}

	private Quadro quadro;
	private E etat = E.INIT;

	NinaFrameReader(Quadro q) {
		quadro = q;
	}

	private boolean isfrm2() {
		return (NinaParser._FRAME1.equals(quadro.getScratch2()) ||
				NinaParser._FRAME2.equals(quadro.getScratch2()));
	}

	/* (non-Javadoc)
	 * @see java.io.Reader#read()
	 */
	@Override
	public int read() {
		int c;

		while(true) {
			switch(etat) {
			case INIT:
				if(isfrm2()) {
					quadro.north();
					etat = E.EOF;
				} else {
					etat = E.CHR0;
					c = quadro.get();
					quadro.east();
					return c < 0 ? 0 : c;
				}
				break;
			case CHR0:
				if(isfrm2()) {
					quadro.west();
					etat = E.CRLF;
				} else if((c = quadro.get()) >= 0) {
					quadro.east();
					return c;
				} else {
					quadro.east();
				}
				break;
			case CRLF:
				if(isfrm2()) {
					quadro.east().south();
					etat = E.INIT;
					return '\n';
				} else {
					quadro.west();
				}
				break;
			case EOF:
				if(isfrm2()) {
					quadro.west();
					etat = E.FIN;
				} else {
					quadro.north();
				}
				break;
			case FIN:
				return -1;
			}
		}
	}

	/* (non-Javadoc)
	 * @see java.io.Reader#read(char[], int, int)
	 */
	@Override
	public int read(char[] b, int off, int len) {
		int c;

		for(int i = off; i < off + len; i++) {
			if((c = read()) < 0) {
				return i > off ? i - off : -1;
			} else {
				b[i] = (char)c;
			}
		}
		return len;
	}

	/* (non-Javadoc)
	 * @see java.io.Reader#read(char[])
	 */
	@Override
	public int read(char[] cbuf) {
		return read(cbuf, 0, cbuf.length);
	}

	/* (non-Javadoc)
	 * @see java.io.Reader#close()
	 */
	@Override
	public void close() {
		switch(etat) {
		case INIT:
			quadro.west();
			for(; isfrm2();  quadro.north());
			quadro.south();
			return;
		case CHR0:
			for(; !isfrm2(); quadro.west());
			for(; isfrm2();  quadro.north());
			quadro.south();
			return;
		default:  return;
		}
	}

}
