#import "Controller.h"
#import "ARTDoc.h"
#import "Pattern.h"
#import "ART_Animator.h"

#include <stdio.h>
#import <appkit/Application.h>
#import <appkit/OpenPanel.h>
#import <appkit/appkit.h>
#import <appkit/Button.h>
#import <appkit/Panel.h>
#import <appkit/publicWraps.h>	/* for NXBeep() */
#import <sys/param.h> 		/* for MAXPATHLEN */
#import <string.h>
#import <objc/NXStringTable.h>


static Window *findDocWindow(const char *name);

static char pathname[1024];
BOOL rand_mode;

BOOL getOpenPath(char *buf, char const *theType)
{
    static id openPanel = nil;
    char const *fileTypes[2] = {0,0};
    int opr;
    char *p;

    if (!openPanel)
        openPanel = [OpenPanel new];
    if (theType && *theType)
	fileTypes[0] = theType;
    [NXApp setAutoupdate:NO];
  
    if (p = rindex(buf,'/')) 
      *p='\0';

    if (*buf)
      opr = [openPanel runModalForDirectory:buf
		 file:NULL types:fileTypes];
    else
      //strcpy(buf,NXHomeDirectory());
      opr = [openPanel runModalForDirectory:buf
	 file:NULL types:fileTypes];
    if (opr) {
	strcpy(buf,[openPanel filename]);
	[NXApp setAutoupdate:YES];
	return YES;
    } else {
	[NXApp setAutoupdate:YES];
	return NO;
    }
}


static BOOL getSavePath(char *buf, char const *defaultPath, View *accessory)
{
    static id	savePanel = nil;
    BOOL	ok;
    char	dirName[1024], fileName[256];

    if (!savePanel) {
        const char *const types[2] = {"art", NULL};
        savePanel = [SavePanel new];
        [savePanel setRequiredFileType:types[0]];
    }
  //  [savePanel setAccessoryView:accessory];
    [NXApp setAutoupdate:NO];
    if (defaultPath && *defaultPath) {
	char *p;
	strcpy(dirName,defaultPath);
	if (p = rindex(dirName,'/')) {
	    strcpy(fileName, p+1);
	    *p = '\0';
	} else {
	    strcpy(fileName,defaultPath);
	    fileName[0] = '\0';
	}
	ok = [savePanel runModalForDirectory:dirName file:fileName];
    } else 
	ok = [savePanel runModal];
    [NXApp setAutoupdate:YES];
    if (ok) {
	strcpy(buf,[savePanel filename]);
	return YES;
    } else 
	return NO;
}

@implementation Controller

- init
{
    [super init];
    [controlPanel removeFromEventMask:(NX_KEYDOWNMASK|NX_KEYUPMASK)];
    [controlPanel setFloatingPanel:YES];
    Pat=[[Pattern new] init];
    rand_mode=YES;
    [NXApp loadNibSection:"ARTAnimator.nib" owner:self];
    [Animator initdisplay];
    return self;
}

- appDidInit:sender
{
    [PatFileName setStringValue:STRTAB("no patternfile loaded")];
    [DimQuan setStringValue: " "];
    [self lookCTRL];
    return self;
}

- info:sender
{
    if (!infoPanel)
	[NXApp loadNibSection:"InfoPanel.nib" owner:self];
    [infoPanel makeKeyAndOrderFront:NULL];
    return self;
}


- newARTDoc:sender
{
    if ([Pat fileName]) {
      
      static char filenamebuf[MAXPATHLEN+1];
      [self stopAll];
      strcpy(filenamebuf, [[OpenPanel new] directory]);
      strcat(filenamebuf,STRTAB("/UNTITLED"));
      [self setDocument:[[ARTDoc alloc] init]];
      [currentDocument setFileName:filenamebuf];
      }
    else
      NXRunAlertPanel(STRTAB("no Pat open"),
                      STRTAB("Open Pat first"),
                      STRTAB("bad new OK"),
                      NULL,
                      NULL);
    return self;
}

- openFile:(char *)fileName
{
    id newDocument;
    newDocument = [[ARTDoc alloc] initFromFile:fileName];
    [newDocument setFileName:fileName];
    [self setDocument:newDocument];
    return self;
}

- open:sender
{
    if ([Pat fileName]) {
      if (getOpenPath(pathname,"art")) {
        [self stopAll];
        [self openFile:pathname];
        }
      }
    else
      NXRunAlertPanel(STRTAB("Open Doc no Pat"),
                      STRTAB("first open Pat"),
                      STRTAB("bad open OK"),
                      NULL,
                      NULL);
    return self;
}

- saveAs:sender
{
    char pathname[1024];
    id doc = currentDocument;
        if (doc && getSavePath(pathname,[doc fileName],nil)) { 
	    [doc setFileName:pathname];
	    [doc save:sender];
	}
    return self;
}

- save:sender
{
    [self stopAll];
    if (currentDocument) {
	if ([currentDocument fileName] &&
	    strcmp(strrchr([currentDocument fileName],'/'),
                   STRTAB("/UNTITLED") ) )
	    [currentDocument save:sender];
	else
	    [self saveAs:sender];
    }
    return self;
}
- saveAll:sender
{
    id winList;
    int i;
    int count=0;
    [self stopAll];
    winList=[NXApp windowList];
    i=[winList count];
    while (i--) {
      id win=[winList objectAt:i];
      id delegate=[win delegate];
      if (delegate && [delegate isKindOf:[ARTDoc class]]) {
        [win makeKeyAndOrderFront:nil];
        [delegate save:win];
        }
      }
    return self;
}
- saveLTMdat:sender
{
    [self stopAll];
    if (currentDocument) {
	if ([currentDocument fileName] &&
	    strcmp(strrchr([currentDocument fileName],'/'),
                   STRTAB("/UNTITLED") ) )
	    [currentDocument creatLTMdat:sender];
    }
    return self;
}

- openPatFile:(char *)fileName
{ 
     char buf[256]; 
     int dim=0;
     int quan=0;
     char *p;
     id winList;
     int i;

     [Pat setFileName:fileName];
     strcpy(buf,fileName);
     if (p = rindex(buf,'/')) {
       strcpy(buf, p+1);
       *p = '\0';
       }
      else
        buf[0]='\0';
     if (![Pat load:self]) {
       buf[0]='\0';
       [Pat setFileName:buf]; 
       return self;
       } 
     quan=[Pat Quantity],
     dim=[Pat Dimension];
     [PatFileName setStringValue: buf];
     sprintf(buf,STRTAB("%d patterns of %d"),quan,dim);
     [DimQuan setStringValue: buf];

     // perform every ARTDoc to rezize it's SearchArray
     winList=[NXApp windowList];
     i=[winList count];
     while (i--) {
      id win=[winList objectAt:i];
      id delegate=[win delegate];
      if (delegate && [delegate isKindOf:[ARTDoc class]])
        [delegate setSearchArray];
      }
     return self;
}
- openPat:sender
{ 
     if (getOpenPath(pathname,"pattern")) {
       [self stopAll];
       [self openPatFile:pathname];
       // switch to a corresponding document or open a new one
       if ( ![currentDocument matchWithPat] ) {
         currentDocument=[self nextMatchDoc];
         // if there is no other matching doc open new one
         if (!currentDocument)
           [self newARTDoc:nil];
         }
       }
     return self;
}

- setDocument:aDocument
{
    currentDocument = aDocument;
    return self;
}

- MisMatchAlert
{
     NXRunAlertPanel(
       STRTAB("ART Alert"),
       STRTAB("ART modul doesn't match"),
       STRTAB("OK"),
       NULL,
       NULL);
     return self;
}

- nextMatchDoc
{
    id winList;
    int i;
    winList=[NXApp windowList];
    // looking in the application windowlist for a matching one
    // or return nil for no match
    i=[winList count];
    while (i--) {
      id win=[winList objectAt:i];
      id delegate=[win delegate];
      if (delegate && [delegate isKindOf:[ARTDoc class]])
        if ([delegate matchWithPat]) {
          // make it main and return
          [win makeKeyAndOrderFront:nil];
          return delegate;
          }
      }
    return nil;
}

- (int)countEditedWindows
{
    id winList;
    int i;
    int count=0;
    winList=[NXApp windowList];
    i=[winList count];
    while (i--) {
      if ([[winList objectAt:i] isDocEdited])
        count++;
      }
    return count;
}


- document
{
    return currentDocument;
}



- (BOOL)Rand_sel
{
  return ( 0==[[selectMtx selectedCell] tag] ) ? YES:NO;
}

- (BOOL)Pat_step
{
  return ( 0==[[stepMtx selectedCell] tag] ) ? YES:NO;
}

- setStopState
{
     [stopButton setState:0];
     return self;
}
- setGoState
{
     [stopButton setState:1];
     return self;
}

-stopAll
{
     id winList;
     int i;
     winList=[NXApp windowList];
     i=[winList count];
     while (i--) {
       id win=[winList objectAt:i];
       id delegate=[win delegate];
       if (delegate && [delegate isKindOf:[ARTDoc class]])
         [delegate set_stop];
      }
     [self setStopState];
     return self;
}

- stop_go:sender
{
     if (currentDocument)
       if ([currentDocument matchWithPat])
         if ([stopButton state]) {
           [animatorPanel orderFront:nil];
           [currentDocument set_go];
           }
         else
           [currentDocument set_stop];
       else
         NXBeep();
     return self;
}
- lookCTRL
{
     [stepButton setEnabled:NO];
     [stopButton setEnabled:NO];
     return self;
}
- unlookCTRL
{
     [stepButton setEnabled:YES];
     [stopButton setEnabled:YES];
     return self;
}

- step:sender
{
     if (currentDocument)
       if ([currentDocument matchWithPat])
         if ([self Pat_step]) {
           [stepButton setEnabled:NO];
           [currentDocument stepPattern];
           [stepButton setEnabled:YES];
           }
         else
           [currentDocument step:self];
       else
         NXBeep();
     return self;
}
- checkDocument
{
     char buf[256];
     char *p;
     if (currentDocument)
       if ([currentDocument fileName]) {
         strcpy(buf,[currentDocument fileName]);
         if (p = rindex(buf,'/')) {
           strcpy(buf, p+1);
           *p = '\0';
           }
          else
            buf[0]='\0';
         if ([currentDocument matchWithPat])
           strcat(buf," match");
         else
           strcat(buf," not match");
         }
       else
         sprintf(buf,"no name");
     else
       sprintf(buf,"no document");
     [PatFileName setStringValue: buf];
     return self;
}

- appDidUpdate:sender
{
   //  [self checkDocument];
     if ([[NXApp windowList] count]==0) [self lookCTRL];
     return self;
}
- appDidHide:sender
{
       return self;
}
- appDidBecomeActive:sender
{
    id win;
    [animatorPanel orderFront:nil];
    [controlPanel orderFront:nil];
    if (currentDocument) 
      if (win = findDocWindow([currentDocument fileName]))
        [win makeKeyAndOrderFront:self];
     //   [win orderFront:self];
    return self;
}
- appDidResignActive:sender
{
    return self;
}


- appWillTerminate:sender
{
     if ([self countEditedWindows]>0) {
       int q=NXRunAlertPanel(
               STRTAB("ART Quit"),
               STRTAB("ART Quit message"),
               STRTAB("review unsaved"),
               STRTAB("quit anyway"),
               STRTAB("Cancel"));
       if (q==1) {
         int i=0;
         id winList;
         winList=[NXApp windowList];
         i=[winList count];
         while (i--) {
           id win=[winList objectAt:i];
           if ([[win delegate] isKindOf:[ARTDoc class]])
             [win performClose:nil];
           }
         return self;
       }
       if (q==-1)
         return nil;
       }
     return self;
}

- Animator_id
{ 
     return Animator; 
}
- Pattern_id
{ 
     return Pat; 
}
- stringTable
{
    return stringTable;	
}

- (int)appOpenFile:(const char *)path type:(const char *)type
{
    BOOL success = NO;
    Window *win;
    strcpy(pathname,path);
    if (type) {
      // pattern file
      if (!strcmp(type, "pattern")) {        
        [self openPatFile:pathname];
        success = YES;
        }
      // ARTDoc file
      else {
        if (!strcmp(type, "art")) {
          // does the file exist already
          if (win = findDocWindow(path)) {
	    [win makeKeyAndOrderFront:self];
	    success = YES;
            }
          // on ergo open form file
          else {
            if ([self openFile:pathname]) success = YES ;
            }
          }
        }
      }
    if (!success) {
      NXRunAlertPanel(
	STRTAB("open alert title"),
	STRTAB("open alert message"),
	STRTAB("OK"),
	NULL,NULL,path);
      }
    return success;
}

/* This says we can accept any number of appOpenFile:type: messages. */
- (BOOL)appAcceptsAnotherFile:sender {
    return YES;
}
static Window *findDocWindow(const char *name) {
    int count;
    id document;
    Window *window;
    List *windowList;
    const char *realPath;
    const char *otherRealPath;
    char realPathBuf[MAXPATHLEN+1];

    windowList = [NXApp windowList];
    count = [windowList count]-1;
    realPath=name;
//    realPath = realpath(name, realPathBuf) ? realPathBuf : name;
    while (count--) {
	window = [windowList objectAt:count];
	document = [window delegate];
	if (document && ([document isKindOf:[ARTDoc class]]) ) {
	    otherRealPath = [document fileName];
	    if (otherRealPath && !strcmp(otherRealPath, realPath))
		return window;
	}
    }
    return nil;
}


@end
