/*
	AramakiOnline
	Copyright (C) 2008 superbacker

	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 <http://www.gnu.org/licenses/>.
 */

#include "Canvas.h"
#include "MainFrame.h"
#include "World.h"
#include "Character.h"
#include "MyCharacter.h"

Canvas::Canvas(wxWindow *parent) : wxGLCanvas(parent,wxID_ANY,wxDefaultPosition,wxDefaultSize,0,wxGLCanvasName,0,wxNullPalette),movable(true),initialized(false) {
	//イベントハンドラを接続
	Connect(wxEVT_PAINT,wxPaintEventHandler(Canvas::onPaint),NULL,this);
	Connect(wxEVT_SIZE,wxSizeEventHandler(Canvas::onSize),NULL,this);
	Connect(wxEVT_KEY_DOWN,wxKeyEventHandler(Canvas::onKeyDown),NULL,this);
	Connect(wxEVT_SET_FOCUS,wxFocusEventHandler(Canvas::onSetFocus),NULL,this);
	Connect(wxEVT_KILL_FOCUS,wxFocusEventHandler(Canvas::onKillFocus),NULL,this);
	Connect(wxEVT_IDLE,wxIdleEventHandler(Canvas::onIdle),NULL,this);
}

Canvas::~Canvas() {
	if (initialized) Character::finalize();

	//イベントハンドラを切断
	Disconnect(wxEVT_PAINT,wxPaintEventHandler(Canvas::onPaint),NULL,this);
	Disconnect(wxEVT_SIZE,wxSizeEventHandler(Canvas::onSize),NULL,this);
	Disconnect(wxEVT_KEY_DOWN,wxKeyEventHandler(Canvas::onKeyDown),NULL,this);
	Disconnect(wxEVT_SET_FOCUS,wxFocusEventHandler(Canvas::onSetFocus),NULL,this);
	Disconnect(wxEVT_KILL_FOCUS,wxFocusEventHandler(Canvas::onKillFocus),NULL,this);
	Disconnect(wxEVT_IDLE,wxIdleEventHandler(Canvas::onIdle),NULL,this);
}

void Canvas::render() {
#ifndef __WXMOTIF__
	if (!GetContext()) return;
#endif

	SetCurrent();

	if (!initialized) {
		initGL();
		initialized=true;
	}

	glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

	if (World::isLoggingIn()) World::getInstance().render();

	//画面に表示
	glFlush();
	SwapBuffers();
}

void Canvas::onPaint(wxPaintEvent &) {
	wxPaintDC(this);
}

void Canvas::onSize(wxSizeEvent &event) {
	wxGLCanvas::OnSize(event);

#ifndef __WXMOTIF__
	if (!GetContext()) return;
#endif

	resetProjectionMode();
}

void Canvas::initGL() {
	//ライト位置
	static const float lightPosition[]={0,20,19,0};
	//環境光
	static const float lightAmbient[]={0.25,0.25,0.25};

	//デプステストを有効に
	glEnable(GL_DEPTH_TEST);

	//テクスチャのAlpha50%以上のピクセルしか表示しない
	glEnable(GL_ALPHA_TEST);
	glAlphaFunc(GL_GREATER,0.5);

	//片面表示をオンに
	glEnable(GL_CULL_FACE);

	//ライトを設定・有効に
	glLightfv(GL_LIGHT0,GL_POSITION,lightPosition);
	glLightfv(GL_LIGHT0,GL_AMBIENT,lightAmbient);
	glEnable(GL_LIGHTING);
	glEnable(GL_LIGHT0);

	//アルファブレンド
	//glEnable(GL_BLEND);
	//glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);

	resetProjectionMode();

	Character::initialize();
}

void Canvas::checkKeyInput(int frameCount) const {
	//キー入力をチェックする
	if (World::isLoggingIn()) {
		if (wxGetKeyState(WXK_UP)) for (int i=0;i<frameCount;++i) MyCharacter::getInstance().goAhead();
		if (wxGetKeyState(WXK_LEFT)) for (int i=0;i<frameCount;++i) MyCharacter::getInstance().turnLeft();
		if (wxGetKeyState(WXK_RIGHT)) for (int i=0;i<frameCount;++i) MyCharacter::getInstance().turnRight();
		if (wxGetKeyState(WXK_DOWN)) for (int i=0;i<frameCount;++i) MyCharacter::getInstance().goBack();
	}
}

void Canvas::resetProjectionMode() {
	int w,h;

	//クライアント領域のサイズを取得
	GetClientSize(&w,&h);

	//行列を再設定
	glViewport(0,0,w,h);

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();

	//視点を設定
	gluPerspective(60,(double)w/h,1,80);
	gluLookAt(0,1.5,5,0,1.5,0,0,1,0);

	glMatrixMode(GL_MODELVIEW);
}

void Canvas::onSetFocus(wxFocusEvent &) {
	delayStopWatch.Start(0);
	movable=true;
}

void Canvas::onKillFocus(wxFocusEvent &) {
	movable=false;
}

void Canvas::onKeyDown(wxKeyEvent &event) {
	if (event.GetKeyCode()==WXK_TAB) {
		//発言入力欄にフォーカスをセット
		MainFrame::getInstance().setFocusToMessageEdit();
	}
}

void Canvas::onIdle(wxIdleEvent &event) {
	//TODO comment
	if (delayStopWatch.Time()>WAIT) {
		int frameCount=delayStopWatch.Time()/WAIT;
		delayStopWatch.Start(delayStopWatch.Time()%WAIT);
		if (movable) checkKeyInput(frameCount);
		render();
	}

	wxMilliSleep(WAIT-delayStopWatch.Time()%WAIT);

	event.RequestMore();
}
