/*

Setup for build:

    sudo apt-get install libsdl1.2-dev

Configure running MC4 on boot:

    sudo nano /etc/rc.local

Break on pure virtual:
    
    break __cxa_pure_virtual


*/

#include "lgi/common/Lgi.h"
#include "lgi/common/Button.h"
#include "lgi/common/DisplayString.h"
#include "lgi/common/CssTools.h"
#include "lgi/common/LgiRes.h"
#include "lgi/common/SubProcess.h"

#include "resdefs.h"
#include "mc4.h"
#include "TouchKbd.h"
#include "Hardware.h"
#include "WebThread.h"

#define DEBUG_TEST_TOUCH_KBD	0
#define DEBUG_SHOW_MOUSE        0

//////////////////////////////////////////////////////////////////
const char *AppName = "mc4";

class CmdThread : public LThread
{
public:
	CmdThread() : LThread("CmdThread")
	{
		Run();
	}
	
	int Main()
	{
		const char *Cmds[] = {
			"xset s off",
			"xset -dpms"
		};
		
		for (int i=0; i<CountOf(Cmds); i++)
		{
			auto c = LString(Cmds[i]).Split(" ", 1);
			LSubProcess p(c[0], c[1]);
			if (p.Start())
			{
				p.Wait();
				printf("Done: '%s' '%s'\n", c[0].Get(), c[1].Get());
			}			
		}		
		
		return 0;
	}
};

class App : public LWindow
{
	Mc4SharedData _Priv;

protected:
	Mc4Logic *Logic;
	Mc4Ui *Ui;
	Hardware *Hw;
	Mc4Shared Shared;
	LAutoPtr<WebThread> WebSrv;
	LAutoPtr<CmdThread> Cmds;
	
public:
    App() : Shared(&_Priv)
    {
		Logic = NULL;
		Ui = NULL;
		LAppInst->AppWnd = this;
		
        Name(AppName);

		#if RPI
		LRect pos = HW_SCREEN.ZeroTranslate();
		SetPos(pos);
		#else
		LRect pos(0, 0, 1199, 999);
		SetPos(pos);
		MoveToCenter();
		#endif

		Shared.SetMaxLock(DEBUG_MAX_LOCK_MS);

        SetQuitOnClose(true);

        if (Attach(0))
        {
			Logic = new Mc4Logic(&Shared);
			
			printf("Creating hardware interface...\n");
			Hw = new Hardware(Logic, &Shared);
			LAssert(Hw != NULL);

			printf("Creating UI object...\n");
			Ui = new Mc4Ui(Hw, &Shared);

			Hw->SetInterface(Ui);
			Logic->SetInterfaces(Hw, Ui);
			
			if (Hw->GetInterface())
			{
				auto cli = GetClient();
				Hw->GetInterface()->SetPos(cli);
				Hw->GetInterface()->Attach(this);
			}
			else
				Ui->Attach(this);
			
			Hw->Run();

            Visible(true);
        }

		RegisterHook(Ui, LKeyEvents);			
		WebSrv.Reset(new WebThread(&Shared, Ui));
		
		#if RPI
		Cmds.Reset(new CmdThread());
		SetDecor(false);
		SetZoom(LZoomMax);
		#endif
    }
    
    ~App()
    {
		Ui->OnShutdown();
		DeleteObj(Hw);
		DeleteObj(Ui);
    }
    
    const char *GetClass()
    {
		return "App";
    }

	void OnPosChange()
	{
		if (Children.Length() > 0)
		{
			auto v = Children[0];
			auto c = GetClient();
			v->SetPos(c);
		}
	}
    
    const char *GetResourcePath()
    {
		return Ui->GetResourcePath();
    }
    
    bool OnKey(LKey &k)
    {
		if (Ui)
			return Ui->OnKey(k);
		return false;
    }
    
    #if 0
    void _Paint(LSurface *pDC = NULL, GdcPt2 *Offset = NULL, LRegion *Update = NULL)
    {
		LWindow::_Paint(pDC, Offset, Update);
		// OnPaint(pDC);
		
		if (ScreenDC)
		{
        	#if RPI
        	LWindow *Current = Ui;
			#endif
			if (Current && Current->Visible())
			{
				Current->_Paint(ScreenDC, NULL, Update);
			}
			else
			{
			    printf("Current=%p Vis=%i\n", 
			        Current, Current?Current->Visible():0);
				ScreenDC->Colour(Rgb24(0, 0, 0), 24);
				ScreenDC->Rectangle();
				ScreenDC->Colour(Rgb24(255, 0, 0), 24);
				ScreenDC->Line(0, 0, ScreenDC->X()-1, ScreenDC->Y()-1);
				ScreenDC->Line(ScreenDC->X()-1, 0, 0, ScreenDC->Y()-1);
			}
			
			pDC->Blt(0, 0, ScreenDC);
		}
    }
    #endif
	
	void Rect(LSurface *pDC, int x1, int y1, int x2, int y2, uint32_t col)
	{
		for (int y=y1; y<=y2; y++)
		{
			uint32_t *p = (uint32_t*) (*pDC)[y];
			if (p)
			{
				for (int x=x1; x<=x2; x++)
				{
					p[x] = col;
				}
			}
		}
	}

    void OnPaint(LSurface *pDC)
    {
		LCssTools t(GetCss(), LSysFont);
		LRect c = GetClient();
		t.PaintBorderAndPadding(pDC, c);
		
		#if 0
		LColour Back = t.GetBack();
		if (Back.IsValid())
		{
			pDC->Colour(Back);
			pDC->Rectangle(&c);
		}
		#else
		pDC->Colour(L_LOW);
		pDC->Rectangle(&c);
		#endif
		
		#if 0
		int x = 400;
		Rect(pDC, x, 10, x+10, 20, 0xff000000);
		x += 20;
		Rect(pDC, x, 10, x+10, 20, 0x00ff0000);
		x += 20;
		Rect(pDC, x, 10, x+10, 20, 0x0000ff00);
		x += 20;
		Rect(pDC, x, 10, x+10, 20, 0x000000ff);
		#endif
    }
};

//////////////////////////////////////////////////////////////////
// sudo TSLIB_FBDEVICE=/dev/fb1 TSLIB_TSDEVICE=/dev/input/touchscreen ts_test

#if RPI
#include <sys/vt.h>
#include <sys/kd.h>
#include <sys/ioctl.h>
#endif

class Mc4App : public LApp
{
public:
    Mc4App
    (
		/// The arguments passed in by the OS.
		OsAppArguments &AppArgs,
		/// The application's name.
		const char *AppName,
		/// Optional args
		LAppArguments *ObjArgs = 0
	) :
	    LApp(AppArgs, AppName, ObjArgs)
    {
    }
    
    ~Mc4App()
    {
    }
};

int LgiMain(OsAppArguments &AppArgs)
{
	#if RPI

		if (AppArgs.Get("reset"))
	    {
        	int r = ioctl(0, KDSETMODE, KD_TEXT);
        	printf("ioctl=%i\n", r);
	        return 0;
	    }

		// We are running on the Raspberry PI, so the screen is just the physical hardware
		setenv("SDL_VIDEODRIVER", "fbcon", true);
		setenv("SDL_FBDEV", "/dev/fb1", true);
		setenv("SDL_MOUSEDEV", "/dev/input/touchscreen", true);
		setenv("SDL_MOUSEDRV", "TSLIB", true);

		#if 1
		// Normal run-time
		AppArgs.Set("mc4 -screen 320x240");
		#else
		// Testing non-GUI stuff...
		AppArgs.Set("mc4 -novid");
		#endif
		
	#else

		// Otherwise we are running on a desktop machine and we need much more real estate
		// to render all the other little controls and so on.
		AppArgs.Set("mc4 -screen 1000x500");

	#endif

	Mc4App a(AppArgs, "mc4");
	auto app = LAppInst;

	if (a.IsOk())
	{
		LFile::Path p(LSP_APP_INSTALL);
		p += "../resources/mc4.lr8";
		if (p.IsFile())
			LgiGetResObj(false, p.GetFull());
		
		LAppInst->AppWnd = new App;

		#if DEBUG_TEST_TOUCH_KBD
		TouchKeyboard kbd(TheApp->GetResourcePath(), TouchKeyboard::KbdNumbers);
		kbd.SetParent(TheApp);
		kbd.MoveSameScreen(TheApp);
		if (kbd.DoModal())
		{
			LgiTrace("Kbd='%s'\n", kbd.Name());
		}		
		#endif
		
		#if 0
		LgiMsg(TheApp, "Test Message", "Title");
		#endif

		a.Run();
	}

	return 0;
}

