#!/bin/bash

#%#
# Copyright 2007 Logan Lee
# Released under GPL
#%#

#%%#
# 0 Tokenizer:
# OK, we can generate a file that contains a token per line using tokenizer. Now we can read each line(a token) and process them.

# 1 Plan outline
# 1.1 Read from output generated by tokenizer <- this is source
# 1.2 Learn to recognize combinations of tokens found in source. <- should be a separate file containing the combinations(let's call it combos)
# 1.3 Process source referring to combos.

# 2 Support code

# 2.1 Read from tokenizer output

TOKENIZER="./tokenizer"
TEST_STRING_FILE="./ply_source"
SOURCE=`$TOKENIZER $TEST_STRING_FILE > /tmp/ply/tokenizer_source`
COMBO_FILE="./ply_combo"
COMBO=`$TOKENIZER $COMBO_FILE > /tmp/ply/tokenizer_combo`

[[ ! -r $TEST_STRING_FILE ]] || [[ ! -r $COMBO_FILE ]] && echo "No ply_source or ply_combo found!" && exit 1

[ ! -d "/tmp/ply" ] && mkdir /tmp/ply

function readFromTokenizer {
    while read TOKEN; do
	echo $TOKEN
    done < "/tmp/ply/tokenizer_source"
} 

# Let's also identify types of tokens.

TOKEN[0]=""

# We'll call an array that contains every token in succession as 'record'. This function generates a record.
# It returns source size(no. of elements in,)
function generateRecord {
    t=1
    while read TOKEN; do
	TOKEN[$t]=$TOKEN
	t=`expr $t + 1`
    done < "/tmp/ply/tokenizer_source"
    echo $t
}

SOURCE_SIZE_PLUS_ONE=$(generateRecord)

function getRecord {
    t=1
    until [ "$t" -eq "$SOURCE_SIZE_PLUS_ONE" ]; do
	echo ${TOKEN[$t]}
	t=`expr $t + 1`
    done < "/tmp/ply/tokenizer_source"
}
#generateRecord > /dev/null && getRecord

# Here's a way to identify unique token from all of the tokens in source:
# a   a
# b x b
# c   c
#
# There are combinations between (a,b,c) x (a,b,c). The unique token 'a' is identified if LHS[$index_a]==RHS[$index_a] but LHS[$index_a]!=RHS[!$index_a].

UNIQUE_TOKEN[0]=""

# Output of this function corresponds to most likely non-tag tokens.
function findUniqueTokens {
    SOURCE_SIZE=`expr $SOURCE_SIZE_PLUS_ONE - 1`
    PREV_TOKEN=""
    v=1
    for t in `seq 1 $SOURCE_SIZE`; do
	for u in `seq 1 $SOURCE_SIZE`; do
	    # LHS[t]=RHS[t]
	    if [ "$t" -eq "$u" ]; then
		# If last token...
		if [ "$t" -eq "$SOURCE_SIZE" ]; then
		    # Match!
		    UNIQUE_TOKEN[$v]=${TOKEN[$t]}
		    echo ${UNIQUE_TOKEN[$v]}
		    v=`expr $v + 1`
		fi
		# Otherwise, next iteration.
		continue
		
	    # If LHS[t]=RHS[u] and t!=u, then no point continuing with current token. Move on to the next token.
	    elif [ "${TOKEN[$t]}" = "${TOKEN[$u]}" ]; then
		break

	    # Else, match!
	    elif [ "$u" -eq "$SOURCE_SIZE" ]; then
		UNIQUE_TOKEN[$v]=${TOKEN[$t]}
		echo ${UNIQUE_TOKEN[$v]}
		v=`expr $v + 1` 
	    fi
	done
   done
}
#generateRecord > /dev/null && findUniqueTokens

# Store identified non-tags in a file.
#generateRecord > /dev/null && findUniqueTokens > /tmp/ply/parser_uniq

# Most likely tag tokens.
function findCommonTokens {
    comm -3 /tmp/ply/tokenizer_source /tmp/ply/parser_uniq | sort - | uniq -
}
generateRecord > /dev/null && findUniqueTokens > /tmp/ply/parser_uniq && findCommonTokens > /tmp/ply/parser_tags


# 2.2 Combo Stuff
# <Pattern> : <Action>

# source = tag + nontag. Now we move fake tags in /tmp/ply/parser_tags to /tmp/parser_nontags. To do this we need specified information about which are real tags.
# DO NOT USE SAME STRING FOR NONTAG THAT IS ALREADY DEFINED AS TAG IN COMBO!!!

function generateParserTags {
    # Move the token(s) that is/are common to both tokenizer_combo and parser_uniq and then copy it/them to parser_tags.
    if [ -n "$(comm -12 /tmp/ply/tokenizer_combo /tmp/ply/parser_uniq)" ]; then
	comm -12 /tmp/ply/tokenizer_combo /tmp/ply/parser_uniq |
	while read u; do
	    touch /tmp/ply/parser_tags && echo $u >> /tmp/ply/parser_tags
	done
    fi
    cat /tmp/ply/parser_tags
}

generateParserTags > /dev/null

# Now parse tokenizer_combo by referencing with parser_tags.
# We need to split pattern and action.

PATTERN[0]=""
ACTION[0]=""
VARS[0]=""
VAR[0]=""

function loadComboSettings {
    k=1
    while read c; do
	PATTERN[$k]=`echo $c | cut -d":" -f1`
	ACTION[$k]=`echo $c | cut -d":" -f2`
	k=`expr $k + 1`
    done < $COMBO_FILE
    echo $k
}

loadComboSettings > /dev/null

# 2.3 Detect and process pattern/action	pair.

function sourceMapping {
    v=1
    VARS=""
    while read s; do
	# If found on parser_tags 1, otherwise 0.
	if [ -n "$(grep $s /tmp/ply/parser_tags)" ] && [ "$s" != "^" ]; then
	    echo -n " $s "
	elif [ "$s" = "^" ]; then
	    echo ""
	    VARS[$v]=$VARS
	    VARS=""
	    v=`expr $v + 1`
	else
	    echo -n "?"
	    VARS+="$s "
	fi
    done < "/tmp/ply/tokenizer_source"
}
sourceMapping > /dev/null

function patternMapping {
    c=`expr $(loadComboSettings) - 1`
    for i in `seq 1 $c`; do
	for j in ${PATTERN[$i]}; do
	    if [ -n "$(grep $j /tmp/ply/parser_tags)" ] && [ "$s" != "^" ]; then
		echo -n " $j "
	    else
		echo -n "?"
	    fi
	done
	echo ""
    done
}

function actionMapping {
    a=`expr $(loadComboSettings) - 1`
    for i in `seq 1 $a`; do
	echo ${ACTION[$i]}
    done
}

SOURCE_MAP=$(sourceMapping)
PATTERN_MAP=$(patternMapping)
ACTION_MAP=$(actionMapping)
    
function generateRunlist {
    echo "$SOURCE_MAP" | 
    while read s; do
	pline=1
	echo "$PATTERN_MAP" |
	while read p; do
	    aline=1
	    [[ -n $(echo "$s" | grep "$p") ]] &&
	    echo "$ACTION_MAP" |
	    while read a; do
		[[ $aline = $pline ]] &&  echo "$a"
		aline=`expr $aline + 1`
	    done
	    pline=`expr $pline + 1`
	done
    done
}
generateRunlist > /tmp/ply/runlist

function generateVarlist {
    for v in $(seq 1 $(expr ${#VARS[@]} - 1)); do
	i=1
	for w in ${VARS[$v]}; do
	    echo "$v ?$i $w"
	    i=`expr $i + 1`
	done
    done
}
generateVarlist > /tmp/ply/varlist

function run {
    l=1
    lines=""
    while read r; do
	line=$r
	while read v; do
	    if [[ $(echo $v | cut -d" " -f1) = $l ]]; then
		var=$(echo $v | cut -d" " -f2)
		value=$(echo $v | cut -d" " -f3)
		line=$(echo $line | sed s@$var@$value@ | sed s@'$'$var@'$'$value@)
	    fi
	done < "/tmp/ply/varlist"
	lines+="$line\n"
	l=`expr $l + 1`
    done < "/tmp/ply/runlist"
    # Execute!
    echo -e $lines
}

# 3 Main
#%%#
function main {
    run > ./run		
    # Clean up
    #rm /tmp/ply/tokenizer* && rm /tmp/ply/parser* #&& rm /tmp/ply/runlist && rm /tmp/ply/varlist
}

main
