


#include	<string.h>
#include	<stddef.h>
#include	<ctype.h>


#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#ifndef SYD_WIN

#include	<PLStringFuncs.h>
#include	<Events.h>
#include	<Notification.h>
#include	<SIOUX.h>

#endif

#include	"sy2types.h"


#define MGAEXT_CARBON_LIB	1

#define VAL_FIX_LEN	8


#include "cm_xx_mga.h"
#include "mgaclient.h"
#include "xx_pgm_dict.st"



#define MGAMAXTCPSERVER	20

XNETLocalNameServerInfo MGAEXTSERVERLIST[MGAMAXTCPSERVER];

#define QUERYTIMEINSECS 3


long last_ticks = -1;
long last_num_doc = 333;


MGAClientStats cs_data[30];

static int mga_console_callback(int cmd, int mgaaction, long par1, long par2, int wpar);
static int SpinProc(XNETLocalNameServerInfo *p, long par);
static int add_pn_IVA(void);
static int add_pn_generica(void);
static char *l2s(char *s, long fln);

static void check_dbri(void);

#ifdef SYD_WIN
#define WPU_TickCount()	((GetTickCount() * 6) / 100)
#else
#define WPU_TickCount()	TickCount()
#endif



static void
FlipDWordInd(Sy2DWORD *l)
{
	register long res;

	res = *l;
	*l = ((res & 0xff) << 24L) | (((res>>8) & 0xff) << 16L) | (((res>>16) & 0xff) << 8L) | (((res>>24) & 0xff));
}

int main(void)
{
	int err, i, n, cardlen, xxerr, xc;
	long logres, user_recid, dbname;
	char uname[50], mgauser[40], password[20], mgakw[16], tableidstr[16], codecf[16];
	MGAServerStats thestats;
	long mgaextlibversion;
	char actkey[64];
	
	long scanid;
	int num, ii, numclients;
	union {
		CARD_MGCF cf;
		CARD_MGSK sk;
		CARD_MGMG mg;
		CARD_MGRI ri;
		CARD_MGRO ro;
		CARD_MGRA ra;
		CARD_MGRM rm;
	} therec;
	
#ifndef SYD_WIN
	SIOUXSettings.autocloseonquit = true;
	SIOUXSettings.asktosaveonclose = false;
#endif
	printf ("Welcome to MGA Console!\n\n");
	srand(time(NULL));

	if ((mgaextlibversion = MGAExtOpenServices(0)) >= 0) {
		if (mgaextlibversion != MGAEXTLIB_VERSION) { 
			printf ("La versione della MGAEXTLIB e' errata!\n\n");
			goto xit_wrong_version;
		}
		
		
		MGAInit(mga_console_callback);
		if ((xxerr = MGAStart(2, 0, MGARTFL_API_MODE)) >= 0) {
		
			if ((n = MGAGetServerList(&MGAEXTSERVERLIST[0], MGAMAXTCPSERVER, QUERYTIMEINSECS, SpinProc, MGA_TCP_MAX_MULTIPROGRAMS, MGA_TCP_OFFSET_MULTIPROGRAMS, WPU_TickCount())) > 0) {
					
				for (i = 0; i < n; i++) {
					printf ("\n%d -> %s - %s\n", i, MGAEXTSERVERLIST[i].serverName, MGAEXTSERVERLIST[i].serverEntity);
				}
		
				printf("\n<Enter the number of the server to login> ");
				scanf("%d", &i);
					
				MGASetServer(&MGAEXTSERVERLIST[i]);
				
				// la chiave di attivazione che segue e' valida per il programma DEMO
				// per far funzionare il login con un altro server sara' necessaria una
				// chiave di attivazione abbinata ad esso (quella di un client)
				
				printf("\n<Enter the activation key ('*' for demo)> ");
				scanf("%s", actkey);
				if (actkey[0] == '*') {
					strcpy(actkey, "EQSYYZ-NMG9MG-8FCQUT-AWJ8N8-25");
				}
				
				if ((logres = MGAExtLogin(actkey)) >= 0) {
					//mga_udp->chan_num = logres;
					printf ("Login OK.\n");
					
					if (MGANeedsUserName() != MGA_TBPU_DISABLED) {
		username_retry:
						printf("\n<Enter the username> ");
						scanf("%40s", uname);
						memset(mgauser, ' ', sizeof(mgauser));
						memmove(mgauser, uname, strlen(uname));
						printf("\n<Enter the password> ");
						scanf("%16s", password);
						memset(mgakw, ' ', sizeof(mgakw));
						memmove(mgakw, password, strlen(password));
						if ((err = MGAAuthenticateUser(uname, mgakw, &user_recid)) < 0) {
							printf ("!! error %d in MGAAuthenticateUser!\n", err);
							goto username_retry;
						}
						printf ("User Authentication OK.\n");
					}
					
					for (;;) {
						printf ("\n0 - Logout\n");
						printf (" 1 - List DBCF             2 - List DBSK\n");
						printf (" 3 - List one table        4 - Get DBCF data from key\n");
						printf (" 5 - Add \"Prima nota IVA\"  6 - Add \"Prima nota Generica\"\n");
						printf (" 7 - MGAClientStats        8 - Test server\n");
						printf (" 9 - Stress server        10 - List ROWS\n");
						printf ("11 - check dbri           12 - ticks\n");
		
						printf("\n<?> ");
						scanf("%d", &i);
						
						if (i == 0) break;
						
						switch (i) {
						case 1:
							dbname = 'DBCF';
							cardlen = sizeof(therec.cf);
							break;
						case 2:
							dbname = 'DBSK';
							cardlen = sizeof(therec.sk);
							break;
						case 3:
							printf("\n<Enter table ID> ");
							scanf("%4s", tableidstr);
							dbname = *(long *)tableidstr;
		#ifdef SYD_WIN
							FlipDWordInd(&dbname);
		#endif
							cardlen = sizeof(therec.sk);
							break;
						case 4:
							printf("\n<Enter key> ");
							scanf("%6s", tableidstr);
							// normalizziamo il codice a sei caratteri
							memset(codecf, ' ', sizeof(therec.cf.hCFCD));
							memmove(codecf, tableidstr, strlen(tableidstr));
							for (xc = 0; xc < sizeof(therec.cf.hCFCD); xc++) {
								codecf[xc] = toupper(codecf[xc]);
							}
							if ((xxerr = MGAGetArchFromKey('DBCF', 1, codecf, sizeof(therec.cf.hCFCD), &therec.cf, sizeof(therec.cf))) >= 0) {
								printf ("\nDBCF data OK: %40.40s - %40.40s\n\n", therec.cf.hCFDE, therec.cf.hCFLO);
							}
							else {
								printf("key %6.6s NOT FOUND! - err %d.\n", codecf, xxerr);
							}
							break;
						case 5:
							xxerr = add_pn_IVA();
							if (xxerr >= 0) {
								printf("\"Prima nota IVA\" added successfully\n\n", xxerr);
							}
							else {
								printf("Error %d adding \"Prima nota IVA\"\n\n", xxerr);
							}
							break;
						case 6:
							xxerr = add_pn_generica();
							if (xxerr >= 0) {
								printf("\"Prima nota Generica\" added successfully\n\n", xxerr);
							}
							else {
								printf("Error %d adding \"Prima nota Generica\"\n\n", xxerr);
							}
							break;
						case 7:
							if ((numclients = MGAGetClientStats(&cs_data[0])) >= 0) {
								printf("MGAGetClientStats ok %d clients\n\n", numclients);
								for (ii = 0; ii < numclients; ii++) {
									printf("#%2.2d - %4.4s * %s - %d \n", ii + 1, l2s(nil, cs_data[ii].mgadata.current_state), cs_data[ii].clientrec.u.rec.MachineName, cs_data[ii].mgadata.current_state);
								}
								printf("\n");
							}
							else {
								printf("Error %d in MGAGetClientStats\n\n", numclients);
							}
							break;
						case 8:
						case 9:
							/***
							{
								Sy2SimpleStopWatchData servertmr;
								long elapsed_time_in_ms, numreq;
								
								numreq = 0;
								//while (!WPU_Button()) {
								for (;;) {
									if (WPU_GetAsyncModifiers() == (SY2_MOD_CTL | SY2_MOD_SHIFT)) break;

									Sy2OpenSimpleStopWatch(&servertmr, 1);
									Sy2StartSimpleStopWatch(&servertmr);
									xxerr = MGADeclareClientState(0);
									elapsed_time_in_ms = Sy2GetSimpleStopWatch(&servertmr) / 1000;
									printf("#%8.8d returned: %d in %6.6d msec.\n", ++numreq, xxerr, elapsed_time_in_ms);
									if (i == 8) {
										for (;;) if ((Sy2GetSimpleStopWatch(&servertmr) / 1000) > 4000) break;
									}
									Sy2StopSimpleStopWatch(&servertmr);
								}
							}
							***/
							break;
						case 10:
							{
								int azienda;
								short numrow;
								long reclen, theref, *qtap;
								//CARD_MGRA radata;
								
							printf("\n<Enter DBID (for example DBRA)> ");
							scanf("%4s", tableidstr);
							dbname = *(long *)tableidstr;
		#ifdef SYD_WIN
							FlipDWordInd(&dbname);
		#endif
							printf("\n<Enter Numint> ");
							scanf("%d", &theref);
							
							printf("\n<Enter Azienda (1 based)> ");
							scanf("%d", &azienda);
							
							if (azienda <= 0) {
								azienda = 1;
							}
							
						
								// theref = 3490;
								MGAClientSetCurrentAzienda(azienda);
								switch (dbname) {
								case 'DBRI':
									reclen = sizeof(CARD_MGRI);
									qtap = (long *)&therec.ri.hRIQT[2];
									break;
								case 'DBRO':
									reclen = sizeof(CARD_MGRO);
									qtap = (long *)&therec.ro.hROQT[2];
									break;
								case 'DBRA':
									reclen = sizeof(CARD_MGRA);
									qtap = (long *)&therec.ra.hRAQT[2];
									break;
								case 'DBRM':
									reclen = sizeof(CARD_MGRM);
									qtap = (long *)&therec.rm.hRMQT[2];
									break;
								default:
									printf("DBID not yet supported!!\n");
									goto abort_10;
									break;
								}

								for (numrow = 1; numrow < 100; numrow++) {
									if (MGAGetNthDetail(dbname, theref, numrow, &therec, reclen) >= 0) {
/***
										if (numrow == 6) {
											radata.hRARN = 2;
											xxerr = MGAPutRecordFromRecID('DBRA', 0, &radata, sizeof(radata));
											printf("MGAPutRecordFromRecID = %d\n", xxerr);
											radata.hRARN = 3;
											xxerr = MGAPutRecordFromRecID('DBRA', 0, &radata, sizeof(radata));
											printf("MGAPutRecordFromRecID = %d\n", xxerr);
											radata.hRARN = 4;
											xxerr = MGAPutRecordFromRecID('DBRA', 0, &radata, sizeof(radata));
											printf("MGAPutRecordFromRecID = %d\n", xxerr);
										}
***/
										printf("ref = %4.4d row = %4.4d %16.16s %40.40s %4.4d\n", theref, numrow, therec.ra.hRACA, therec.ra.hRADE, *qtap);
									}
								}
							}
abort_10:
							break;
						case 11:
							check_dbri();
							break;
						case 12:
							/***
							{
								Sy2SimpleTimerData xtmr;

								Sy2StartSimpleTimer(&xtmr, 100);
								for (;;) {
									if (WPU_GetAsyncModifiers() == (SY2_MOD_CTL | SY2_MOD_SHIFT)) break;

									if (Sy2CheckSimpleTimer(&xtmr) != 0) {
										printf("--->FIRED! ticks = %d\n", GetTickCount());
										printf("start = %d\nend = %d\nelaps = %x\n", xtmr.start, xtmr.end, xtmr.lastelapsed);
										Sy2StartSimpleTimer(&xtmr, 100);
									}
								}
							}
							***/
							{
								unsigned long end;
								unsigned long nummsec, prec;
								int g;
									
								prec = 0;
								for (g = 1; g < 100; g++) {
									nummsec = g * 24 * 60 * 60 * 1000;
									end = ((nummsec/10) * 6) / 10;
									printf ("giorno %2.2d %d - end = %d diff = %d\n", g, nummsec, end, nummsec - prec);
									prec = nummsec;
								}
							}
							break;
						}
						
						// qui eseguiamo i primi tre comandi
						if (i >= 1 && i <= 3) {
							if ((xxerr = MGAGetServerStats(&thestats)) >= 0) {
								printf ("\nCurrent number of requests: %d\n", thestats.num_reqs);
							}
							else {
								printf ("!!!! errore %d in MGAGetServerStats !!!!\n", xxerr);
							}
							if ((scanid = MGAScanOpen(dbname, 1)) > 0) {
								printf ("\nMGAScanOpen OK.\n");
								num = 0;
								while (MGAScanNext(dbname, scanid, &therec, cardlen) >= 0) {
									if (dbname == 'DBCF') {
										printf ("%4.4d: %6.6s - %40.40s\n", ++num, therec.cf.hCFCD, therec.cf.hCFDE);
									}
									else if (dbname == 'DBSK') {
										printf ("%4.4d: %10.10s - %40.40s\n", ++num, therec.sk.hPCCD, therec.sk.hPCDE);
									}
									else {
										printf ("%4.4d: %40.40s\n", ++num, therec.sk.hPCCD);
									}
								}
								MGAScanClose(scanid);
								printf ("\nMGAScanClose OK.\n");
							}
							else {
								printf ("\nMGAScanOpen failed - err %d.\n", scanid);
							}
							
							if ((xxerr = MGAGetServerStats(&thestats)) >= 0) {
								printf ("\nCurrent number of requests: %d\n", thestats.num_reqs);
							}
							else {
								printf ("!!!! errore %d in MGAGetServerStats !!!!\n", xxerr);
							}
						}
						
					}
					MGAExtLogout();
					printf ("Logged OUT.\n");
				}
				else {
					printf ("!!!! errore %d in MGALogin !!!!\n", logres);
				}
				
			}
			else {
				printf ("Server non trovato!\n");
			}
			MGAEnd();
		}
		else {
			printf ("!!!! errore %d in MGAStart !!!!\n", xxerr);
		}
xit_wrong_version:
		MGAExtCloseServices();
	}
	else {
		printf ("!!!! errore %d in MGAOpenExternalServices !!!!\n", mgaextlibversion);
	}
	return 0;
}


static int
SpinProc(XNETLocalNameServerInfo *p, long par)
{
	long xxticks, togo;
	
	xxticks = WPU_TickCount() - par;
	
	if ((xxticks % 15) == 0) {
		if (xxticks != last_ticks) {
			togo = QUERYTIMEINSECS*60 - xxticks;
			printf("querying server... %4.4d ticks to go\n", togo);
		}
		last_ticks = xxticks;
	}
	return(0);
}

static int
mga_console_callback(int cmd, int mgaaction, long par1, long par2, int wpar)
{
	register int res = 0;
	
	switch (cmd) {
	case MGACB_GET_STRING:
		switch(par1) {
		case 'ADMI':
			strcpy((char *)par2, "*Amministratore");
			break;
		default:
			*(char *)par2 = '\0';
			break;
		}
		break;
	case MGACB_INTERNAL_EXCEPTION:
		printf("MGA Internal Exception %d / %d", par1, par2);
		break;
	case MGACB_IDLE:
#ifndef SYD_WIN
		{
			EventRecord ev;

			WaitNextEvent(0, &ev, 0, 0);
		}
#endif
		break;
	}
	return(res);
}


static int
add_pn_generica(void)
{
	int res = 0;
	/***
	CARD_HGEN header_pn_gen;
	CARD_RGEN row_pn_gen;

	memset(&header_pn_gen, 0, sizeof(header_pn_gen));
	
	header_pn_gen.hMOTI = T_GENERICO;
	// long hMOFL;
	Sy2StringToDate("311293", 6, 1, &header_pn_gen.hMODT);				// data di reg. 31/12/93
	memmove(header_pn_gen.hMOCA, "AA  ", sizeof(header_pn_gen.hMOCA));	// codice causale contabile
	memset(header_pn_gen.hMOND, ' ', sizeof(header_pn_gen.hMOND));		// numero documento (VUOTO per esempio)
	header_pn_gen.hMODD = header_pn_gen.hMODT;							// data documento uguale a data registrazione
	memset(header_pn_gen.hPAAG, ' ', sizeof(header_pn_gen.hPAAG));		// codice agente (VUOTO per esempio)
	// per ora niente IVA differita
	header_pn_gen.hMOGI = TPGI_NOWORRY;
	// long hMOFD;
	// unsigned char hMOTV[8];
	
	memset(&row_pn_gen, 0, sizeof(row_pn_gen));

	memmove(row_pn_gen.hRNDA, "01.01.01  ", sizeof(row_pn_gen.hRNDA));				// codice dare
	memmove(row_pn_gen.hRNAV, "01.01.02  ", sizeof(row_pn_gen.hRNAV));				// codice avere
	BufToFixed(VAL_FIX_LEN, 0, 0, "101000", strlen("101000"), row_pn_gen.hRNID);	// importo dare 101.000
	CopyFixed(row_pn_gen.hRNID, VAL_FIX_LEN, row_pn_gen.hRNIA, VAL_FIX_LEN);		// idem per importo avere
	// nessun rif. partita aperta
	// char hRNAP[12];
	memmove(row_pn_gen.hRNDE, "Prova da MGAConsole     ", sizeof(row_pn_gen.hRNDE));	// descrizione

	if ((res = MGAAddMasterDetail('DBPN', T_GENERICO, &header_pn_gen, sizeof(header_pn_gen), &row_pn_gen, sizeof(row_pn_gen), 1, -1, nil)) >= 0) {	// per controllo
		res = MGAAddMasterDetail('DBPN', T_GENERICO, &header_pn_gen, sizeof(header_pn_gen), &row_pn_gen, sizeof(row_pn_gen), 1, 0, nil);
	}
	***/
	return(res);
}

static int
add_pn_IVA(void)
{
	int res = 0;
/***
	CARD_HIVA header_pn_iva;
	CARD_RIVA row_pn_iva;
	char numstr[32];

	memset(&header_pn_iva, 0, sizeof(header_pn_iva));
	
	header_pn_iva.hMOTI = T_IVA;
	// long hMOFL;
	Sy2StringToDate("311293", 6, 1, &header_pn_iva.hMODT);				// data di reg. 31/12/93
	memmove(header_pn_iva.hMOCA, "FV  ", sizeof(header_pn_iva.hMOCA));	// codice causale contabile
	// utilizziamo un numero progressivo per non duplicare le partite aperte
	BinToCString(sizeof(last_num_doc), (Sy2UBYTE *)&last_num_doc, numstr, sizeof(numstr), nil);
	last_num_doc++;
	memset(header_pn_iva.hMOND, ' ', sizeof(header_pn_iva.hMOND));		// numero documento
	memmove(header_pn_iva.hMOND, numstr, strlen(numstr));
	header_pn_iva.hMODD = header_pn_iva.hMODT;							// data documento uguale a data registrazione
	// questi (se vuoti) vengono assegnati in automatico
	memset(header_pn_iva.hMORI, ' ', sizeof(header_pn_iva.hMORI));		// cod registro IVA
	// long hMONP;														// protocollo IVA
	memmove(header_pn_iva.hMOCP, "RB3     ", sizeof(header_pn_iva.hMOCP));	// codice cond. pagamento
	memset(header_pn_iva.hMOCN, ' ', sizeof(header_pn_iva.hMOCN));	// niente incasso automatico
	memmove(header_pn_iva.hMOCF, "CA0001    ", sizeof(header_pn_iva.hMOCF));	// codice partita
	// nessun rif. partita aperta
	// char hMOAP[12];
	memset(header_pn_iva.hPAAG, ' ', sizeof(header_pn_iva.hPAAG));		// codice agente (VUOTO per esempio)
	// per ora niente IVA differita
	header_pn_iva.hMOGI = TPGI_NOWORRY;
	// long hMOFD;
	
	memset(&row_pn_iva, 0, sizeof(row_pn_iva));

	memmove(row_pn_iva.hRNCP, "20.01.01  ", sizeof(row_pn_iva.hRNCP));				// codice dare
	BufToFixed(VAL_FIX_LEN, 0, 0, "101000", strlen("101000"), row_pn_iva.hRNIM);	// importo imponibile 101.000
	memmove(row_pn_iva.hRNCI, "19  ", sizeof(row_pn_iva.hRNCI));					// codice IVA
	BufToFixed(VAL_FIX_LEN, 0, 0, "19190", strlen("19190"), row_pn_iva.hRNIV);		// importo imponibile 19.190
	memmove(row_pn_iva.hRNDE, "Prova da MGAConsole     ", sizeof(row_pn_iva.hRNDE));	// descrizione

	if ((res = MGAAddMasterDetail('DBPN', T_IVA, &header_pn_iva, sizeof(header_pn_iva), &row_pn_iva, sizeof(row_pn_iva), 1, -1, nil)) >= 0) {	// per controllo
		res = MGAAddMasterDetail('DBPN', T_IVA, &header_pn_iva, sizeof(header_pn_iva), &row_pn_iva, sizeof(row_pn_iva), 1, 0, nil);
	}
***/
	return(res);
}

static char localstring[6];

static char *l2s(char *s, long fln)
{
	union {
		long a;
		char b[6];
	} u;
	char *os;

	if (s == 0) s = localstring;
	os = s;
	u.a = fln;
#ifdef	SYD_WIN
	*s++ = u.b[3];
	*s++ = u.b[2];
	*s++ = u.b[1];
	*s++ = u.b[0];
#else
	*s++ = u.b[0];
	*s++ = u.b[1];
	*s++ = u.b[2];
	*s++ = u.b[3];
#endif
	*s = 0;
	return(os);
}

static void
check_dbor()
{
	long scanid, mynum;
	CARD_MGOR ordata;

	mynum = 1;
	if ((scanid = MGAScanOpen('DBOR', 2)) > 0) {
		while (MGAScanNext('DBOR', scanid, &ordata, sizeof(ordata)) >= 0) {
			if (ordata.hORNP > 1044) break;
			if (ordata.hORNP >= mynum) {
				while (ordata.hORNP != mynum) {
					printf("%d\n", mynum);
					mynum++;
				}
				mynum++;
			}
		}
		MGAScanClose(scanid);
	}
}

static void
check_dbri()
{
	long scanid, last_ridn;
	CARD_MGRI ridata;
	CARD_MGOR ordata;

	last_ridn = 0;
	if ((scanid = MGAScanOpen('DBRI', 1)) > 0) {
		while (MGAScanNext('DBRI', scanid, &ridata, sizeof(ridata)) >= 0) {
			if (ridata.hRIDN < 5811) {
				if (ridata.hRIDN % 2) printf("-\n");
				else printf("+\n");
				continue;
			}
			if (ridata.hRINO != 0) {
				if (MGAGetRecordFromKey('DBOR', 1, &ridata.hRINO, sizeof(ridata.hRINO), &ordata, sizeof(ordata)) < 0) {
					if (ridata.hRIDN != last_ridn) {
						last_ridn = ridata.hRIDN;
						printf("n.int DF %6.6d - OR %6.6d\n", ridata.hRIDN, ridata.hRINO);
					}
				}
			}
		}
		MGAScanClose(scanid);
	}
}
/************* Sy2 stubs ***************/

#ifdef SYD_WIN

int
Prog_Manager(unsigned int message, long par)
{
	return(0);
}
#endif
