package jp.sourceforge.nicoro;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Random;

import jp.sourceforge.nicoro.MessageChat;
import jp.sourceforge.nicoro.MessageChatController;
import jp.sourceforge.nicoro.PlayerConstants;

import android.graphics.Paint;
import android.test.AndroidTestCase;

public class MessageChatTest extends AndroidTestCase {

	@Override
	protected void setUp() throws Exception {
		super.setUp();
	}

	@Override
	protected void tearDown() throws Exception {
		super.tearDown();
	}

	public void testShitaY() {
		Paint paint = new Paint();

		MessageChat chat = new MessageChat("medium shita", 0, 0, 0L, "", 0);
		chat.computeLineHeight(paint);
		int fontSize = chat.getFontSize();
		assertEquals(MessageChat.FONTSIZE_PX_MEDIUM, fontSize);
		paint.setTextSize(fontSize);
		float ascent = paint.ascent();
		assertTrue(ascent < 0.0f);
		float descent = paint.descent();
		assertTrue(descent > 0.0f);

		assertEquals(0, chat.getY());
		assertEquals(0.0f, chat.getDrawY());
//		assertEquals(-fontSize, chat.getNextY());

		int lineHeight = chat.getSingleLineHeight() + MessageChat.MARGIN_NEXT;
		assertEquals(PlayerConstants.REAL_PLAYER_HEIGHT_PX_4_3 - lineHeight,
				chat.setY(PlayerConstants.REAL_PLAYER_HEIGHT_PX_4_3, paint));
		assertEquals(PlayerConstants.REAL_PLAYER_HEIGHT_PX_4_3 - lineHeight,
				chat.getNextY());
		assertEquals(PlayerConstants.REAL_PLAYER_HEIGHT_PX_4_3, chat.getY());
		assertEquals(PlayerConstants.REAL_PLAYER_HEIGHT_PX_4_3 - descent,
				chat.getDrawY());
	}

	public void testComputeShitaNextY() {
		Paint paint = new Paint();

		MessageChat chat1 = new MessageChat("medium shita", 0, 1, 0L, "", 0);
		MessageChat chat2 = new MessageChat("medium shita", 0, 2, 0L, "", 0);
		MessageChat chat3 = new MessageChat("medium shita", 0, 3, 0L, "", 0);
		chat1.computeLineHeight(paint);
		chat2.computeLineHeight(paint);
		chat3.computeLineHeight(paint);
		int fontSize = chat1.getFontSize();
        int fontSizeType = chat1.getFontSizeType();
		assertEquals(MessageChat.FONTSIZE_PX_MEDIUM, fontSize);
        assertEquals(MessageChat.FONTSIZE_TYPE_MEDIUM, fontSizeType);
		assertEquals(fontSize, chat2.getFontSize());
		assertEquals(fontSize, chat3.getFontSize());
        assertEquals(fontSizeType, chat2.getFontSizeType());
        assertEquals(fontSizeType, chat3.getFontSizeType());

		LinkedList<MessageChat> chats = new LinkedList<MessageChat>();
		Random random = new Random();

		int lineHeight = chat1.getSingleLineHeight() + MessageChat.MARGIN_NEXT;
		int nextY = chat1.computeShitaNextY(chats, random);
		assertEquals(PlayerConstants.REAL_PLAYER_HEIGHT_PX_4_3, nextY);
		assertEquals(nextY - lineHeight,
				chat1.setY(nextY, paint));

		chats.add(chat1);
		nextY = chat2.computeShitaNextY(chats, random);
		assertEquals(PlayerConstants.REAL_PLAYER_HEIGHT_PX_4_3 - lineHeight, nextY);
		assertEquals(nextY - lineHeight,
				chat2.setY(nextY, paint));

		chats.add(chat2);
		nextY = chat3.computeShitaNextY(chats, random);
		assertEquals(PlayerConstants.REAL_PLAYER_HEIGHT_PX_4_3 - lineHeight * 2, nextY);
		assertEquals(nextY - lineHeight,
				chat3.setY(nextY, paint));
	}

	public void testComputeUeNextY() {
		Paint paint = new Paint();

		MessageChat chat1 = new MessageChat("medium ue", 0, 1, 0L, "", 0);
		MessageChat chat2 = new MessageChat("medium ue", 0, 2, 0L, "", 0);
		MessageChat chat3 = new MessageChat("medium ue", 0, 3, 0L, "", 0);
		chat1.computeLineHeight(paint);
		chat2.computeLineHeight(paint);
		chat3.computeLineHeight(paint);
		int fontSize = chat1.getFontSize();
		int fontSizeType = chat1.getFontSizeType();
		assertEquals(MessageChat.FONTSIZE_PX_MEDIUM, fontSize);
        assertEquals(MessageChat.FONTSIZE_TYPE_MEDIUM, fontSizeType);
		assertEquals(fontSize, chat2.getFontSize());
		assertEquals(fontSize, chat3.getFontSize());
        assertEquals(fontSizeType, chat2.getFontSizeType());
        assertEquals(fontSizeType, chat3.getFontSizeType());

		LinkedList<MessageChat> chats = new LinkedList<MessageChat>();
		Random random = new Random();

		int lineHeight = chat1.getSingleLineHeight() + MessageChat.MARGIN_NEXT;
		int nextY = chat1.computeUeNextY(chats, random);
		assertEquals(0, nextY);
		assertEquals(nextY + lineHeight,
				chat1.setY(nextY, paint));

		chats.add(chat1);
		nextY = chat2.computeUeNextY(chats, random);
		assertEquals(lineHeight, nextY);
		assertEquals(nextY + lineHeight,
				chat2.setY(nextY, paint));

		chats.add(chat2);
		nextY = chat3.computeUeNextY(chats, random);
		assertEquals(lineHeight * 2, nextY);
		assertEquals(nextY + lineHeight,
				chat3.setY(nextY, paint));
	}

	public void testComputeNakaNextY1() {
		Paint paint = new Paint();
		MessageChatController controller = new MessageChatController();

		MessageChat chat1 = new MessageChat("medium naka", 0, 1, 0L, "", 0);
		chat1.setText("foo");
		chat1.prepareAdd(controller, paint, 0);
		MessageChat chat2 = new MessageChat("medium naka", 0, 2, 0L, "", 0);
		chat2.setText("foo");
		chat2.prepareAdd(controller, paint, 0);
		MessageChat chat3 = new MessageChat("medium naka", 0, 3, 0L, "", 0);
		chat3.setText("foo");
		chat3.prepareAdd(controller, paint, 0);
		int fontSize = chat1.getFontSize();
		int fontSizeType = chat1.getFontSizeType();
		assertEquals(MessageChat.FONTSIZE_PX_MEDIUM, fontSize);
        assertEquals(MessageChat.FONTSIZE_TYPE_MEDIUM, fontSizeType);
		assertEquals(fontSize, chat2.getFontSize());
		assertEquals(fontSize, chat3.getFontSize());
        assertEquals(fontSizeType, chat2.getFontSizeType());
        assertEquals(fontSizeType, chat3.getFontSizeType());

		LinkedList<MessageChat> chats = new LinkedList<MessageChat>();
		Random random = new Random();

		int lineHeight = chat1.getSingleLineHeight() + MessageChat.MARGIN_NEXT;
		int nextY = chat1.computeNakaNextY(0, chats, random);
		assertEquals(0, nextY);
		assertEquals(nextY + lineHeight,
				chat1.setY(nextY, paint));

		chats.add(chat1);
		nextY = chat2.computeNakaNextY(0, chats, random);
		assertEquals(lineHeight, nextY);
		assertEquals(nextY + lineHeight,
				chat2.setY(nextY, paint));

		chats.add(chat2);
		nextY = chat3.computeNakaNextY(0, chats, random);
		assertEquals(lineHeight * 2, nextY);
		assertEquals(nextY + lineHeight,
				chat3.setY(nextY, paint));
	}

	public void testComputeNakaNextY2() {
		Paint paint = new Paint();

		MessageChat chat1 = new MessageChat("medium naka", 0, 1, 0L, "", 0);
		chat1.setText("foo");
		chat1.computeWidth(paint);
		chat1.computeSpeed();
		chat1.computeLineHeight(paint);
		MessageChat chat2 = new MessageChat("medium naka", 100, 2, 0L, "", 0);
		chat2.setText("foo");
		chat2.computeWidth(paint);
		chat2.computeSpeed();
		chat2.computeLineHeight(paint);
		MessageChat chat3 = new MessageChat("medium naka", 200, 3, 0L, "", 0);
		chat3.setText("foo");
		chat3.computeWidth(paint);
		chat3.computeSpeed();
		chat3.computeLineHeight(paint);
		int fontSize = chat1.getFontSize();
        int fontSizeType = chat1.getFontSizeType();
		assertEquals(MessageChat.FONTSIZE_PX_MEDIUM, fontSize);
        assertEquals(MessageChat.FONTSIZE_TYPE_MEDIUM, fontSizeType);
		assertEquals(fontSize, chat2.getFontSize());
		assertEquals(fontSize, chat3.getFontSize());
        assertEquals(fontSizeType, chat2.getFontSizeType());
        assertEquals(fontSizeType, chat3.getFontSizeType());

		LinkedList<MessageChat> chats = new LinkedList<MessageChat>();
		Random random = new Random();

		int lineHeight = chat1.getSingleLineHeight() + MessageChat.MARGIN_NEXT;
		int nextY = chat1.computeNakaNextY(0, chats, random);
		assertEquals(0, nextY);
		assertEquals(nextY + lineHeight,
				chat1.setY(nextY, paint));

		chats.add(chat1);
		nextY = chat2.computeNakaNextY(100, chats, random);
		assertEquals(0, nextY);
		assertEquals(nextY + lineHeight,
				chat2.setY(nextY, paint));

		chats.add(chat2);
		nextY = chat3.computeNakaNextY(200, chats, random);
		assertEquals(0, nextY);
		assertEquals(nextY + lineHeight,
				chat3.setY(nextY, paint));
	}

	public void testAddShitaOrder() {
		Paint paint = new Paint();

		MessageChat chat1 = new MessageChat("medium shita", 0, 1, 0L, "", 0);
		MessageChat chat2 = new MessageChat("medium shita", 0, 2, 0L, "", 0);
		MessageChat chat3 = new MessageChat("medium shita", 0, 3, 0L, "", 0);
		chat1.computeLineHeight(paint);
		chat2.computeLineHeight(paint);
		chat3.computeLineHeight(paint);
		int lineHeight = chat1.getSingleLineHeight() + MessageChat.MARGIN_NEXT;

		LinkedList<MessageChat> chats = new LinkedList<MessageChat>();
		Random random = new Random();
		int nextY = chat1.computeShitaNextY(chats, random);
		assertEquals(nextY - lineHeight,
				chat1.setY(nextY, paint));

		chat1.addShitaOrder(chats);
		assertEquals(chat1, chats.get(0));

		nextY = chat2.computeShitaNextY(chats, random);
		assertEquals(nextY - lineHeight,
				chat2.setY(nextY, paint));

		chat2.addShitaOrder(chats);
		assertEquals(chat2, chats.get(1));

		nextY = chat3.computeShitaNextY(chats, random);
		assertEquals(nextY - lineHeight,
				chat3.setY(nextY, paint));

		chat3.addShitaOrder(chats);
		assertEquals(chat3, chats.get(2));

		chats.remove(chat1);
		MessageChat chat4 = new MessageChat("big shita", 0, 4, 0L, "", 0);
		chat4.computeLineHeight(paint);
		assertEquals(MessageChat.FONTSIZE_PX_BIG, chat4.getFontSize());
        assertEquals(MessageChat.FONTSIZE_TYPE_BIG, chat4.getFontSizeType());
		int lineHeightBig = chat4.getSingleLineHeight() + MessageChat.MARGIN_NEXT;

		nextY = chat4.computeShitaNextY(chats, random);
		assertEquals(chat3.getNextY(), nextY);
		assertEquals(nextY - lineHeightBig,
				chat4.setY(nextY, paint));
		chat4.addShitaOrder(chats);
		assertEquals(chat4, chats.get(2));

		MessageChat chat5 = new MessageChat("medium shita", 0, 5, 0L, "", 0);
		chat5.computeLineHeight(paint);
		int lineHeightMedium = chat5.getSingleLineHeight() + MessageChat.MARGIN_NEXT;
		nextY = chat5.computeShitaNextY(chats, random);
		assertEquals(PlayerConstants.REAL_PLAYER_HEIGHT_PX_4_3, nextY);
		assertEquals(nextY - lineHeightMedium,
				chat5.setY(nextY, paint));
		chat5.addShitaOrder(chats);
		assertEquals(chat5, chats.get(0));
	}

	public void testComputeSpeed() {
		Paint paint = new Paint();

		MessageChat chat = new MessageChat("medium naka", 0, 0, 0L, "", 0);
		chat.setText("");
		chat.computeWidth(paint);
		assertEquals(0, chat.getWidth());

		chat.computeSpeed();
		assertEquals((float) -PlayerConstants.REAL_PLAYER_WIDTH_PX_4_3 / (float) MessageChat.DISPLAY_TIME_VPOS_NAKA,
				chat.getSpeed());

		chat.setText("ニコニコ");
		float[] widths = new float[4];
		chat.computeWidth(paint);
		assertEquals(4, paint.getTextWidths("ニコニコ", widths));
		float sumWidths = widths[0] + widths[1] + widths[2] + widths[3];
		assertEquals((int) sumWidths, chat.getWidth());

		chat.computeSpeed();
		assertEquals((float) -(PlayerConstants.REAL_PLAYER_WIDTH_PX_4_3 + sumWidths) / (float) MessageChat.DISPLAY_TIME_VPOS_NAKA,
				chat.getSpeed());
	}

	public void testInitializeX() {
		MessageChat chat = new MessageChat("medium naka", 500, 0, 0L, "", 0);
		chat.setText("a");

		chat.initializeX(650);
		assertEquals(chat.computeX(650), chat.getDrawX());
	}

	public void testFontSize() {
	    checkFontSize(MessageChat.FONTSIZE_PX_BIG, MessageChat.LINEHEIGHT_PX_BIG);
        checkFontSize(MessageChat.FONTSIZE_PX_MEDIUM, MessageChat.LINEHEIGHT_PX_MEDIUM);
        checkFontSize(MessageChat.FONTSIZE_PX_SMALL, MessageChat.LINEHEIGHT_PX_SMALL);
        checkFontSize(MessageChat.FONTSIZE_PX_SMALL_BIG, MessageChat.LINEHEIGHT_PX_SMALL_BIG);
        checkFontSize(MessageChat.FONTSIZE_PX_SMALL_MEDIUM, MessageChat.LINEHEIGHT_PX_SMALL_MEDIUM);
        checkFontSize(MessageChat.FONTSIZE_PX_SMALL_SMALL, MessageChat.LINEHEIGHT_PX_SMALL_SMALL);
	}

	private void checkFontSize(int fontSize, int height) {
        Paint paint = new Paint();

        paint.setTextSize(fontSize);
        float fontHeight = paint.descent() - paint.ascent();
        if (fontHeight < fontSize) {
            fail("fontHeight=" + fontHeight + ", but fontSize=" + fontSize);
        }
        if (fontHeight > height + 0.5f) {
            fail("fontHeight=" + fontHeight + ", but height=" + height);
        }
	}

	public void testApplyNgCommand() {
        MessageChat chat = new MessageChat("big shita", 0, 0, 0L, "", 0);
        int fontSize = chat.getFontSize();
        assertEquals(MessageChat.FONTSIZE_PX_BIG, fontSize);
        int pos = chat.getPos();
	    assertEquals(MessageChat.POS_SHITA, pos);

	    ArrayList<ConfigureNgClient.NgClient> ngCommands = new ArrayList<ConfigureNgClientInterface.NgClient>();
	    ngCommands.add(new ConfigureNgClient.NgClient(
	            ConfigureNgClientInterface.NG_TYPE_COMMAND, "big"));
	    chat.applyNgCommand(ngCommands);
        fontSize = chat.getFontSize();
        assertEquals(MessageChat.FONTSIZE_PX_MEDIUM, fontSize);
        pos = chat.getPos();
        assertEquals(MessageChat.POS_SHITA, pos);

        ngCommands.clear();
        ngCommands.add(new ConfigureNgClient.NgClient(
                ConfigureNgClientInterface.NG_TYPE_COMMAND, "shita"));
        chat.applyNgCommand(ngCommands);
        fontSize = chat.getFontSize();
        assertEquals(MessageChat.FONTSIZE_PX_BIG, fontSize);
        pos = chat.getPos();
        assertEquals(MessageChat.POS_NAKA, pos);

        ngCommands.clear();
        ngCommands.add(new ConfigureNgClient.NgClient(
                ConfigureNgClientInterface.NG_TYPE_COMMAND, "all"));
        chat.applyNgCommand(ngCommands);
        fontSize = chat.getFontSize();
        assertEquals(MessageChat.FONTSIZE_PX_MEDIUM, fontSize);
        pos = chat.getPos();
        assertEquals(MessageChat.POS_NAKA, pos);

        // nullチェック
        chat = new MessageChat(null, 0, 0, 0L, "", 0);
        chat.applyNgCommand(ngCommands);
	}
}
