#
# Copyright 2013-2014 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.
#
putlicense_cstyle.sh

[ -z "$PACKAGE" ] || echo "package $PACKAGE;"
[ -z "$EXTENDS" ] || extends="extends $EXTENDS"
[ -z "$IMPLEMENTS" ] || implements="implements $IMPLEMENTS"
print_imports
cat definition

if [ -z "$TYPE" ]
then
  nullsym='-1'
  [ -z "$NEWLINEMODE" ] && streamsym='java.io.Reader'
  [ -z "$NEWLINEMODE" ] || streamsym='java.io.InputStream'
  rdt='java.io.Reader'
  tre='throws java.io.IOException'
else
  nullsym='null'
  rdt="Iterable<$CTYPE>"
  streamsym='java.util.Iterator'
  tre=''
fi

echo '/**'
awk '{ printf(" * %s\n", $0) }' description
echo ' */'
cat << EOF
public $ABSTRACT class ${CLASSNAME}${TEMPLATE} $extends $implements {

	static final int N  = 0x1000;
	static final int E  = 0x0100;
	static final int W  = 0x0010;
	static final int S  = 0x0001;
	static final int L  = W;
	static final int R  = E;
	static final int NE = N | E;
	static final int NW = N | W;
	static final int SE = S | E;
	static final int SW = S | W;
	static final int INITIAL = 0;

	private int STATE;
EOF

case "$TAPETYPE" in
DFA)
  if [ -z "$TYPE" ]
  then
    cat << EOF
	private $streamsym reader;
	private $CTYPE now = $nullsym;

	${CLASSNAME}${TEMPLATE}($streamsym rd) $tre {
		reader = rd;
		now = rd.read();
	}

	$CTYPE _getnow() {
		try {
			return reader.read();
		} catch(java.io.IOException e) {
			throw new RuntimeException(e);
		}
	}
EOF
  else
    cat << EOF
	private java.util.Iterator<$CTYPE> reader;
	private $CTYPE now = $nullsym;

	${CLASSNAME}${TEMPLATE}(java.util.Iterator<$CTYPE> rd) $tre {
		reader = rd;
		now = rd.hasNext() ? rd.read() : $nullsym;
	}

	$CTYPE _getnow() {
		return reader.hasNext() ? reader.read() : $nullsym;
	}
EOF
  fi
  cat << EOF

	$CTYPE _readtape() {
		return now;
	}

	void _writetape($CTYPE o) {
		now = o;
	}

	void _movetape(int direction) {
		switch(direction) {
		case E:
			if(now != $nullsym)  now = _getnow();
			return;
		default:  throw new RuntimeException();
		}
	}
EOF
  ;;
*)
  if [ -z "$TYPE" ]
  then
    cat << EOF
	private $CTYPE[] _tape;
	private int _tapeptr = 0;

	${CLASSNAME}${TEMPLATE}($streamsym rd) $tre {
		$CTYPE[] a = new $CTYPE[100], b;
		int p = 0;
		$CTYPE c;

		while((c = rd.read()) >= 0) {
			if(p >= a.length) {
				b = a;
				a = new $CTYPE[a.length * 2];
				System.arraycopy(b, 0, a, 0, b.length);
			}
			a[p++] = c;
		}
		b = a;
		a = new $CTYPE[p];
		System.arraycopy(b, 0, a, 0, p);
		_tape = a;
		_tapeptr = 0;
	}
EOF
  else
    cat << EOF
	private $CTYPE[] _tape;
	private int _tapeptr = 0;

	${CLASSNAME}${TEMPLATE}(java.util.Iterator<$CTYPE> rd) $tre {
		$CTYPE[] a = new $CTYPE[100], b;
		int p = 0;

		while(rd.hasNext()) {
			if(p >= a.length) {
				b = a;
				a = new $CTYPE[a.length * 2];
				System.arraycopy(b, 0, a, 0, b.length);
			}
			a[p++] = rd.next();
		}
		b = a;
		a = new $CTYPE[p];
		System.arraycopy(b, 0, a, 0, p);
		_tape = a;
		_tapeptr = 0;
	}
EOF
  fi
  cat << EOF

	$CTYPE _readtape() {
		if(_tapeptr < 0 || _tapeptr >= _tape.length) {
			return $nullsym;
		}
		return _tape[_tapeptr];
	}

	void _writetape($CTYPE o) {
		if(_tapeptr >= 0 && _tapeptr < _tape.length) {
			_tape[_tapeptr] = o;
		}
	}

	void _movetape(int direction) {
		switch(direction) {
		case E:
			_tapeptr += _tapeptr < _tape.length ? 1 : 0;
			return;
		case W:
			_tapeptr -= _tapeptr >= 0 ? 1 : 0;
			return;
		default:  throw new RuntimeException();
		}
	}
EOF
  ;;
esac

cat field
c='$c'
echo
cat << EOF
	private int _step($CTYPE $c) {
		switch(STATE) {
EOF
print_states
cat << EOF
		}
		return 0;
	}

	private boolean _accepted() {
EOF
print_accepts
cat << EOF
	}

	private int _execaction($CTYPE $c) {
		switch(STATE) {
EOF
print_actions
cat << EOF
		}
		return 1;
	}

	private boolean _execstep() {
		if(_step(_readtape()) != 0) {
			return false;
		} else if(_accepted()) {
			return true;
		} else {
			throw new RuntimeException();
		}
	}

	void run() {
		do {
			_execaction(_readtape());
		} while(!_execstep());
	}

	static void parse($streamsym rd) $tre {
		${CLASSNAME}${TEMPLATE} r;

		r = new ${CLASSNAME}${TEMPLATE}(rd);
		r.run();
	}

EOF
[ -z "$TYPE" ] && [ -z "$NEWLINEMODE" ] && cat << EOF
	static void parse(java.io.InputStream rd) $tre {
		parse(new java.io.InputStreamReader(rd));
	}

EOF

cat fragment
echo '}'
