#import "dotGraphWatcher.h"
#import "utils.h"
#import "tamsutils.h"
#import "prefBoss.h"
#import "MGWPopUpButton.h"



int moveInArray(id who, NSMutableArray *theArray, int row)
{
    int dndNdx;
    dndNdx = [theArray indexOfObject: who];
    if(row > dndNdx)
    {
        [theArray insertObject: who atIndex: row];
        [theArray removeObjectAtIndex: dndNdx];
        return row;
    }
    else if (row < dndNdx)
    {
    [theArray removeObject: who];
      [theArray insertObject: who atIndex: row];
        return row +1;
    }
    return row;
    
}
NSString *seDirNames [] = {
    @"Both",
    @"Forward",
    @"Backward"
};
NSString *nodeShapes[]={
    @"plaintext",
    @"box",
    @"ellipse",
    @"hexagon",
    @"house",
    @"point"};

NSString *edgeType[]={
    @"both",
    @"forward",
    @"back",
    @"none"};
NSString *edgeStyle[]= {
    @"solid",
    @"dotted",
    @"dashed",
    @"invis"};
NSString *borderStyle[] = {
    @"solid",
    @"bold",
    @"dotted",
    @"filled"};

@implementation dotGraphWatcher

-(id) init
{
    [super init];
    dndList = [[NSMutableArray alloc] init];
    colList = [[NSMutableArray alloc] init];
    pairList = [[NSMutableArray alloc] init];
    pairCount = [[MWDoubleDictionary alloc] init];
    return self;
}
-(void) onExit
{
    [colList release];
    [pairList release];
    [pairCount release];
    [attribs release];
    [pairAttribs release];
    [edgeAttribs release];
    [seDict release];
    [snDict release];
}
    
-(void) dealloc
{
    [dndList release];
    [super dealloc];
}

- (IBAction)addDotGraph:(id)sender
{
}
-(int) codeLevel
{
   return [codeLevel intValue];
}
//NSPRINTF(X) appendString: [NSString stringWithFormat: X]
-(NSString *) properNameForVariable: (NSString *) X Value: (NSString *) Y
{
    //is this _code?
    if([X isEqualToString: @"_code"] && [codeLevelSwitch state] == NSOnState)
    {
        int lvl;
        NSString *nc;
        lvl = [self codeLevel];
        nc = codeToLevel(Y, lvl);
        return nc;
    }
    else
        return Y;
}
-(NSString *) nodeNameForVariable: (NSString *) X Value: (NSString *) Y
{
        //is this _code?
    if([X isEqualToString: @"_code"] && [codeLevelSwitch state] == NSOnState)
    {
        int lvl;
        NSString *nc;
        lvl = [self codeLevel];
        nc = codeToLevel(Y, lvl);
        return [NSString stringWithFormat: @"%@:%@",X, nc];
    }
    else
        return [NSString stringWithFormat: @"%@:%@",X, Y];
}
#define NODENAME(X,Y) [self nodeNameForVariable: X Value: Y]
#define PROPERNAME(X,Y) [self properNameForVariable: X Value: Y]

-(void) savePanelDidEnd: (NSSavePanel *) sheet returnCode: (int) returnCode contextInfo: (void *) contextInfo
{

    if(returnCode == NSOKButton)
    {
        [self openGraphviz: [sheet filename]];
    }
    else
    {

    }
}

-(void) projectGraphviz: (NSString *) theName
{
	NSTask *mytask;

	mytask = [[NSTask alloc] init];

	[mytask setLaunchPath: [gPrefBoss dotDir]];
	[mytask setArguments: [NSArray arrayWithObjects: @"-Tps", [NSString stringWithFormat: @"-o%@.ps",theName],theName, nil]];
/*
	[[NSFileManager defaultManager] createFileAtPath: [NSString stringWithFormat: @"%@.ps", theName]
		contents: @""
		attributes: [NSDictionary dictionary]];
	[mytask setStandardOutput: [NSFileHandle fileHandleForWritingAtPath: [NSString stringWithFormat: @"%@.ps", theName]]];
*/

	[mytask launch];
    //[mytask waitUntilExit];

	if([gPrefBoss useGV] == 1)
	{
		NSLog(@"Using gv\n");
		[NSTask launchedTaskWithLaunchPath: [gPrefBoss gvDir] arguments: [NSArray arrayWithObjects: [NSString stringWithFormat: @"%@.ps",theName], nil]];
	}
	else
		if([[NSWorkspace sharedWorkspace] openFile: [NSString stringWithFormat: @"%@.ps", theName]] == NO)
		{
			NSString *mywarn, *mygraphfile;
			mygraphfile = [NSString stringWithFormat: @"%@.ps", theName];
			mywarn = [NSString stringWithFormat: @"Could not open application for file \"%@\"", mygraphfile];
			NSWARNING(mywarn);	
		}



}

-(void) openGraphviz: (NSString *) theName
{
    
    {
       // NSString *theName = [NSString stringWithFormat: @"/tmp/tams %@%@.dot", [nameField stringValue], uniqueFileName()];
        //NSString *theName = @"/Users/Matthew/out.dot"
        NSMutableString *ans = [[NSMutableString alloc] init];
        NSArray *data;
        int i,j, k,cnt, cnt2, cnt3;
        NSMutableArray *fieldValues = [[NSMutableArray alloc] init];
        
        //set the open
        [ans setString: [NSString stringWithFormat: @"digraph \"%@\" {\ngraph[overlap=no]\n", [nameField stringValue]]];
        
        [ans appendString: [NSString stringWithFormat: @"edge[dir=%@ style=%@]\n", edgeType[[[arrowDirMenu selectedItem] tag]], edgeStyle[[[lineTypeMenu selectedItem] tag]]]];
        
        //get the selected cols
        //assemble the scale
        {
            if([[levelMenu selectedItem] tag] == 0) 
            {
                [ans appendString: [NSString stringWithFormat: @"{\nedge[color=white]\nnode[shape=plaintext]\n"]];
                cnt = [colList count];
                for(i = 0; i < cnt; i++) {
                    if(i == 0)[ans appendString: [NSString stringWithFormat: @"\"%@\"",[colList objectAtIndex: i]]];
                    else [ans appendString: [NSString stringWithFormat:@"->\"%@\"", [colList objectAtIndex: i]]];
                }
                [ans appendString: @"\n}\n\n"];
            }
            
        }
        
        //get the data
        data = [theBoss hotData];
        //go through and for each column assemble the data and 
        {
            cnt = [colList count];
            cnt2 = [data count];
            for(i = 0; i < cnt; i++)
            {
                for(j = 0; j < cnt2; j++)
                {
                    id thisRec;
                    thisRec = [data objectAtIndex: j];
                    addUniqueToArray(fieldValues, PROPERNAME([colList objectAtIndex: i], [thisRec objectForKey: [colList objectAtIndex: i]]));
                }
                
                //then create a "same"
                if([[levelMenu selectedItem] tag] == 0) 
                {
                    [ans appendString: [NSString stringWithFormat: @"{rank=same; \"%@\";", [colList objectAtIndex: i]]];
                    cnt3 = [fieldValues count];
                    for(j=0; j < cnt3; j++)
                    {
                        [ans appendString: [NSString stringWithFormat: @" \"%@\"", NODENAME([colList objectAtIndex: i], [fieldValues objectAtIndex: j])]];
                    }
                    [ans appendString: @"}\n"];
                }
                //at the same time we should do the boxes!!
                
                FORALL(fieldValues)
            {
                    NSString *a;//, *aa;
                    a = [self findAttrib: [colList objectAtIndex: i] forWhat: temp];
                    [ans appendString: [NSString stringWithFormat: @"\"%@\"[label=\"%@\"]\n", 
                        NODENAME([colList objectAtIndex: i], temp), PROPERNAME([colList objectAtIndex:i], temp)]];
                    /*
                    if((aa = [nsDict objectForKey: NODENAME([colList objectAtIndex: i], temp)]) != nil)
                    {
                        [ans appendString: [NSString stringWithFormat: @"\"%@\"%@\n",
                            NODENAME([colList objectAtIndex: i], temp), aa]];
                    }
                     */
                    if([a isEqualToString: @""] == NO)
                    {
                        [ans appendString: a];
                        [ans appendString: @"\n"];
                    }
            }
                ENDFORALL;
                [fieldValues removeAllObjects];
            }
        }
        [fieldValues release];
        //go through and count the # of maps
        {
            NSArray *fk, *sk;
            NSString *ea;
            int xcnt;
            int ycnt;
            ycnt = xcnt = cnt;
            if([[typeMenu selectedItem] tag] == 0)
                xcnt = 1;
            [edgeAttribs removeAllObjects];
            [pairCount removeAllObjects];
            for(i = 0; i < xcnt; i++)
            {
                if([[typeMenu selectedItem] tag] == 2)
                {
                    ycnt = i+2; //kludge to make the this for loop only go one time
                    if( ycnt > cnt) continue;
                }
        
                for(j=i+1; j < ycnt; j++)
                {
                    for(k=0; k<cnt2; k++)
                    {
                        id thisRec;
                        thisRec = [data objectAtIndex: k];
                        [pairCount incKey1: 
                            NODENAME([colList objectAtIndex: i], [thisRec objectForKey: [colList objectAtIndex: i]])
                                      key2: 
                            NODENAME([colList objectAtIndex: j], [thisRec objectForKey: [colList objectAtIndex: j]])];
                        ea = [pairAttribs objectForKey1: [colList objectAtIndex: i] key2: [colList objectAtIndex: j]];
                        if(ea != nil)
                        {
                            [edgeAttribs setObject: ea
                                           forKey1:
                                NODENAME([colList objectAtIndex: i], [thisRec objectForKey: [colList objectAtIndex: i]])
                                              key2: 
                                NODENAME([colList objectAtIndex: j], [thisRec objectForKey: [colList objectAtIndex: j]])
                                ];
                        }
                    }
                    
                }
            }
            //go through and make the maps
            fk = [pairCount firstKeys];
            FORALL(fk)
            {
                int mcnt;
                NSString *eans;
                sk = [pairCount keysForKey1: temp];
                mcnt = [sk count];
                for(i=0; i < mcnt; i++)
                {
                    NSString *currVal = [sk objectAtIndex: i];
                    if([countSwitch state] == NSOnState)
                        [ans appendString: [NSString stringWithFormat: @"\"%@\"->\"%@\"[label=\"%d\"]",
                            temp, currVal, [pairCount intForKey1: temp key2: currVal]]];
                    else
                        [ans appendString: [NSString stringWithFormat: @"\"%@\"->\"%@\"",
                            temp, currVal]];
                    if((eans = [seDict objectForKey1: temp key2: @"Backward"]) != nil)
                    {
                        //first
                        [ans appendString: eans];
                    }
                    else if((eans = [seDict objectForKey1: temp key2: @"Both"]) != nil)
                    {
                        //first
                        [ans appendString: eans];
                    }
                    else if((eans = [seDict objectForKey1: currVal key2: @"Forward"]) != nil)
                        [ans appendString: eans];
                    else if((eans = [seDict objectForKey1: currVal key2: @"Forward"]) != nil)
                        [ans appendString: eans];
                    else if([edgeAttribs objectExistsForKey1: temp key2: currVal])
                    {
                        [ans appendString:  [edgeAttribs objectForKey1: temp key2: [sk objectAtIndex: i]]];
                    }
                    [ans appendString: @"\n"];
                    
                }
            }
            ENDFORALL;
        }
        [ans appendString: @"}\n"];
        [ans writeToFile: theName atomically: YES];
        if(saveFlag == NO)
		[self projectGraphviz: theName];
//            [[NSWorkspace sharedWorkspace] openFile:theName withApplication: @"Graphviz.app"];
    }
}
- (IBAction)cancel:(id)sender
{
    [thePane orderOut: sender];
    [NSApp endSheet: thePane returnCode: 0];
}

- (IBAction)delAllDotGraph:(id)sender
{
}

- (IBAction)delDotGraph:(id)sender
{
}
-(void) dotGraphDidEnd: (NSWindow *) mySheet returnCode: (int) returnCode contextInfo: (void *) contextInfo
{
    if(returnCode)
    {
        
    }
    [self onExit];
}
- (IBAction)writeDotGraph:(id)sender
{
    NSSavePanel *msp;
    NSEnumerator *nnn;
    NSNumber *ndx;
    nnn = [fieldList selectedRowEnumerator];
    [colList removeAllObjects];
    while((ndx = [nnn nextObject]) != nil)
    {
        [colList addObject: [colPool objectAtIndex: [ndx intValue]]];
    }
    if([colList count] <= 1)
    {
        NSWARNING(@"Select fields for graphing");
        return;
    }
    
    if(saveFlag == YES)
    {
        msp = [NSSavePanel savePanel];
        [msp setDelegate: self];
        [msp setRequiredFileType: @"dot"];
        [msp beginSheetForDirectory: nil file: nil modalForWindow: thePane modalDelegate: self didEndSelector: @selector(savePanelDidEnd:returnCode:contextInfo:) contextInfo: nil];
    }
    else
    {
        NSString *theName = [NSString stringWithFormat: @"/tmp/tams %@ %@.dot", [nameField stringValue], uniqueFileName()];
        [self openGraphviz: theName];
    }
    //[thePane orderOut: sender];
    //[NSApp endSheet: thePane returnCode: 1];

}
-(IBAction) override: (id) sender
{

    if([overrideSwitch state] == NSOffState)
    {
	saveFlag = NO;
/*
        if(graphvizInstalled == NO)
        {
            NSWARNING(@"Graphviz is not properly installed, will prompt for file to save");
            [overrideSwitch setState: NSOnState];
            saveFlag = YES;
        }
        else
            saveFlag = NO;
*/
    }
    else
    {
        saveFlag = YES;
    }
    if(saveFlag == YES)
        [saveButton setTitle: @"Save graph"];
    else
        [saveButton setTitle: @"Show graph"];
    
    
}
-(void) doDotGraph
{
    id columns;
    int  n;
/*    
    if([[NSWorkspace sharedWorkspace] fullPathForApplication: @"Graphviz"] == nil)
        graphvizInstalled = NO;
    else
        graphvizInstalled = YES;
*/
	graphvizInstalled = YES;
    if([gPrefBoss saveGraphviz] == 0 && graphvizInstalled ==NO)
    {
//        NSWARNING(@"Graphviz is not properly installed, will prompt for file to save");
//        saveFlag = YES;
	saveFlag = NO;
    }
    else if (graphvizInstalled == NO)
    {
        saveFlag = YES;
    }
    else if ([gPrefBoss saveGraphviz] == 1)
        saveFlag = YES;
    else
        saveFlag = NO;
    [codeLevel setIntValue: [theBoss codeLevel]];
    if(saveFlag == YES) [overrideSwitch setState: NSOnState];
    else [overrideSwitch setState: NSOffState];
    [dndList removeAllObjects];
//    [fieldList setVerticalMotionCanBeginDrag: YES];
    [fieldList registerForDraggedTypes: [NSArray arrayWithObjects: NSStringPboardType, nil]];
NSLog(@"register drags\n");
    attribs = [[NSMutableArray alloc] init];
    colList = [[NSMutableArray alloc] init];
    colPool = [[NSMutableArray alloc] init];
    pairList = [[NSMutableArray alloc] init];
    pairCount = [[MWDoubleDictionary alloc] init];
    pairAttribs = [[MWDoubleDictionary alloc] init];
    edgeAttribs = [[MWDoubleDictionary alloc] init];
    snDict = [[NSMutableDictionary alloc] init];
    seDict = [[MWDoubleDictionary alloc] init];
    columns = [theBoss tableColumns];
    [nGroupMenu removeAllItems];
    [fromMenu removeAllItems];
    [toMenu removeAllItems];
    [snVarMenu removeAllItems];
    [snValMenu removeAllItems];
    [seVarMenu removeAllItems];
    [seValMenu removeAllItems];
    
    FORALL(columns)
    {
        NSString *idfr = [temp identifier];
        if([idfr isEqualToString: @"#"])
            continue;
        else if([idfr isEqualToString: @"_code"])
            [colPool addObject: [[idfr copy] autorelease]];
        else if([idfr characterAtIndex: 0] == '_')
            continue;
        else
            [colPool addObject: [[idfr copy] autorelease]];
            
 /*              OLD code  
        if([theBoss fieldType: [temp identifier]] > 0)
        {
            [colPool addObject: [temp identifier]];
        }
        else
        {
            if([[temp identifier] isEqualToString: @"_code"] ||
                [[temp identifier] isEqualToString: @"_doc"]  )
                [colPool addObject: [temp identifier]];
        }
*/
    }

    ENDFORALL;
    n = [colPool count];
    //[snVarMenu setDelegate: self];
    //[seVarMenu setDelegate: self];
    /*
    for(i = 0 ; i < n; i++)
        {
        [ snVarMenu addItemWithTitle: [colPool objectAtIndex: i] action: @selector(snValHandler) keyEquivalent: @""];
        [ seVarMenu addItemWithTitle: [colPool objectAtIndex: i] action: @selector(seValHandler) keyEquivalent: @""];

        
        }
    */
    
    [snVarMenu addItemsWithTitles: colPool];
    [snVarMenu setAction: @selector(snValHandler:)];
    [snVarMenu setEnabled: YES];
NSLog(@"added snVal\n");
    [seVarMenu addItemsWithTitles: colPool];
    [seVarMenu setAction: @selector(seValHandler:)];
    [seVarMenu setEnabled: YES];
NSLog(@"added seVal\n");
    [self seValHandler: nil];
    [self snValHandler: nil];
    
    [nGroupMenu addItemsWithTitles: colPool];
NSLog(@"ngroupmenu\n");
    [fromMenu addItemsWithTitles: colPool];
NSLog(@"fromMenu \n");
    [toMenu addItemsWithTitles: colPool];
    NSLog(@"added menus\n");
    [fieldList reloadData];
    [attribTable reloadData];
    [edgeAttribTable reloadData];
    [seTable reloadData];
    [snTable reloadData];
NSLog(@"tables reloaded\n");
    if([gPrefBoss saveGraphviz])
        [saveButton setTitle: @"Save graph"];
    else
        [saveButton setTitle: @"Show graph"];
    [NSApp beginSheet: thePane
       modalForWindow: nil
	modalDelegate: self
        didEndSelector: @selector(dotGraphDidEnd:returnCode:contextInfo:)
          contextInfo: nil];
    
}
-(IBAction) addAttrib:(id)sender
{
    NSMutableDictionary *tmp;
    int n;
    NSString *wh;
    
    n = [[nShapeMenu selectedItem] tag];
    wh =nodeShapes[n];
    tmp = [[NSMutableDictionary alloc] init];
    [tmp setObject: [[[nGroupMenu titleOfSelectedItem] copy] autorelease] forKey: @"name"];
    [tmp setObject: [[wh copy] autorelease] forKey: @"shape"];
    [tmp setObject: [[borderStyle[[[nBorderMenu selectedItem] tag]] copy] autorelease] forKey: @"border"];
    [attribs addObject: [tmp autorelease]];
    [attribTable reloadData];
    
    
}
- (int)numberOfRowsInTableView:(NSTableView *) tt
{
    if(tt == fieldList)
        return [colPool count];
    if(tt == attribTable)
        return [attribs count];
    if(tt == edgeAttribTable)
        return [pairAttribs count];
    if(tt == snTable) return [[snDict allKeys] count];
    if(tt == seTable) return [seDict count];
}

-(IBAction) delAttrib: (id) sender
{
    int n;
    n = [attribTable selectedRow];
    if( n >= 0) [attribs removeObjectAtIndex: n];
    [attribTable reloadData];
}
-(IBAction) delAllAttrib: (id) sender
{
    [attribs removeAllObjects];
    [attribTable reloadData];
}

-(NSString *) attribNdx: (int) rowIndex
{
    NSDictionary *who = [attribs objectAtIndex: rowIndex];
    return [NSString stringWithFormat: @"\"%@\"[shape=%@ style=%@]", [who objectForKey: @"name"], [who objectForKey: @"shape"], [who objectForKey: @"border"]];
}    
-(NSString *) findAttrib: (NSString *) who forWhat: (NSString *) what
{
    NSString *pn;
    NSString *ans;
    NSString *nn;
    pn = PROPERNAME(who, what);
    nn = NODENAME(who, pn);
    if((ans = [snDict objectForKey: nn]) != nil)
        return ans;
    FORALL(attribs)
    {
        if([[temp objectForKey: @"name"] isEqualToString: who])
            return [NSString stringWithFormat: @"\"%@:%@\"[shape=%@ style=%@]", who,pn, [temp objectForKey: @"shape"],
                [temp objectForKey: @"border"]];
    }
    ENDFORALL;
    return @"";
}
- (NSDragOperation)tableView:(NSTableView *)tableView validateDrop:(id)info proposedRow:(int)row proposedDropOperation:(NSTableViewDropOperation)operation
{
    if(tableView == fieldList)
        return  NSDragOperationMove;//NSDragOperationEvery
    else
        return    NSDragOperationNone ;
}
- (BOOL)tableView:(NSTableView *)tableView acceptDrop:(id <NSDraggingInfo>)info row:(int)row dropOperation:(NSTableViewDropOperation)operation
{
    int n;
   if(tableView == fieldList)
    {
        int currSpot;
        /*
        [colPool removeObjectsInArray: dndList];
        FORALL(dndList)
        {
            [colPool insertObject: temp atIndex: row + __i];
        }
        ENDFORALL;
        return YES;
         */
#ifdef SINGLEDRAG
        if(row > dndNdx)
        {
            NSString *tmp;
            tmp = [colPool objectAtIndex: dndNdx];
            [colPool insertObject: tmp atIndex: row];
            [colPool removeObjectAtIndex: dndNdx];
        }
        else if (row < dndNdx)
        {
            NSString *tmp;
            tmp = [colPool objectAtIndex: dndNdx];
            [colPool insertObject: tmp atIndex: row];
            [colPool removeObjectAtIndex: dndNdx + 1];
        }
        [tableView reloadData];
        return YES;
#else
        n = [dndList count];
        currSpot = row;
        FORALL(dndList)
        {
            currSpot = moveInArray(temp, colPool, currSpot);
        }
        ENDFORALL;
        [tableView reloadData];
        [tableView deselectAll: nil];
        FORALL(dndList)
        {
            [tableView selectRow: [colPool indexOfObject: temp] byExtendingSelection: YES];
        }
        ENDFORALL;
        [dndList removeAllObjects];
        return YES;
        
#endif
    }
    else return NO;
}
- (BOOL)tableView:(NSTableView *)tableView writeRows:(NSArray *)rows toPasteboard:(NSPasteboard *)pboard
{
    id testid;
    testid = fieldList;
    
    if(tableView == fieldList)
    {
        /*
         
        [dndList removeAllObjects];
        FORALL(rows)
        {
            [dndList addObject: [colPool objectAtIndex: [temp intValue]]];
        }
        ENDFORALL;
        [pboard setString: [dndList objectAtIndex: 0] forType: NSStringPboardType];
        return YES;
         */
#ifdef SINGLEDRAG
        if([rows count] != 1) return NO;
        dndNdx = [[rows objectAtIndex: 0] intValue];
        [pboard setString: [colPool objectAtIndex: [[rows objectAtIndex: 0] intValue]] forType: NSStringPboardType];
        return YES;
#else
        [dndList removeAllObjects];
        FORALL(rows)
        {
            [dndList addObject: [colPool objectAtIndex: [temp intValue]]];
        }
        ENDFORALL;
        [pboard	declareTypes:[NSArray arrayWithObject:NSStringPboardType]
                       owner:self];
        [pboard setString: [colPool objectAtIndex: [[rows objectAtIndex: 0] intValue]] forType: NSStringPboardType];
        return YES;
#endif
        
    }
    else return NO;
}

- (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex
{
    if(aTableView == fieldList)
        return [colPool objectAtIndex: rowIndex];
    if(aTableView == attribTable)
    {
        return [self attribNdx: rowIndex];
        
    }
    if(aTableView == edgeAttribTable)
    {
        NSArray *aa;
        NSDictionary *dd;
        aa = [pairAttribs toArray];
        dd = [aa objectAtIndex: rowIndex];
        return [NSString stringWithFormat: @"%@->%@%@",
            [dd objectForKey: @"key1"], [dd objectForKey: @"key2"], [dd objectForKey: @"object"]];
    }
    if(aTableView == snTable)
    {
        NSString *who;
        who = [[snDict allKeys] objectAtIndex: rowIndex];
        return [NSString stringWithFormat: @"%@%@", who, [snDict objectForKey: who]];

    }
    if(aTableView == seTable)
    {
        NSArray *aa;
        NSDictionary *rr;
        aa = [seDict toArray];
        rr = [aa objectAtIndex: rowIndex];
        return [NSString stringWithFormat: @"%@%@ %@", [rr objectForKey: @"key1"], [rr objectForKey: @"object"],
            [rr objectForKey: @"key2"]];
        
    }
    
}
/*
-(NSString *) edgeAttribsForFrom: (NSString *) from To: (NSString *) to
{
    NSString *ans;
    if((ans = [seDict objectForKey: from]) != nil)
        return ans;
    else if((ans = [seDict objectForKey: to]) != nil)
        return ans;
    else
        return [pairAttribs objectForKey1: from key2: to];
}
*/
-(IBAction) addEdgeAttrib: (id)sender
{
    NSString *sss;
    sss = [NSString stringWithFormat: @"[dir=%@ style=%@]",
        edgeType[[[ftDirMenu selectedItem] tag]], edgeStyle[[[ftStyleMenu selectedItem] tag]]];
    [pairAttribs setObject: sss forKey1: [fromMenu titleOfSelectedItem] key2: [toMenu titleOfSelectedItem]];
    [edgeAttribTable reloadData];
}
-(IBAction) delEdgeAttrib: (id) sender
{
    NSArray *aa;
    NSDictionary *dd;
    int n; n = [edgeAttribTable selectedRow];
    if(n < 0) return;
    aa = [pairAttribs toArray];
    dd = [aa objectAtIndex: n];
    [pairAttribs removeObjectForKey1: [dd objectForKey: @"key1"] key2: [dd objectForKey: @"key2"]];
    [edgeAttribTable reloadData];
    
}
-(IBAction) delAllEdgeAttrib: (id) sender
{
    [pairAttribs removeAllObjects];
    [edgeAttribTable reloadData];
}

-(void) buildVarMenuFrom: (NSPopUpButton *) varMenu to: (NSPopUpButton *) valMenu
{
    NSMutableArray *vals = [NSMutableArray array];
    NSArray *arr = [theBoss hotData];
    NSString *varName;
    
	if([varMenu indexOfSelectedItem] < 0) return;
    varName = [varMenu titleOfSelectedItem];
    
    [valMenu removeAllItems];
    
    FORALL(arr)
    {
        NSString *rn = PROPERNAME(varName, [temp objectForKey: varName]);
	
        addUniqueToArray(vals, rn);
        
    }
    ENDFORALL;
    [valMenu addItemsWithTitles: vals];
    
    
}
-(IBAction) snValHandler: (id) sender
{
    [self buildVarMenuFrom: snVarMenu to:  snValMenu];
}

-(IBAction) snAdd: (id) sender
{
    if([snValMenu count] == 0) return;
    [snDict setObject: [NSString stringWithFormat: @"[shape=%@ style=%@]",
                    nodeShapes[[[snShapeMenu selectedItem] tag]],
                    borderStyle[[[snStyleMenu selectedItem] tag]]]
               forKey: NODENAME([snVarMenu titleOfSelectedItem], [snValMenu titleOfSelectedItem])];
        
    [snTable reloadData];
}

-(IBAction) snDel: (id) sender{
    int n;
    NSString *who;
    
    n = [snTable selectedRow];
    who = [[snDict allKeys] objectAtIndex: n];
    [snDict removeObjectForKey: who];
    [snTable reloadData];
}
-(IBAction) snDelAll: (id) sender{
    [snDict removeAllObjects];
    [snTable reloadData];
}
-(IBAction) seValHandler: (id) sender
{
    [self buildVarMenuFrom: seVarMenu to:  seValMenu];
    
}
-(IBAction) seAdd: (id) sender
{
    if([seValMenu count] == 0) return;
    [seDict setObject: [NSString stringWithFormat: @"[dir=%@ style=%@]",
        edgeType[[[seShapeMenu selectedItem] tag]],
        edgeStyle[[[seStyleMenu selectedItem] tag]]]
        
              forKey1: NODENAME([seVarMenu titleOfSelectedItem], [seValMenu titleOfSelectedItem])
                 key2: seDirNames[[[seDirMenu selectedItem] tag]]];
    [seTable reloadData];
        
}
-(IBAction) seDel: (id) sender{
    int n;
    NSDictionary *dd;
    NSArray *aa;
    aa = [seDict toArray];
    n = [seTable selectedRow];
    dd = [aa objectAtIndex: n];
    
    [seDict removeObjectForKey1: [dd objectForKey: @"key1"] key2: [dd objectForKey: @"key2"]];
    [seTable reloadData];
}
-(IBAction) seDelAll: (id) sender
{
    [seDict removeAllObjects];
    [seTable reloadData];
}

@end
