/*
**	$Id: Application.cpp 1.7 1995/12/03 12:16:23 olsen Exp olsen $
**
**	:ts=4
*/

/*
 * Copyright © 1995 by Olaf Barthel, All Rights Reserved
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO
 * EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * This software has not been validated by the ``Bundesamt fuer Zulassungen in
 * der Telekommunikation'' of the ``Deutsche Bundepost Telekom'' and thus
 * must not be used for accessing the BTX-Network of the Telekom in Germany.
 *
 * Diese Software hat keine Zulassung durch das Bundesamt fuer Zulassungen in
 * der Telekommunikation der Deutschen Bundespost Telekom und darf daher nicht
 * am Netz der Deutschen Bundespost Telekom in Deutschland betrieben werden.
 */

/****************************************************************************/

#include <dos/dosextens.h>

#include <clib/exec_protos.h>
#include <clib/dos_protos.h>

#ifdef __SASC
#include <pragmas/exec_pragmas.h>
#include <pragmas/dos_pragmas.h>

extern struct ExecBase		*SysBase;
extern struct DosLibrary	*DOSBase;
#endif	// _SASC

#include <stdio.h>

/****************************************************************************/

#ifndef _APPLICATION_HPP
#include "Application.hpp"
#endif

/****************************************************************************/

#define D(x)

/****************************************************************************/

Application::Application()
{
	AppChannel	= NULL;
	AppService	= NULL;
	AppDisplay	= NULL;
	AppModem	= NULL;
}

Application::~Application()
{
	Close();
}

VOID Application::Close(VOID)
{
	if(AppDisplay)
	{
		delete AppDisplay;
		AppDisplay = NULL;
	}

	if(AppChannel)
	{
		delete AppChannel;
		AppChannel = NULL;
	}

	if(AppService)
	{
		delete AppService;
		AppService = NULL;
	}

	if(AppModem)
	{
		delete AppModem;
		AppModem = NULL;
	}
}

STRPTR Application::Open(STRPTR PubScreen,int XScale,int YScale,BOOL TextOnly,BOOL Direct,CONST STRPTR Channel,ULONG Unit,ULONG Baud,BOOL RTS_CTS)
{
	IOChannel	*ThisChannel;
	BTXDisplay	*ThisDisplay;
	BOOL		 IsSerial;

	if(ThisChannel = new IOFile)
	{
		IsSerial = FALSE;

		if(ThisChannel->Open(Channel))
		{
			delete ThisChannel;
			ThisChannel = NULL;
		}
	}

	if(!ThisChannel)
	{
		if(ThisChannel = new IOSerial)
		{
			IsSerial = TRUE;

			if(ThisChannel->Open(Channel,Unit,Baud,RTS_CTS))
			{
				delete ThisChannel;
				ThisChannel = NULL;
			}
		}
	}

	if(ThisChannel)
	{
		if(TextOnly)
			ThisDisplay = new TextDisplay;
		else
			ThisDisplay = new GfxDisplay;

		if(ThisDisplay)
		{
			if(ThisDisplay->Open(PubScreen,XScale,YScale,Direct))
			{
				delete ThisDisplay;
				ThisDisplay = NULL;
			}
		}

		if(!ThisDisplay)
		{
			if(ThisDisplay = new TextDisplay)
			{
				if(ThisDisplay->Open(PubScreen,XScale,YScale,Direct))
				{
					delete ThisDisplay;
					ThisDisplay = NULL;
				}
			}
		}

		if(ThisDisplay)
		{
			if(IsSerial)
			{
				if(AppModem = new ModemService)
				{
					if(AppModem->Open(ThisChannel,ThisDisplay))
					{
						delete AppModem;
						AppModem = NULL;
					}
				}

				if(!AppModem)
				{
					delete ThisChannel;
					ThisChannel = NULL;

					delete ThisDisplay;
					ThisDisplay = NULL;

					return("Error opening modem service.");
				}
			}

			if(AppService = new BTXService)
			{
				if(AppService->Open(ThisDisplay,this))
				{
					delete AppService;
					AppService = NULL;
				}
			}

			if(AppService)
			{
				AppChannel = ThisChannel;
				AppDisplay = ThisDisplay;

				return(NULL);
			}
			else
			{
				delete AppModem;
				AppModem = NULL;

				delete AppChannel;
				AppChannel = NULL;

				delete AppDisplay;
				AppDisplay = NULL;

				return("Error opening BTX service.");
			}
		}
		else
		{
			delete ThisChannel;

			return("Error opening display.");
		}
	}
	else
		return("Error opening serial channel.");
}

LONG Application::DoEvent(VOID)
{
	ULONG Mask;

	Mask = AppChannel->WaitMask() | AppDisplay->WaitMask() | SIGBREAKF_CTRL_C;

	for(;;)
	{
		while(AppChannel->Waiting() || AppDisplay->Waiting())
		{
			if(AppChannel->Waiting())
			{
#if 0 D(+1)
				int rc;
				rc = AppService->ProcessInput();

				if(rc < 0)
					return(-1);

				if(rc > 0)
				{
					UBYTE matrix[40*24],line[44];
					int x,y,i;

					AppService->GetMatrix((UBYTE *)matrix,&x,&y);

					printf("+----------------------------------------+ %ld,%ld\n",x,y);
					for(i = 0 ; i < 24 ; i++)
					{
						memcpy(line,&matrix[40 * i],40);
						line[40] = 0;
						printf("|%s|\n",line);
					}
					printf("+----------------------------------------+\n\n");
				}
#else
				if(AppService->ProcessInput() < 0)
					return(-1);
#endif
			}

			if(AppDisplay->Waiting())
			{
				LONG Char = AppDisplay->GetChar();

				if(Char >= 0)
				{
					if(Char == '\033')
						return(-1);
					else
						AppChannel->PutChar(Char);
				}
			}
		}

		if(Wait(Mask) & SIGBREAKF_CTRL_C)
			return(-1);
	}
}

VOID Application::WaitForUserInput(VOID)
{
	ULONG Signals;

	AppDisplay->PutLine("[Hit any key to exit]");

	for(;;)
	{
		Signals = Wait(AppDisplay->WaitMask() | SIGBREAKF_CTRL_C);

		if(Signals & AppDisplay->WaitMask())
		{
			if(AppDisplay->Waiting())
			{
				if(AppDisplay->GetChar() >= 0)
					break;
			}
		}

		if(Signals & SIGBREAKF_CTRL_C)
			break;
	}
}

VOID Application::WaitEvent(VOID)
{
	Wait(AppChannel->WaitMask() | AppDisplay->WaitMask() | SIGBREAKF_CTRL_C);
}

LONG Application::DispatchEvent(VOID)
{
	LONG Value;

	Value = DispatchDisplayEvent();

	if(Value == CHANNELERR_Nothing)
		Value = (LONG)AppChannel->GetChar();

	return(Value);
}

LONG Application::DispatchDisplayEvent(VOID)
{
	if(SetSignal(0,0) & SIGBREAKF_CTRL_C)
		return(CHANNELERR_EOF);

	if(AppDisplay->Waiting())
	{
		LONG Char;

		Char = AppDisplay->GetChar();

		if(Char == '\033')
			return(CHANNELERR_EOF);
		else
		{
			if(Char >= 0)
				AppChannel->PutChar(Char);
		}
	}

	return(CHANNELERR_Nothing);
}
