/**
 * Arensus Crossword Applet: an open source crossword puzzle game in java.
 * Copyright (c) 2002 Phyrum Tea
 * http://www.tea.ch/ 
 * 
 * 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 2 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, write to the Free Software Foundation, Inc., 59 Temple
 * Place, Suite 330, Boston, MA 02111-1307, USA. 
 */

import java.applet.*;
import java.net.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.io.*;
import java.util.*;

/* Last modifications 15.10.2002 by Phyrum Tea
 * - removed java.awt.geom.*;
 * ToDo: - Scrolle, wenn das Kreuzworträtsel nicht in das Fenster passt.
 *       - oder skalieren
 */
public class TooHotCrosswordApplet extends Applet {
	final static int UPWARDS = 1;
	final static int DOWNWARDS = 2;
	
	/** field type is clue */
	final static int C = 4;
	
	/** field type is answer */
	final static int A = 8;
	
	/** clue direction is east-north */
	final static int EN = 16;
	
	/** clue direction is east */
	final static int EE = 32;
	
	/** clue direction is east-south */	
	final static int ES = 64;
	
	/** clue direction is south-west */
	final static int SW = 128;

	/** clue direction is south */
	final static int SS = 256;

	/** clue direction is south-east */
	final static int SE = 512;

	final static int AR = 4096;
	
	final static int H = 8192;
	
	final static int V = H*2;
	
	final static int BV = V*2;
	
	final static int EV = BV*2;
	
	final static int BH = EV*2;
	
	final static int EH = BH*2;
	
	/** field is selected, current position */
	final static int CURPOS = 1024;
	
	/** field is part of current word */
	final static int CURWORD = 2048;
	
	/** latest x-position of cursor */
	private int curX;
	
	/** latest y-position of cursor */
	private int curY;
	
	private int cellsX;
	private int cellsY;
	
	/** current direction */
	private int curDir;
	
	/** id of current Question */
	private int curQuestionPos;
	
	private String curQuestion;
	
	private String curAnswer;
	
	private int curAnswerX;
	
	private int curAnswerY;
	
	/** array of questions */
	private Vector questions;
	
	/** buffered image */
	private Image bImg;
	
	/** fields */
	private Element[][] field;
	
	/** width of cell */
	private int wc;
	
	/** url of crossword file */
	private URL dataFileURL;
	
	/** base url */
	private URL baseURL;
	private URL toohotURL;
	
	/** fonts are initialized flag */
	private boolean fontInitialized;
	
	/** backround of crossword puzzle */
	private Color bgColor;
	
	/** color of frame */
	private Color frameColor;
	
	/** line color */
	private Color lineColor;
	
	/** background color of question field */
	private Color qbgColor;
	
	/** background color of answer field */
	private Color abgColor;
	
	/** background of current wordcell */
	private Color abgcwColor;
	
	/** background of current cell */
	private Color abgccColor;
	
	/** background color of selected word fields */
	private Color wbgColor;
	
	/** font color of question */
	private Color qfColor;
	
	/** font color of answer */
	private Color afColor;
	
	/** font for answer */
	private Font aFont;
	
  /** font for clues */
	private Font qfFont;
	
	/** small font for clues */
	private Font qsFont;
	
	/** large font clues */
	private Font qlFont;
	
	private FontMetrics aFontM;
	private FontMetrics qfFontM;
	private FontMetrics qsFontM;
	private FontMetrics qlFontM;

	/** width of this component */
	private int drawWidth;
	
	/** height of this component */
	private int drawHeight;
	
	/** area of question text */
	private int qAreaHeight;
	
	/** padding between question area and puzzle area */
	private int qPadding;
	
	private int padY;
	private Toolkit toolkit;
	
	private Cursor handCursor, defaultCursor;
	private Cursor currentCursor;

	/** answer of user */
	private String fielAnswer[][];

	public void init() {
		String param;

		/* initialize default values, some of these values could be
		 * retrieved from applet parameters in future releases
		 */
		toolkit = getToolkit();
		fontInitialized = false;
		wc = 30;
		bgColor = Color.white;
		frameColor = Color.black;
		lineColor = Color.black;
		qbgColor = Color.darkGray;
		abgColor = Color.white;
		wbgColor = Color.black;
		qfColor = Color.white;
		afColor = Color.black;
		abgccColor = Color.orange;
		abgcwColor = Color.lightGray;
		curDir = H;
		curAnswer = null;
		bImg = null;
		dataFileURL = null;
		baseURL = getDocumentBase();
		/* get parameter */
		param = getParameter("WIDTHCELL");
		if (param != null) {
			try {
				wc = Integer.parseInt(param);
			} catch (NumberFormatException e) {
			}
		}
		
		qfFont = new java.awt.Font("SansSerif", 0, (int)(wc/5.0));
		aFont = new java.awt.Font("SansSerif", 0, (int)(wc*0.6));
		qlFont = new java.awt.Font("SansSerif", 0, 14);
		qsFont = new java.awt.Font("SansSerif", 0, 10);
		
		drawHeight = getSize().height;
		drawWidth = getSize().width;
		qAreaHeight = 20;
		qPadding = 15;
    padY = qAreaHeight+qPadding;
		handCursor = new Cursor(Cursor.HAND_CURSOR);
		defaultCursor = new Cursor(Cursor.DEFAULT_CURSOR);
		currentCursor = defaultCursor;
		
		/* get location of crossword puzzle data */
		param = getParameter("DATAURL");
		if (param != null) {
			try {
				if (param.indexOf(":") < 0)
					dataFileURL = new URL(baseURL,param);
				else
					dataFileURL = new URL(param);
					toohotURL = new URL("http://www.tea.ch/");
			} catch (MalformedURLException u) {
			}
		}
		
		/* load puzzle from that location */
		try {
			loadCrossword(dataFileURL);
		} catch (IOException ioe) {
			ioe.printStackTrace();
		}
		
		/* set initial selection */
		setActivePos(0,0);
		
		requestFocus();
  }

	public void paint(Graphics g) {
		render(g);
		super.paint(g);
	}
	
	public void update(Graphics g) {
		Rectangle cb = getBounds();
		
		/* we do double buffering with a buffered image */
		if (bImg == null) {
			bImg = createImage(cb.width,cb.height);
		}
		render(bImg.getGraphics());
		if (bImg != null)  {
			g.drawImage(bImg, cb.x, cb.y, this);
			toolkit.sync();
		}
	}
	
	public void render(Graphics g) {
		int i,j;
		if (!fontInitialized) {	
			/* one time Font-Metrics generation */		
			qfFontM = g.getFontMetrics(qfFont);
			aFontM = g.getFontMetrics(aFont);
			qlFontM = g.getFontMetrics(qlFont);
			qsFontM = g.getFontMetrics(qsFont);
			fontInitialized = true;
		}
    
    /* we now fill background of applet, clue area and crossword area,
		/* first clear applet background with background color
		 */
		g.setColor(bgColor);
		g.fillRect(0, 0, drawWidth, drawHeight);
		
		/* clear top clue area with clue background color */
    g.setColor(qbgColor);
    g.fillRect(0,0,drawWidth,qAreaHeight);
    
    /* draw border around top clue area */
    g.setColor(frameColor);
    g.drawRect(0,0,drawWidth-1,qAreaHeight-1);

		/* clear puzzle area with background color of answers */    
    g.setColor(abgColor);  
    g.fillRect(1,padY+1,cellsX*wc-1,cellsY*wc-1);
    
    /* no comment */
    g.setFont(qsFont);
    g.setColor(afColor);
    g.drawString("Arensus Crossword Applet © 2002 http://www.tea.ch/", 2, padY-3);
    
    g.setColor(qfColor);
    /* test if question is too wide for larger font */
    if (qlFontM.stringWidth(curQuestion) > drawWidth - 4) {
    	g.setFont(qsFont);
	    g.drawString(curQuestion,2,qAreaHeight-6);
    } else {
    	/* we can use large fonts for top clue area */
    	g.setFont(qlFont);
	    g.drawString(curQuestion,2,qAreaHeight-5);
    }
		
		/* start drawing cells */
		for (j=0;j<cellsX ;j++) {
	    for (i=0;i<cellsY;i++) {				
	    	
	    	/* fill backgrounds */
	    	if (field[i][j] == null) {
	    		/* cell is undefined */
	    		g.setColor(qbgColor);
					g.fillRect(1+j*wc,padY+i*wc+1,wc-1,wc-1);
	    		continue;
	    	}
	    	if ((field[i][j].t&CURPOS) == CURPOS) {
	    		/* cell is in current position of selection */
	    		g.setColor(abgccColor);
					g.fillRect(1+j*wc,padY+i*wc+1,wc-1,wc-1);
	    	} else if ((field[i][j].t&CURWORD) == CURWORD) {
	    		/* cell is part of word of current selection */
	    		g.setColor(abgcwColor);
					g.fillRect(1+j*wc,padY+i*wc+1,wc-1,wc-1);
	    	} else if ((field[i][j].t&C) == C) {
	    		/* cell contains a clue */
	    		g.setColor(qbgColor);
					g.fillRect(1+j*wc,padY+i*wc+1,wc-1,wc-1);
	    	} else {
	    	}
	    	
	    	
				if (field[i][j].g != null) {
					/* field has a user-guess, draw guessed character */
					g.setColor(afColor);
					g.setFont(aFont);
					g.drawString(field[i][j].g,(int)(j*wc+(wc-aFontM.stringWidth(field[i][j].g))/2),
					(int)(padY+(i+0.9)*wc-((wc-aFontM.getAscent())/2)));
				} else if ((field[i][j].t&C) == C) {
					/* field is clue */
					g.setColor(qfColor);
					if (field[i][j].fclue == null) drawString(field[i][j].clue,j*wc,padY+i*wc,g);
					else drawStringForm(field[i][j].fclue,j*wc,padY+i*wc,g);
				}
				if ((field[i][j].t&AR) == AR) {
					/* field is arrow field too */
					if((field[i][j].a&(SE+ES))==(SE+ES)) {
						if ((field[i][j].a&SE) == SE) renderArrow(1+j*wc,padY+i*wc+1,SE,g);
						if ((field[i][j].a&ES) == ES) renderArrow(1+j*wc,padY+i*wc+1,ES,g);
					} else if((field[i][j].a&(SS+EE))==(SS+EE)) {
						renderArrow(1+j*wc,padY+i*wc+1,SS,g);
						renderArrow(1+j*wc,padY+i*wc+1,EE,g);
					} else renderArrow(1+j*wc,padY+i*wc+1,field[i][j].a,g);
					/* draw arrow */
				}
	    }
    }
		g.setColor(lineColor);
		/* draw horizontal lines */
		for (i=1;i<cellsY;i++) g.drawLine(1, padY+i*wc, cellsX*wc-1, padY+i*wc);
		
		/* draw vertical lines */
		for (j=1;j<cellsX;j++) g.drawLine(j*wc, padY+1, j*wc, padY+cellsY*wc-1);

		/* draw border around puzzle */
		g.setColor(frameColor);
		g.drawRect(0,padY,cellsX*wc,cellsY*wc);
	}
		
	protected void setActivePos(int row, int col) {
		int i=-1,j=-1,k,a=-1,b=-1;
		
		repaint();
		
		if ((row < 0)||(row >cellsY-1)||(col < 0)||(col > cellsX-1)) return;
		if (field[row][col] == null) return;
		int len;
		
		/* reset current selection */
		if (curAnswer != null) {
			len = curAnswer.length();
			field[curY][curX].t &= ~CURPOS;
			if (curDir==V) {
				for (k=0;k<len;k++) {
					field[curAnswerY+k][curAnswerX].t &= ~CURWORD;
				}
			} else {
				for (k=0;k<len;k++) {
					field[curAnswerY][curAnswerX+k].t &= ~CURWORD;
				}
			}
			if ((curX == col)&&(curY == row)&&((field[row][col].d&(H+V)) == (H+V))) {
				curDir = (curDir==V)?H:V;
			}
		}
		
		/* do we have to change direction? if we have both direction as choice,
		 * we keep old direction and do nothing */
		if ((field[row][col].d&(H+V)) != (H+V)) {
			curDir = field[row][col].d;
		}
		
		if ((field[row][col].t&C) == C) {
			a = row;
			b = col;
			switch (field[row][col].d) {
				case ES: i = row+1; j = col; curDir = H; break;
				case SE: i = row; j = col+1; curDir = V; break;
				case EE: i = row; j = col+1; curDir = H; break;
				case EN: i = row-1; j = col; curDir = H; break;
				case SW: i = row; j = col-1; curDir = V; break;
				case SS: i = row+1; j = col; curDir = V; break;
			} 
		} else if (curDir==V) {
			/* find clue in vertical direction */
			i = row; j = col;
			while ((i>=0)&&((BV&field[i][j].t) != BV)) i--;
			if ((BV&field[i][j].t) == BV) {
				if ((i-1>=0)&&(field[i-1][j] != null)&&((SS&field[i-1][j].d)==SS)) { a = i-1; b = j; }
				else if ((j-1>=0)&&(field[i][j-1] != null)&&((SE&field[i][j-1].d)==SE)) { a = i; b = j-1; }
				else if ((j+1<cellsX)&&(field[i][j+1] != null)&&((SW&field[i][j+1].d)==SW)) { a = i; b = j+1; }
			}
		} else {
			/* find clue in horizontal direction */
			i = row; j = col;
			while ((j>=0)&&((BH&field[i][j].t)!=BH)) j--;
			if ((BH&field[i][j].t)==BH) {
				if ((j-1>=0)&&(field[i][j-1] != null)&&((EE&field[i][j-1].d)==EE)) { a = i; b = j-1; }
				else if ((i-1>=0)&&(field[i-1][j] != null)&&((ES&field[i-1][j].d)==ES)) { a = i-1; b = j; }
				else if ((i+1<cellsY)&&(field[i+1][j] != null)&&((EN&field[i+1][j].d)==EN)) { a = i+1; b = j; }
			}
		}
		
		/* now: a contains row and b contains column of clue that was found and
		 * i contains row and j contains column of first letter of answer
		 */
		len = field[a][b].answer.length();
		
		curQuestion = field[a][b].clue;
		curAnswer = field[a][b].answer;
		
		curAnswerX = j;
		curAnswerY = i;
		
		/* tag all cells of word that is part of current selection */
		if (curDir==V) {
			for (k=0;k<len;k++) {
				field[i+k][j].t |= CURWORD;
			}
		} else {
			for (k=0;k<len;k++) {
				field[i][j+k].t |= CURWORD;
			}
		}

		if ((a==row)&&(b==col)) {
			curX = j;
			curY = i;
		} else {
			curX = col;
			curY = row;
		}
		field[curY][curX].t |= CURPOS;

		repaint();
	}
	
	public boolean mouseMove(Event evt, int px, int py) {
		if ((py > qAreaHeight)&&(py < padY)) {
			setCursor(handCursor);
			currentCursor = handCursor;
			getAppletContext().showStatus(toohotURL.toString());
		} else if (currentCursor != defaultCursor) {
			setCursor(defaultCursor);
			currentCursor = defaultCursor;
		}
		return true;
	}

	public boolean mouseDown(Event evt, int px, int py) {
		int x = px;
		int y = py-qAreaHeight-qPadding;
		if ((py > qAreaHeight)&&(py < padY)) {
			getAppletContext().showDocument(toohotURL);
		}
		
		if ((x < 0)||(y < 0)||(x > cellsX*wc)||(y > cellsY*wc)) {
			System.out.println("Ausserhalb");
		} else {
			int j = (int)((x-x%wc)/wc);
			int i = (int)((y-y%wc)/wc);
			setActivePos(i,j);
		}
		return false;
	}

	public boolean keyDown(Event evt, int key) {
		int row = curY,col = curX,i,dir=curDir,step=1;
		char[] car = new char[1];
		car[0] =  (char)key;
		if ((key > 256)||(key < 32)) {
			switch (key) {
				case 9: break; /* tabulator */
				case 10: break; /* enter key */
				case 1004: /* up arrow */
					if (curY==0) row = cellsY-1;
					else row = curY-1;
					dir = V;
					step = -1;
					break;
				case 1005: /* down arrow */
					row = (curY+1)%cellsY;
					dir = V;
					break;
				case 1006: /* left arrow */
					if (curX==0) col = cellsX-1;
					else col = curX-1;
					dir = H;
					step = -1;
					break;
				case 1007: /* right arrow */
					col = (curX+1)%cellsX;
					dir = H;
					break;
				default: return false;
			}
			/* now go to the preferred direction, we don't want to make an endless
			 * loop, so count loop with i
			 */
			i=0;
			if (dir == H) {
				while (((i < cellsX)&&(field[row][col] == null))||
					((i < cellsX)&&(field[row][col].clue != null))) {
					col = (cellsX+col+step)%cellsX;
					i++;
				}
			} else {
				while (((i < cellsY)&&(field[row][col] == null))||
					((i < cellsY)&&(field[row][col].clue != null))) {
					row = (cellsY+row+step)%cellsY;
					i++;
				}
			}
		} else {
			/* user has guessed */
			field[curY][curX].g = (new String(car)).toUpperCase();
			if ((curY+1==cellsY)&&(curX+1==cellsX)) {
				row=0;
				col=0;
			} else if(curDir==V) {
				if (curY+1==cellsY) {
					row = 0;
					col =curX+1;
				} else {
					row = curY+1;
				}
			} else {
				if (curX+1==cellsX) {
					col = 0;
					row = curY+1;
				} else {
					col = curX+1;
				}
			}
		}
		
		/* advance to the new position */
		setActivePos(row,col);
		return true;
	}
	
	private void renderArrow(int cx, int cy, int arrow, Graphics g) {
		int k;
		float[] xP = {0.2f,0.3f,0.2f};
		float[] yP = {1.4f,1.5f,1.6f};
		float[] xsP = {-0.4f,-0.5f,-0.6f};
		float[] ysP = {0.2f,0.3f,0.2f};
		boolean horizontal = true;
		g.setColor(frameColor);
		if ((arrow&EE) == EE) {
			cx -= 0.2*wc;
			cy -= wc;
		} else if ((arrow&ES) == ES) {
			cy -= wc;
			g.drawLine((int)(cx+0.1*wc), cy+wc, (int)(cx+0.1*wc), (int)(cy+1.5*wc));
			g.drawLine((int)(cx+0.1*wc), (int)(cy+1.5*wc), (int)(cx+0.2*wc), (int)(cy+1.5*wc));
		} else if ((arrow&EN) == EN) {
			cy -= wc;
			g.drawLine((int)(cx+0.1*wc), cy+2*wc, (int)(cx+0.1*wc), (int)(cy+1.5*wc));
			g.drawLine((int)(cx+0.1*wc), (int)(cy+1.5*wc), (int)(cx+0.2*wc), (int)(cy+1.5*wc));
		} else if ((arrow&SS) == SS) {
			cx += wc; cy -= 0.2*wc;
			horizontal = false;
		} else if ((arrow&SW)==SW) {
			cx +=wc;
			g.drawLine(cx, (int)(cy+0.1*wc), (int)(cx-0.5*wc), (int)(cy+0.1*wc));
			g.drawLine((int)(cx-0.5*wc), (int)(cy+0.1*wc), (int)(cx-0.5*wc), (int)(cy+0.2*wc));
			horizontal = false;
		} else if ((arrow&SE)==SE) {
			cx += wc;
			g.drawLine((int)(cx-wc), (int)(cy+0.1*wc), (int)(cx-0.5*wc), (int)(cy+0.1*wc));
			g.drawLine((int)(cx-0.5*wc),(int)(cy+0.1*wc),(int)(cx-0.5*wc), (int)(cy+0.2*wc));
			horizontal = false;
		}

		if (!horizontal) { xP = xsP; yP = ysP; }
		int[] xT = new int[xP.length];
		int[] yT = new int[yP.length];
		xT[0] = (int)(cx+xP[0]*wc);
		yT[0] = (int)(cy+yP[0]*wc);;	
		for (k = 1; k < xP.length; k++) {
			xT[k] = (int)(cx+xP[k]*wc);
			yT[k] = (int)(cy+yP[k]*wc);
		}
		g.fillPolygon(xT,yT,xT.length);
	}
	
	private void drawString(String s, int x, int y, Graphics g) {
		boolean fitv = false;
		FontMetrics fm = null;
		g.setFont(qfFont);

		Vector sv = new Vector();
		int i,size = qfFont.getSize();
		String s1;
		float w1,w2;
		while (!fitv) {
			fm = g.getFontMetrics();
			if (((fm.stringWidth(s)*fm.getHeight())/(0.8*wc) < 0.8*wc)||
				(fm.getHeight()*15 < wc)) fitv = true;
			else g.setFont(new Font(qfFont.getName(),qfFont.getStyle(),--size));
		}
		
		while (fm.stringWidth(s) > (wc*0.8)) {
			i = 1;
			s1 = "";
			while (fm.stringWidth(s1) < (wc*0.8)) {s1 = s.substring (0,i++);}
			sv.addElement(s.substring(0,i-1).trim());
			s = s.substring(i-1).trim();
		}
		sv.addElement(s);
		int sh = fm.getHeight();
		float sy = (wc-sh*sv.size())/2;
		g.setColor(qfColor);
		for (i = 0; i < sv.size(); i++) {
			g.drawString((String)(sv.elementAt(i)), x+(wc-fm.stringWidth((String)(sv.elementAt(i))))/2, (int)(y+sy+sh*(i+1)-2));
		}
	}

	/** draw clue, string is already formatted with new lines */
	private void drawStringForm(String s, int x, int y, Graphics g) {
		int i, sh, maxW=0;
		String str;
		g.setFont(qfFont);
		FontMetrics fm = g.getFontMetrics();
		Vector sv = new Vector();
		while ((i = s.indexOf("\\n")) > 0) {
			str = s.substring(0,i);
			sv.addElement(str);
			s = s.substring(i+2);
			if (maxW < fm.stringWidth(str)) maxW = fm.stringWidth(str);
		}
		sv.addElement(s);
		if (maxW < fm.stringWidth(s)) maxW = fm.stringWidth(s);
		sh = fm.getAscent();
		float sy = (wc-sh*sv.size())/2;
		g.setColor(qfColor);
		for (i = 0; i < sv.size(); i++) {
			g.drawString((String)(sv.elementAt(i)), x+(wc-maxW)/2, (int)(y+sy+sh*(i+1)-2));
		}
	}

	/** Load crossword puzzle file with formatted clues */
	public void loadCrossword(URL fileURL) throws IOException {
		int i,j;
		int w=0,h=0,d,c,r;
		String s1 = "",s2,answer,clue,fclue;
		BufferedReader datei = new BufferedReader(new InputStreamReader(fileURL.openStream()));
		boolean skip = false;

		/* read size of crossword puzzle */	
		questions = new Vector();
		while (!skip&&((s1 = datei.readLine()) != null)) {
			if (s1.startsWith("#")) continue;
			i = s1.indexOf(',');
			if (i > 0) {
				w = Integer.parseInt(s1.substring(0,i));
				cellsX = w;
				h = Integer.parseInt(s1.substring(i+1));
				cellsY = h;
				skip = true;
			} else return;
		}
		field = new Element[h][];
		for (i = 0; i < h; i++) {
			field[i] = new Element[w];
			for (j=0;j<w;j++) field[i][j] = null;
		}

		/* read content of crossword puzzle */
		while ((s1 = datei.readLine()) != null) {
			/* comment-lines start with # */
			if (s1.startsWith("#")) continue;
			i = s1.indexOf(',');
			if (i > 0) {
				c = Integer.parseInt(s1.substring(0,i));
				s1 = s1.substring(i+1);
			} else continue;
			i = s1.indexOf('/');
			if (i > 0) {
				r = Integer.parseInt(s1.substring(0,i));
				s1 = s1.substring(i+1);
			} else continue;
			i = s1.indexOf('/');
			if (i > 0) {
				s2 = s1.substring(0,i);
				if ("ES".equals(s2)) {        d = ES;
				} else if ("SE".equals(s2)) {	d = SE;
				} else if ("EE".equals(s2)) {	d = EE;
				} else if ("EN".equals(s2)) {	d = EN;
				} else if ("SW".equals(s2)) {	d = SW;
				} else if ("SS".equals(s2)) {	d = SS;
				} else continue;
				s1 = s1.substring(i+1);
			} else continue;
			i = s1.indexOf('=');
			fclue = null;
			if (i > 0) {
				answer = s1.substring(0,i);
				j = s1.indexOf("//");
				if (j != -1) {
					clue = s1.substring(i+1,j);
					s1 = s1.substring(j+2);
					if (s1.length() > 0) fclue = s1;
				} else clue = s1.substring(i+1);
			} else continue;
			insertClueAnswer(clue,answer,fclue,r,c,d);
			questions.addElement(clue);
		} 
	}
	
	protected void insertClueAnswer(String clue, String answer, String fclue, int r, int c, int d) {
		int i,len,row=0,col=0,dir=H;
		Element elem = new Element(clue,answer,fclue,C);
		field[r][c] = elem;
		len = answer.length();
		switch (d) {
			case ES: row = r+1; col = c; dir = H; break;
			case SE: row = r; col = c+1; dir = V; break;
			case EE: row = r; col = c+1; dir = H; break;
			case EN: row = r-1; col = c; dir = H; break;
			case SW: row = r; col = c-1; dir = V; break;
			case SS: row = r+1; col = c; dir = V; break;
		} 
		
		field[r][c].t |= dir;
		field[r][c].d = d;
		if (dir == H) {
			for (i=0;i < len;i++) {
				if (field[row][col+i] != null) field[row][col+i].d |= H;
				else {
					field[row][col+i] = new Element(null,answer.substring(i,i+1),fclue,A);
					field[row][col+i].d = H;
				}
			}
			field[row][col].t |= BH|AR;
			field[row][col+len-1].t |= EH;
		} else {
			for (i=0;i < len;i++) {
				if (field[row+i][col] != null) field[row+i][col].d |= V;
				else {
					field[row+i][col] = new Element(null,answer.substring(i,i+1),fclue,A);
					field[row+i][col].d = V;
				}
			}
			field[row][col].t |= BV|AR;
			field[row+len-1][col].t |= EV;
		}
		field[row][col].a |= d;
	}
	
	class Element {
		/* clue */
		String clue;
		
		/* part of answer */
		String answer;
		
		/* formatted clue */
		String fclue;
		/* user guess */
		String g;
		
		int d;
		
		/* type */
		int t;
		
		/* arrow type */
		int a;
		
		Element(String c, String a, String fclue, int t) {
			this.clue = c;
			this.answer = a;
			this.fclue = fclue;
			this.t = t;	
		}
	}
}
