#include <stdlib.h>

#include <exec/execbase.h>
#include <exec/memory.h>
#include <exec/semaphores.h>
#include <dos/dosextens.h>
#include <intuition/sghooks.h>
#include <libraries/commodities.h>
#include <libraries/locale.h>

#include <clib/alib_protos.h>
#include <clib/commodities_protos.h>
#include <clib/dos_protos.h>
#include <clib/exec_protos.h>
#include <clib/intuition_protos.h>
#include <clib/locale_protos.h>

#include<pragmas/commodities_pragmas.h>
#include<pragmas/dos_pragmas.h>
#include<pragmas/exec_pragmas.h>
#include<pragmas/intuition_pragmas.h>
#include<pragmas/locale_pragmas.h>

#include "NewEdit.h"

#define CATCOMP_NUMBERS
#define CATCOMP_BLOCK
#define CATCOMP_CODE
#include "Catalog.h"

/* Disable SAS/C control c handling */
int _CXBRK   (void)  { return 0; }
int __chkabort(void) { return 0; }

void disable_hook( void );
void process_messages( struct MsgPort *port );

static char verstag[] = VERSTAG;
char Version[] = VERS" ("DATE") ";

extern ULONG __saveds __asm  string_hook( register __a0 struct Hook   *hook,
                                          register __a2 struct SGWork *sgw,
                                          register __a1 unsigned long *msg  );
extern BOOL init_iffparse( void );
extern void close_iffparse( void );

#define TITLESTRING VERS" by Uwe Röhm"

extern struct ExecBase *SysBase, *DOSBase;
struct Library *IntuitionBase = NULL, *UtilityBase = NULL, *CxBase = NULL;

BOOL Disabled;
CxObj *Broker = NULL;
struct Hook Edh;
struct Hook *OldHook;
struct SignalSemaphore *Sem;
struct NewBroker MyBroker =
{
	NB_VERSION, "NewEdit", TITLESTRING,
	0, NBU_NOTIFY | NBU_UNIQUE,
	0, 0, 0L, 0
};

struct LocaleInfo LI;
#define LocaleBase LI.li_LocaleBase
#define catalog LI.li_Catalog

LONG Max, Num, Pos, Len;

void __stdargs __main( char *stream )
{
	LONG error;
	int retcode;
	struct Task *mytask;
	struct TagItem cattags[] =
	{
		OC_BuiltInLanguage, (ULONG)"english",
		TAG_DONE
	};

	if ( SysBase->LibNode.lib_Version > 36 )
	{
		SetProgramName( "NewEdit" );

		if ( LocaleBase = OpenLibrary( "locale.library", 38 ) )
			catalog = OpenCatalogA( NULL, "NewEdit.catalog", cattags );

		if ( IntuitionBase = OpenLibrary( "intuition.library", 37 ) )
		{
			if ( UtilityBase = OpenLibrary( "utility.library", 37 ) )
			{
				if ( CxBase = OpenLibrary( "commodities.library", 37 ) )
				{
					mytask = FindTask( NULL );

					MyBroker.nb_Port = &( ( struct Process * )mytask )->pr_MsgPort;
					MyBroker.nb_Descr = GetString( &LI, MSG_CX_DESCRIPTION );

					if ( Broker = CxBroker( &MyBroker, &error ) )
					{
						if ( Sem = (struct SignalSemaphore *)AllocMem( sizeof( struct SignalSemaphore ), MEMF_CLEAR ) )
						{
							Sem->ss_Link.ln_Pri  = 0;
							Sem->ss_Link.ln_Name = "NewEdit.Semaphore";
							AddSemaphore( Sem );

							Edh.h_Entry = ( ULONG (*)() )string_hook;

							/* Initialize clipboard unit 0 */
							if ( init_iffparse() )
							{
								Disabled = FALSE;
								OldHook = SetEditHook( &Edh );
								PutStr( GetString( &LI, MSG_HAILSTRING ) );
								ActivateCxObj( Broker, 1l );

								process_messages( MyBroker.nb_Port );

								disable_hook();
								close_iffparse();
							}
							else
							{
								PutStr( GetString( &LI, MSG_ERROR_NOCLIPBOARD ) );
								retcode = RETURN_FAIL;
							}

							RemSemaphore( Sem );
							FreeMem( Sem, sizeof( struct SignalSemaphore ) );
							PutStr( GetString( &LI, MSG_BYEBYE ) );
						}
						else
						{
							Permit(); // Why ???????
							PutStr( GetString ( &LI, MSG_ERROR_MEMORY ) );
							retcode = RETURN_FAIL;
						}

						DeleteCxObj ( Broker );

					}
					else retcode = RETURN_WARN;

					CloseLibrary( CxBase );
				}
				CloseLibrary( UtilityBase );
			}
			CloseLibrary( IntuitionBase );
		}

		if ( LocaleBase )
		{
			CloseCatalog( catalog );
			CloseLibrary( LocaleBase );
		}
	}
   __exit( retcode );
}


void disable_hook()
{
	ObtainSemaphore( Sem );

	Disable();

	SetEditHook( OldHook );

	Enable();

	ReleaseSemaphore( Sem );
}

void process_messages ( struct MsgPort *port )
{
	short sigs, tasksig;
	CxMsg *cxm;

	tasksig = 1L << port->mp_SigBit;

	do
	{
		sigs = Wait( tasksig | SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_F );

		if ( sigs & tasksig )
		{
			while ( cxm = ( CxMsg * )GetMsg( MyBroker.nb_Port ) )
			{
				if ( CxMsgType( cxm ) == CXCMD_UNIQUE ) sigs |= SIGBREAKF_CTRL_C;
				else
				switch ( CxMsgID( cxm ) )
				{
					case CXCMD_DISABLE:
						Disabled = TRUE;
						ActivateCxObj( Broker, 0l );
					break;

					case CXCMD_ENABLE:
						Disabled = FALSE;
						ActivateCxObj( Broker, 1l );
					break;

					case CXCMD_UNIQUE:
					case CXCMD_KILL:
						sigs |= SIGBREAKF_CTRL_C;
					break;

					default:
					break;
				}

				ReplyMsg( (struct Message*)cxm );

			}
		}
	} while ( !( sigs & ( SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_F ) ) );
}
