// Copyright 2005, Danger, Inc.  All Rights Reserved.
// This file is subject to the Danger, Inc. Sample Code License,
// which is provided in the file SAMPLE_CODE_LICENSE.
// Copies are also available from http://developer.danger.com/

package com.danger.text;

import danger.ui.*;
import danger.util.*;
import danger.text.span.*;
import danger.app.Timer;
import danger.app.Event;

/**
 * This window has a text box that works like the IM chat history.
 */
public class
Conversation
extends DemoWindow
{
	public
	Conversation()
	{
		LogTextBox ltb = new LogTextBox();

		ltb.setSize(getWidth(), getHeight());
		ltb.setBorderShowsScrolling(true);
		ltb.show();
		ltb.setGrowFromBottom(true);
		ltb.setBlankAfterFinalNewline(false);
		addChild(ltb);
		setFocusedChild(ltb);

		Scrollbar sb = new Scrollbar();
		sb.setSize(2, getHeight() - 4);
		sb.setPosition(getWidth() - 2, 2);
		sb.show();
		addChild(sb);
		ltb.attachScrollbar(sb);

		setTitle(getApplication().getString(Resources.ID_DEMO_CONVERSATION));

		mLog = ltb;
		mConversation = getApplication().getResources().getStringArray(Resources.ID_CONVERSATION);

		new Timer(500, false, this, 0, null).start();
	}

	public boolean
	receiveEvent(Event e)
	{
		if (e.type == Event.EVENT_TIMER)
		{
			if (e.data + 1 < mConversation.length && isVisible())
				new Timer(DELAY, false, this, e.data + 1, null).start();

			SpannableString ss = new SpannableString(mConversation[e.data] + '\r');
			ConversationSpan cs;

			if (e.data % 2 == 1)
				cs = new ConversationSpan(Resources.ID_OUTGOING, 0);
			else
				cs = new ConversationSpan(Resources.ID_INCOMING, Font.F_BOLD);

			ss.setSpan(cs, 0, ss.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE | Spannable.SPAN_DELETE_ON_EMPTY | Spannable.SPAN_PARAGRAPH);
			mLog.append(ss);

			return true;
		}

		return super.receiveEvent(e);
	}

	/**
	 * This class provides both the marginal arrow and the style change
	 * for incoming or outgoing messages.  These two functions could be
	 * handled separately, but since there is a per-object cost, it seems
	 * better to do both at once and spend only one object per incoming
	 * or outgoing message instead of two.
	 */
	private class
	ConversationSpan
	extends StyleSpan.Standard
	implements LeftMarginSpan
	{
		public
		ConversationSpan(int bitmap, int style)
		{
			super(style);

			mBitmap = bitmap;
			mBitmapWidth = getApplication().getResources().getBitmap(mBitmap).getWidth();
		}

		public int
		modifyLeftMargin(int margin, Object[] spans, Font f, CharSequence text, int parStart, int lineStart, int paragraphDistance)
		{
			// The return value from modifyLeftMargin() is the total
			// size of the new margin.

			return margin + mBitmapWidth + GAP;
		}

		public int
		drawLeftMargin(Pen p, int x, int top, int baseline, int bottom, Object[] spans, CharSequence text, int parStart, int lineStart, int paragraphDistance, Object[] characterSpans)
		{
			Bitmap b = getApplication().getResources().getBitmap(mBitmap);

			// The reason for this call is to cause the selection highlight
			// to be drawn in the margin if the selection crosses the
			// start of this line.

			CharacterSpan.Set.drawBlank(p, x, mBitmapWidth + GAP, top, baseline, bottom, characterSpans);

			// The reason for this check is that the arrow in the margin
			// is only drawn on the first line of each incoming or
			// outgoing message.  If you want to have something special
			// happen for the first line of each paragraph, you can also
			// check if lineStart == parStart.

			if (lineStart == ((Spanned) text).getSpanStart(this))
				p.drawBitmap(x, baseline - b.getHeight(), b);

			// The return value from drawLeftMargin() is, in contrast,
			// the increment to the margin.

			return mBitmapWidth + GAP;
		}

		private int mBitmap;
		private int mBitmapWidth;

		private static final int GAP = 2;
	}

	private String[] mConversation;
	private LogTextBox mLog;

	private static final int DELAY = 2000;
}
