/******************************************************************************
*                                                                             *
*   MATRIX! V1.1a Kommunikationslibrary                                       *
*                                                                             *
*   geschrieben von Jens Lohaus                                               *
*                                                                             *
*   Copyright der Dateien MATRIX!libsup.c und libstart.asm liegt bei Manx.    *
*                                                                             *
*   Die in dieser Library zusammengefaßten Funktion, dienen der Steuerung     *
*   aller Funktionen von MATRIX! von einem anderen Programm aus.              *
*   An diesem Source-Code ( Aztec C V5.0a ) sollte auch klar werden wie       *
*   eigenen Programme zu schreiben sind, die die Funktionen aus MATRIX!       *
*   nutzen wollen. Der Code enthält darum einige Erläuterungen zu den         *
*   Funktionen und der Vorgehensweise.                                        *
*                                                                             *
******************************************************************************/

#include "MATRIX!.H" /* Alle weiteren Einbindungen werden dort vorgenommen. */


/* Die Funktion LoginM stellt die Verbindung zwischen Ihrem Programm
   und MATRIX! her. Sie ist vor allen weiteren Operationen mit MATRIX!
   aufzurufen. 
   Der Parameter Flag gibt an ob MATRIX!, obwohl es von Außen gesteuert
   wird, weiter Ausgaben in sein Fenster durchführen soll. Dazu die
   folgenden beiden Definitionen:                                           */

#define OUTPUT 		1
#define NOOUTPUT 	0
#define MATRIXID	48996.95

/* Die Funktion hat als Rückgabewert eine 0, wenn sie erfolgreich war und
   ansonsten einen der folgenden definierten Werte: */

#define NO_INTUITION	1
#define NO_WB_SCREEN	2
#define NO_MATRIX	3
#define NO_REPLYPORT	4
#define MATRIX_ENDING	5
#define NO_SIGNAL	6
#define PRE_LOCKED	7

/* Ein Aufruf von LoginM könnte wie folgt aussehen :
   
   void main(void)
   {
   struct Login *login;
     .
     .
     
   if((login=LoginM(NOUTPUT))==NULL) {
    printf("Kann MATRIX! nicht ansprechen!\n");
    exit(20);}                                                              */
  

int LoginM(int OutFlag)
{
struct MatrixlibBase *MatrixlibBase;
ULONG Lock;
struct Window *win;
struct IntuitionBase *IntuitionBase;
struct Screen *scr;
BOOL Flag;

if(MatrixlibBase->log) return(-1);  /* MATRIX! ist bereits angesprochen */

/* Zunächst wird die Intuition.library geöffnet, denn in ihr sind einige
   benötigte Funktionen. */

if((IntuitionBase=(struct IntuitionBase *)OpenLibrary("intuition.library",0))==NULL) return(NO_INTUITION);
MatrixlibBase->IntBase=IntuitionBase;

/* Als nächstes wird die Liste der Screens nach dem Worbenchscreen durchsucht,
   denn MATRIX! muß sich auf ihm befinden. */

Lock=LockIBase(0); /* Damit die Liste der Screens und Windows nicht
                      geändert werden kann */
scr=IntuitionBase->FirstScreen;
while((scr!=NULL)&&(Flag)) {
 if(*(double *)(scr->UserData)!=MATRIXID) scr=scr->NextScreen;
 else Flag=FALSE;}
if(Flag) {  /* MATRIX!-Screen nicht gefunden */
 scr=IntuitionBase->FirstScreen;
 while((scr!=NULL)&&(Flag)) {
  if(strcmp((char *)scr->Title,"Workbench Screen")) scr=scr->NextScreen;
  else Flag=FALSE;}}
if(Flag) {  /* Worbenchscreen nicht gefunden. */
 UnlockIBase(Lock);
 CloseLibrary(IntuitionBase);
 MatrixlibBase->IntBase=NULL;
 return(NO_WB_SCREEN);}

/* Nun wird die Liste der Workbenchfenster nach dem MATRIX! Fenster durchsucht. */

Flag=TRUE;
win=scr->FirstWindow;
while((win!=NULL)&&(Flag)) {
 if(((struct Kommunikation *)(win->UserData))->ID!=MATRIXID) win=win->NextWindow;
 else Flag=FALSE;}
if(Flag) {  /* Fenster nicht gefunden, MATRIX! läuft also nicht. */
 UnlockIBase(Lock);
 CloseLibrary(IntuitionBase);
 MatrixlibBase->IntBase=NULL;
 return(NO_MATRIX);}
UnlockIBase(Lock);

/* Nun wird die Verbindung zur Kommunikationsstruktur hergestellt. */

MatrixlibBase->Out=(struct Kommunikation *)win->UserData; 
if(MatrixlibBase->Out==NULL) { /* MATRIX! läuft zwar noch ist aber dabei zu enden */
 CloseLibrary(IntuitionBase);
 MatrixlibBase->IntBase=NULL;
 return(MATRIX_ENDING);}
if(MatrixlibBase->Out->lock) { /* Einanderes Programm benutzt MATRIX! */
 CloseLibrary(IntuitionBase);
 MatrixlibBase->IntBase=NULL;
 return(PRE_LOCKED);}
MatrixlibBase->Out->lock=TRUE; /* Damit wird MATRIX! signalisiert, daß ein anderes Programm
                   läuft, daß es nutzen möchte. MATRIX! kann jetzt nicht
                   gestoppt werden. Ist das Fenster von MATRIX! klein so
                   läßt es sich nicht mehr vergrößern */
MatrixlibBase->Out->extask=FindTask(NULL); /* MATRIX! wird ein Zeiger auf das eigene
            Programm übergeben damit es Signalisieren kann, wenn es Rechnungen
            beendet hat und die Ergebnisse abrufbar sind */

/* Nun wird versucht das Signalbit vom System zu bekommen mit dem MATRIX!
   dies signalisieren soll */

if((MatrixlibBase->bit=AllocSignal(-1))<0) { /* Kein Bit bekommen */
 MatrixlibBase->Out->lock=FALSE;
 MatrixlibBase->Out->extask=NULL;
 CloseLibrary(IntuitionBase);
 MatrixlibBase->IntBase=NULL;
 return(NO_SIGNAL);}
MatrixlibBase->Out->maske=1 << MatrixlibBase->bit; /* MATRIX! wird die zu sendende
       Bitmaske übermittelt */

/* Nun wird versucht einen Messageport zu öffnen damit man an MATRIX! Messages,
   also Befehle absenden kann. */

if((MatrixlibBase->ReplyPort=CreatePort("MKOM",0))==NULL) {
                          /* Konnte Port nicht öffnen */
 FreeSignal(MatrixlibBase->bit);
 MatrixlibBase->Out->lock=FALSE;
 MatrixlibBase->Out->extask=NULL;
 CloseLibrary(IntuitionBase);
 MatrixlibBase->IntBase=NULL;
 return(NO_REPLYPORT);}

/* Damit ist nun die Kommunikation mit MATRIX! gesichert !
   Es wird nun noch die zu sendende Message initialisiert*/
MatrixlibBase->MyMess.ExecMessage.mn_ReplyPort=MatrixlibBase->ReplyPort;
MatrixlibBase->MyMess.ExecMessage.mn_Node.ln_Type=NT_MESSAGE;
MatrixlibBase->MyMess.Class=GADGETDOWN;
MatrixlibBase->MyMess.Qualifier=0;
MatrixlibBase->MyMess.Code=0;
MatrixlibBase->MyMess.IAddress=(APTR)&(MatrixlibBase->Gad);
MatrixlibBase->MATRIXPort=win->UserPort;
MatrixlibBase->Out->set=TRUE;
MatrixlibBase->Out->output=OutFlag;
SetSignal(0,MatrixlibBase->Out->maske);
MatrixlibBase->log=TRUE;
return(0);
}

/* Die Funktion FreeM sollte als letztes in ihrem Programm vorkommen, denn
   sie bricht die Kommunikation mit MATRIX! ab und gibt den dazu
   benötigten Speicher wieder frei. Wird diese Funktion nicht aufgerufen
   kann MATRIX! nicht angehalten werden. */

void FreeM(void)
{
struct MatrixlibBase *MatrixlibBase;
struct IntuitionBase *IntuitionBase;

IntuitionBase=MatrixlibBase->IntBase;

MatrixlibBase->log=FALSE;
MatrixlibBase->Out->output=TRUE; /* Ausgabe einschalten */
MatrixlibBase->Out->set=FALSE;   /* Eingabe einschalten */
MatrixlibBase->Out->extask=NULL; /* Zeiger aif eigenen Task löschen */
MatrixlibBase->Out->lock=FALSE;  /* MATRIX! freigeben */
Make(BUILDUP);                   /* Die Anzeige von MATRIX! wird wieder aufgebaut */
Delay(10);
FreeSignal(MatrixlibBase->bit);  /* allociertes Signalbit freigeben */
DeletePort(MatrixlibBase->ReplyPort); /* Messageport freigeben */
CloseLibrary(IntuitionBase); 
MatrixlibBase->IntBase=NULL;
}

/* Mit der folgende Funktion löst man nach dem einloggen in MATRIX! mit LoginM
   eine Funktion in MATRIX! aus die keine weiteren Parameter abfragt. Z.B.
   TRANS oder PRINT usw. Der Übergabeparameter 'Operation' kann dabei
   die in MATRIX!.H angegebenen Werte annehmen. */

int Make(int Operation)
{
struct MatrixlibBase *MatrixlibBase;

if(MatrixlibBase->log==FALSE) return(-1);  /* MATRIX! steht gar nicht zur
  Verfügung. Vorher LoginM aufrufen! */

MatrixlibBase->MyMess.ExecMessage.mn_ReplyPort=MatrixlibBase->ReplyPort;
MatrixlibBase->MyMess.ExecMessage.mn_Node.ln_Type=NT_MESSAGE;
MatrixlibBase->MyMess.Class=GADGETDOWN;
MatrixlibBase->MyMess.Qualifier=0;
MatrixlibBase->MyMess.Code=0;
MatrixlibBase->MyMess.IAddress=(APTR)&(MatrixlibBase->Gad);
MatrixlibBase->Gad.GadgetID=Operation;
Forbid();   /* Zur Sicherheit damit kein anderes Programm MATRIX! ansendet */
SetSignal(0,MatrixlibBase->Out->maske);
PutMsg(MatrixlibBase->MATRIXPort,(struct Message *)&(MatrixlibBase->MyMess));
Permit();  
Wait(1L << MatrixlibBase->ReplyPort->mp_SigBit);
GetMsg(MatrixlibBase->ReplyPort);
Wait(MatrixlibBase->Out->maske);
return(Operation);
}


/* Mit der folgenden Funktion können Sie die Größe der Matrizen und Vektoren
   einstellen. Ist die Operation erfolgreich wird 0 ansonsten -1 zurückgegeben */

int ChangeDim(long DIM)
{
struct MatrixlibBase *MatrixlibBase;

MatrixlibBase->Out->dim=DIM;
MatrixlibBase->MyMess.Class=GADGETUP;
if(MatrixlibBase->log==FALSE) return(-1);  /* MATRIX! steht gar nicht zur
  Verfügung. Vorher LoginM aufrufen! */
MatrixlibBase->MyMess.ExecMessage.mn_ReplyPort=MatrixlibBase->ReplyPort;
MatrixlibBase->MyMess.ExecMessage.mn_Node.ln_Type=NT_MESSAGE;
MatrixlibBase->MyMess.Class=GADGETUP;
MatrixlibBase->MyMess.IAddress=(APTR)&(MatrixlibBase->Gad);
MatrixlibBase->Gad.GadgetID=CHANGEDIM;
Forbid();   /* Zur Sicherheit damit kein anderes Programm MATRIX! ansendet */
SetSignal(0,MatrixlibBase->Out->maske);
PutMsg(MatrixlibBase->MATRIXPort,(struct Message *)&(MatrixlibBase->MyMess));
Permit();  
Wait(1L << MatrixlibBase->ReplyPort->mp_SigBit);
GetMsg(MatrixlibBase->ReplyPort);
Wait(MatrixlibBase->Out->maske);
return(-(DIM==MatrixlibBase->Out->dim));
}


/* Mit der folgenden Funktion kann das Potenzieren von Matrizen und das
   Tensorprodukt etc. ausgelöst werden. Die dazu zusätzliche nötige übergabe
   einer ganzen Zahl wird mit dem Parameter ganze_zahl verwirklicht. 
   Beachten Sie, daß die Zahl beim Tensorprodukt nicht überprüft wird.
   Sie muß also ein Teiler der eingestellten Größe sein. 
   Auch wird mit dieser Funktion die LR-Zerlegung gestartet,
   die ja möglicherweise einen CHAR als Parameter erwartet
   der angibt in welcher Matrix die Permutationsmatrix abgelegt
   werden soll. Dazu sind in MATRIX!.h die Makros PTOA bis PTOG zu finden. */

void Make_long(int Operation,long ganze_zahl)
{
struct MatrixlibBase *MatrixlibBase;

MatrixlibBase->Out->val.l=ganze_zahl;
Make(Operation);
}


/* Mit Make_real werden Skalarprodukte und die Berechnung der Eigenäume
   gesteurt. Ein Zeiger  auf die benötigte doppelt genaue Fließkommazahl
   wird mittels reelle_zahl übergeben. 
   Beachten sie das Format in dem die von Ihnen benutzte MATRIX! Version
   Fließkommazahlen verarbeitet. */

void Make_real(int Operation,double *reelle_zahl)
{
struct MatrixlibBase *MatrixlibBase;

MatrixlibBase->Out->val.d=*reelle_zahl;
Make(Operation);
}


/* Mit der nächsten Funktion werden die Dateiopertionen gesteuert.
   Der Erste Paramter beschreibt die Operation und der zweite enthält das
   Ziel bzw. das Objekt mit dem gearbeitet wird. 
   Der dritte ist ein Zeiger auf den Namen der Datei oder des Dateisatzes. */

void Make_datei(int Operation,int Objekt,char *name)
{
struct MatrixlibBase *MatrixlibBase;

MatrixlibBase->Out->val.s=name;

if(MatrixlibBase->log){
 MatrixlibBase->MyMess.ExecMessage.mn_ReplyPort=MatrixlibBase->ReplyPort;
 MatrixlibBase->MyMess.ExecMessage.mn_Node.ln_Type=NT_MESSAGE;
 MatrixlibBase->MyMess.Class=GADGETDOWN;
 MatrixlibBase->MyMess.IAddress=(APTR)&(MatrixlibBase->Gad);
 MatrixlibBase->Gad.GadgetID=Objekt;
 Forbid();
 SetSignal(0,MatrixlibBase->Out->maske);
 PutMsg(MatrixlibBase->MATRIXPort,(struct Message *)&(MatrixlibBase->MyMess));
 Permit();  
 Wait(1L << MatrixlibBase->ReplyPort->mp_SigBit);
 GetMsg(MatrixlibBase->ReplyPort);}
Make(Operation);
}


/* Mit der nächsten Funktion können Sie die Auswahl von Menüpunkten
   Steuern. Der Wert Operation kann die in MATRIX!.H definierten
   Konstanten beinhalten. Für die in MATRIX!.H gekennzeichneten
   Funktionen muß noch der Long l übergeben werden. */

int Make_menu(int Operation,long l)
{
struct MatrixlibBase *MatrixlibBase;

if(MatrixlibBase->log==FALSE) return(-1); /* MATRIX! steht garnicht zur
  Verfügung. Vorher LoginM aufrufen! */
MatrixlibBase->MyMess.ExecMessage.mn_ReplyPort=MatrixlibBase->ReplyPort;
MatrixlibBase->MyMess.ExecMessage.mn_Node.ln_Type=NT_MESSAGE;
MatrixlibBase->MyMess.Class=MENUPICK;
MatrixlibBase->MyMess.Qualifier=0;
MatrixlibBase->MyMess.Code=Operation;
MatrixlibBase->MyMess.IAddress=NULL;
MatrixlibBase->Gad.GadgetID=0;
MatrixlibBase->Out->val.l=l;
Forbid();   /* Zur Sicherheit damit kein anderes Programm MATRIX! ansendet */
SetSignal(0,MatrixlibBase->Out->maske);
PutMsg(MatrixlibBase->MATRIXPort,(struct Message *)&(MatrixlibBase->MyMess));
Permit();  
Wait(1L << MatrixlibBase->ReplyPort->mp_SigBit);
GetMsg(MatrixlibBase->ReplyPort);
Wait(MatrixlibBase->Out->maske);
return(Operation);
}


/* Nun noch zum verändern und lesen von Daten aus MATRIX!:
   Dies wird über die Struktur MATRIX!libBase durchgeführt auf die Sie
   beim öffnen der Library einen Zeiger bekommen.
   In dieser Struktur finden Sie einen Eintrag Out der eine Zeiger auf
   die Kommunikationsstruktur von MATRIX! ist in der ihnen alle Daten
   offen stehen. Wollen Sie z.B. den Koeffizienten in der 3 Zeile der
   4 Spalte der Matrix B auf 7 setzen, können Sie schreiben:
   
   MatrixlibBase->Out->M[1][(3-1)*MatrixlibBase->Out->dim+(4-1)]=7;
   
   M[1] ist dabei der Zeiger auf die 2. Matrix denn M[0] ist der Zeiger auf
   die erste. MatrixlibBase->Out->dim enthält die Größe der Matrizen
   und damit die Anzahl der Elemente in einer Zeile. Die -1 hinter der
   3 und der 4 ist nötigt da der erste Eintrag in der ersten Zeile der Matrix
   nicht die Indices 1,1 sondern 0,0 hat.
   Das lesen aus diesen Werten geht analog;
   Sie können aber auch einfach die folgenden Macros benutzen die in
   MATRIX!.H definiert werden.:   

   MAT(Matrix,x,y)

   Gibt den Wert des Koeffizienten in der x-ten Spalte und y-ten Zeile der
   mit den üblichen Buchstaben bezeichneten Matrix zurück.
   Der oberste linke Koeffizient hat die Koordinaten (1,1).

   VEK(Vektor,y)

   Gibt den Wert des y-ten Koeffizienten des Vektors, der mit den üblichen
   Buchstaben bezeichnet wird, zurück.
   Der oberste linke Koeffizient hat die Koordinaten (1,1).
 
   Sie können beide Macros aber auch zum Beispiel zum Schreiben in die
   Matrix oder in einen Vektor benutzen. Z.B:

   MAT('A',3,3)=17.4;  
 
   Wollen Sie die Ausgabe von MATRIX! mittels einer PRINT Funktion in die Datei
   df0:ausgabe lenken so schreiben Sie:
   
   strcpy(MatrixlibBase->Out->printer,"df0:ausgabe");

   oder benutzen das gleichwertige Macro:

   AUSGABE("df0:ausgabe");
   
   Den Eintrag Rang aus dem Ergebnis der Statistikfunktion erreichen sie durch:
   
   Rang=MatrixlibBase->Out->MStat->Rang;
   
   oder über den Macro MSTATRANG (z.B. Rang=MSTATRANG). Weitere Macros mit denen
   Sie die entsprechenden Ergebnisse der INFO und STATIS Funktionen einfach
   abfragen können sind: 

   MSTATSUMME,MSTATPRODUKT,MSTATDICHTE,MSTATSPUR,MSTATDET,MSTATNIL,MSTATZDIM,
   MSTATSDIM,MSTATSYMMETRISCH,MSTATNORMAL,MSTATORTHOGONAL,MSTATDIAGONAL,
   MSTATTRIAGONAL,MSTATSELBSTINVERS,MSTATPROJEKTION,MSTATSELBSTADJUNGIERT,
   MSTATDEFINIT,MINFODET,MINFORANG und MINFOSPUR
  
   Das Ergebnis einer Normberechnung erreichen Sie über den Macro ERGEBNIS.
   
   Sie können den Inhalt der Statuszeile von MATRIX! wie folgt ausgeben:
   
   printf("Statuszeile: %s\n",MatrixlibBase->Out->string);
   
   Sie können aber wieder auch einfach einen Macro benutzen:

   printf("Statuszeile: %s\n",STATUSZEILE);

   Eine Demonstration einiger Möglichkeiten finden Sie im Programm
   Beispiel und dem zugehörigen Source-Code.
   Weitere Informationen sind in MATRIX!.H zu finden. */

