/*
 * Verrückte Turing-Maschinen — A turing complete game
 * Copyright (C) 2016-2018 kcf <vidofnir@folksprak.org>
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

namespace mod_vtm
	{
		
		export namespace mod_model
			{
				
				export namespace mod_token
					{
						
						/**
						 * @author kcf <vidofnir@folksprak.org>
						 */
						export type type_token =
							{
								state : mod_state.type_state;
								tape : Array<mod_symbol.type_symbol>;
								spot : mod_spot.type_spot;
							}
						;
						
						
						/**
						 * @author kcf <vidofnir@folksprak.org>
						 */
						export function create
							(
								tape : Array<mod_symbol.type_symbol> = [],
								spot : mod_spot.type_spot = mod_spot.null_()
							)
							: type_token
							{
								return {
									"state": mod_state.running,
									"tape": tape,
									"spot": spot,
								};
							}
						
						
						/**
						 * @author kcf <vidofnir@folksprak.org>
						 */
						export function state_read
							(
								token : type_token
							)
							: mod_state.type_state
							{
								return token.state;
							}
						
						
						/**
						 * @author kcf <vidofnir@folksprak.org>
						 */
						export function tape_read
							(
								token : type_token
							)
							: Array<mod_symbol.type_symbol>
							{
								return token.tape;
							}
						
						
						/**
						 * @author kcf <vidofnir@folksprak.org>
						 */
						export function spot_read
							(
								token : type_token
							)
							: mod_spot.type_spot
							{
								return token.spot;
							}
						
						
						/**
						 * @author kcf <vidofnir@folksprak.org>
						 */
						export function move
							(
								token : type_token,
								direction : mod_direction.type_direction
							)
							: void
							{
								let summand : mod_spot.type_spot = mod_spot.from_direction(direction);
								token.spot = mod_spot.add(token.spot, summand);
							}
						
						
						/**
						 * @author kcf <vidofnir@folksprak.org>
						 */
						export function write
							(
								token : type_token,
								symbol : mod_symbol.type_symbol
							)
							: void
							{
								token.tape.push(symbol);
							}
						
						
						/**
						 * @author kcf <vidofnir@folksprak.org>
						 */
						export function read
							(
								token : type_token
							)
							: lib_errormonade.type_errormonade<mod_symbol.type_symbol>
							{
								if (token.tape.length <= 0)
									{
										return (lib_errormonade.create_nothing<mod_symbol.type_symbol>());
									}
								else
									{
										return (lib_errormonade.create_just<mod_symbol.type_symbol>(token.tape[0]));
									}
							}
						
						
						/**
						 * @author kcf <vidofnir@folksprak.org>
						 */
						export function shift
							(
								token : type_token
							)
							: void
							{
								if (token.tape.length <= 0)
									{
										let message : string = "Band ist leer";
										throw (new Error(message));
									}
								else
									{
										token.tape.shift();
									}
							}
						
						
						/**
						 * @author kcf <vidofnir@folksprak.org>
						 */
						export function accept
							(
								token : type_token
							)
							: void
							{
								token.state = mod_state.accepted;
							}
						
						
						/**
						 * @author kcf <vidofnir@folksprak.org>
						 */
						export function reject
							(
								token : type_token
							)
							: void
							{
								token.state = mod_state.rejected;
							}
						
					}
					
			}
			
	}


