/* InspectCut.m		by Mike Gravina		November 1991
 * Controls the cuts on plots
 *
 * Copyright (C)  1991  The Board of Trustees of
 * The Leland Stanford Junior University.  All Rights Reserved.
 */ 

#import "InspectCut.h"

const char InspectCut_h_rcsid[] = INSPECTCUT_H_ID;
const char InspectCut_m_rcsid[] = "$Id: InspectCut.m,v 1.44 1992/04/20 01:37:46 pfkeb Rel $";

#import <appkit/Application.h>
#import <appkit/Button.h>
#import <appkit/Panel.h>
#import <appkit/Form.h>
#import <appkit/NXBrowser.h>
#import <appkit/NXBrowserCell.h>
#import <appkit/Matrix.h>
#import <objc/List.h>
#include <string.h>

#import "FineSlider.h"
#import "DrawDocument.h"
#import "HDraw.h"
#import "HGraphicView.h"
#import "Plot.h"
#import "NewInspector.h"

#define SCALE_FACTOR 5.0
#define CUT_HI 0
#define CUT_LO 1

 /*
  * we want to KEEP what we select, but hippo wants to DELETE it...
  * hence inverse cut types...
  */
char* cutTypeInverse[] = {"h_cut_gt", "h_cut_lt", "h_cut_outside",  "h_cut_in_incl"}; 
	
 
@implementation InspectCut
- initInspFor:aDraw
{
    [super initInspFor:aDraw];
    
    [NXApp loadNibSection:"InspectCut.nib" owner:self
           withNames:NO fromZone:[self zone]];
    
    sliders[0] = cutVal1Slider;
    sliders[1] = cutVal2Slider;
    [ self setSliders:NO];
    [sliders[CUT_LO] setScaleFactor:SCALE_FACTOR];
    [sliders[CUT_HI] setScaleFactor:SCALE_FACTOR];
    [self setShowAllState:NO];
    
    [theInspector addView:[contentBox contentView]
    		 withName:"Cut Options" withSupervisor:self];
    return self;
}

- setSliders:(BOOL)flag
{
    float	xlp, xhp;
    double	xl,  xh;
    BOOL 	val2Set;
    
    if ( !flag ) {
        [sliders[0] setEnabled:NO];
	[sliders[1] setEnabled:NO];
	[cutValueForm setStringValue:"" at:CUT_LO];
	[cutValueForm setStringValue:"" at:CUT_HI];
	[cutValueForm  setEnabled:NO];
        return self;
    }
    varlo = selectedTuple->nlow[parms.varIndex];
    varhi = selectedTuple->nhigh[parms.varIndex];
    [cutPlot getRangeForAxis:XAXIS low:&xlp high:&xhp];
    xl = (varlo < xlp) ? xlp : varlo;
    xh = (varhi > xhp) ? xhp : varhi;
    [sliders[CUT_HI] setMinValue: xl];
    [sliders[CUT_HI] setMaxValue: xh];
    [sliders[CUT_LO] setMinValue: xl];
    [sliders[CUT_LO] setMaxValue: xh];
   
    [cutValueForm setFloatValue:parms.cutValue1 at:CUT_LO];
    [[cutValueForm cellAt: CUT_LO :0] setEnabled:YES];
    [sliders[CUT_LO] setFloatValue:parms.cutValue1];
    [sliders[CUT_LO] setEnabled:YES];
    
    if (parms.cutCode >= 2) {
	val2Set = YES;
	[cutValueForm setFloatValue:parms.cutValue2 at:CUT_HI];
	[cutValueForm setEnabled:YES];
	[sliders[CUT_HI] setFloatValue:parms.cutValue2];
	[sliders[CUT_HI] setEnabled:YES];
	[zpSwitch setEnabled:YES];
    } else {
	parms.cutValue2 = 0.0;
	val2Set = NO;
	[cutValueForm setStringValue:"" at:CUT_HI];
	[[cutValueForm cellAt: CUT_HI :0] setEnabled:NO];
	[sliders[CUT_HI] setFloatValue:varlo];
	[sliders[CUT_HI] setEnabled:NO];
	[zpSwitch setEnabled:NO];
    }
    return self;
}

- newValueInForm:sender
{
    parms.cutValue1 = [cutValueForm floatValueAt:CUT_LO];
    if (parms.cutValue1 < varlo)
	parms.cutValue1 = varlo;
    if (parms.cutValue1 > varhi)
	parms.cutValue1 = varhi;

    if (parms.cutCode >= 2) {
	parms.cutValue2 = [cutValueForm floatValueAt:CUT_HI];
	if (parms.cutValue2 < varlo)
	    parms.cutValue2 = varlo;
	if (parms.cutValue2 > varhi)
	    parms.cutValue2 = varhi;
    }
    [cutPlot setCutParms:&parms];
    [self setSliders:YES];
    [self reDrawPlot:@selector(changeCutPlot:) inList :dependList];
    return self;
}

- newValueInSlider2:sender
{
	float newValue1, diff;
	
	newValue1 = [sliders[CUT_LO] floatValue];
	if (newValue1 == parms.cutValue1) return self;
	diff = newValue1 - parms.cutValue1;
	parms.cutValue1 = newValue1;
	[cutValueForm setFloatValue:parms.cutValue1 at:CUT_LO];

	if (parms.cutCode >= 2 && [zpSwitch state] == YES) {
		parms.cutValue2 += diff;
		[cutValueForm setFloatValue:parms.cutValue2 at:CUT_HI];
		[sliders[CUT_HI] setFloatValue:parms.cutValue2];
	}
	[cutPlot setCutParms:&parms];
	[self reDrawPlot: @selector(changeCutPlot:) inList:dependList];
    	return self;
}

- newValueInSlider1:sender
{
	float newValue2, diff;
	
	newValue2 = [sliders[CUT_HI] floatValue];
	if (newValue2 == parms.cutValue2) return self;
	diff = newValue2 - parms.cutValue2;
	parms.cutValue2 = newValue2;
	[cutValueForm setFloatValue:parms.cutValue2 at:CUT_HI];

	if (parms.cutCode >= 2 && [zpSwitch state] == YES) {
		parms.cutValue1 -= diff;
		[cutValueForm setFloatValue:parms.cutValue1 at:CUT_LO];
		[sliders[CUT_LO] setFloatValue:parms.cutValue1];
	}
	[cutPlot setCutParms:&parms];
	[self reDrawPlot: @selector(changeCutPlot:) inList:dependList];
    	return self;
}
- initCutParms
{
    cutButton = [radio selectedRow];
    parms.cutCode = cutButton;
    parms.cutFunc = cutTypeInverse[cutButton];
    parms.varIndex = [tpBrowserCells selectedRow];
 /*
  * set the cut parameters to 'no-cut' starting values 
  */
    varlo = selectedTuple->nlow[parms.varIndex];
    varhi = selectedTuple->nhigh[parms.varIndex];

    switch (parms.cutCode) {
    case 0:
	parms.cutValue1 = varhi;
	break;
    case 1:
	parms.cutValue1 = varlo;
	break;
    case 2:
	parms.cutValue1 = varlo;
	parms.cutValue2 = varhi;
	break;
    case 3:
	parms.cutValue1 = (varhi + varlo) / 2.0;
	parms.cutValue2 = (varhi + varlo) / 2.0;
	break;
    }
    return self;
}
- newCut:sender
{
    int		no = 0, yes = 1;
    
    if (!selectedTuple) {
        return self;
    }
    [self initCutParms];
    cutPlot = [graphicView addPlotOfType:HISTOGRAM andSelect:NO];
    [cutPlot setCutHistFlag:YES];
    [cutPlot bindAxisX:&parms.varIndex];
    [cutPlot setLogScaleX:&no];
    [cutPlot setLogScaleY:&no];
    [cutPlot setAutoScaleX:&yes];
    [cutPlot setAutoScaleY:&yes];
    [cutPlot setTitlesFlag:&yes];
    [cutPlot setAxesFlag:&yes];
    [graphicView graphicsPerformSingle:@selector(setCutParms:)
                                  with:(id)&parms on:cutPlot];
    [graphicView cacheGraphic:cutPlot];
    [[[graphicView window] flushWindow] makeKeyWindow];
    dependList = [cutPlot dependList];
    [docCutList addObject:cutPlot];
    [self setSliders:YES];
    if ( selectedPlot ) {
	[addButton performClick:self];
    } else {
        [self setShowAllState:YES];
	[self updateView];
    }
    return self;
}

- deleteCut:plot
{
    [docCutList removeObject:plot];
    if ( selectedPlot == plot ) {
       selectedPlot = nil;
    }
    [self setSliders:NO];
    [self updateView];
    return self;
}
- addCut:plot
{
    [docCutList addObject:plot];
    return self;
}
- add:sender
{
    int		i;
    
    [graphicView graphicsPerform:@selector(addCutPlot:)
                            with:cutPlot andDraw:YES];
    [graphicView graphicsPerformNOP:cutPlot];
    [[[graphicView window] flushWindow] makeKeyWindow];
    [self setShowAllState:NO];
    [ self updateView];
    i = [cutList indexOf:cutPlot];
    cutBrowserCells = [cutBrowser matrixInColumn:0];
    [cutBrowserCells selectCellAt:i :0];
    return self;
}
- remove:sender
{
    [self removeCut:cutPlot];
    [self setShowAllState:NO];
    [self updateView];
    return self;
}
- replace:sender
{
    id		applyList;
    
    if ( !cutPlot ) {
        return self;
    }
    applyList = [[cutPlot dependList] copy];
    [self removeCut:cutPlot];
    [self initCutParms];
    [cutPlot setCutParms:&parms];
    [cutPlot bindAxisX:&parms.varIndex];
    [self setSliders:YES];
    [self reDrawPlot:@selector(addCutPlot:) inList: applyList];
    [applyList free];
    [graphicView graphicsPerformNOP:cutPlot];
    [[[graphicView window] flushWindow] makeKeyWindow];
    return self;
}
- removeCut:plot
{
    id		drawList;
    
    drawList = [[cutPlot dependList] copy];
    [self reDrawPlot:@selector(removeCutPlot:) inList:drawList];
    [drawList free];
    return self;
}
- reDrawPlot: (SEL) operation inList:aList
{
    [graphicView graphicsPerform:operation	/* redraw selected list */
                            with:cutPlot
			 andDraw:YES
			  inList:aList];
    [graphicView graphicsPerformNOP:cutPlot];

 /*
  * flush window buffer to screen 
  */
    [[[graphicView window] flushWindow] makeKeyWindow];

    return self;
}
- showButton:sender
{
    if ( showAllState ) {
        [self setShowAllState:NO];
    } else {
        [self setShowAllState:YES];
    }
    [self updateView];
    return self;
}
/* Methods that update the view */
- setShowAllState:(BOOL) state
{
    if ( state ) {
	[cutBrowser setTitle:"Available Cuts" ofColumn:0];
	[showAllButton setTitle:"Show selected"];
	showAllState = YES;
    } else {
	[cutBrowser setTitle:"Cuts on Selected Plot" ofColumn:0];
	[showAllButton setTitle:"Show All"];
	showAllState = NO;
    }
    return self;
}
- updateView
{
    unsigned int	i;
    
    docCutList = [graphicView cutList];
    if ( selectedPlot ) {
	[self setTuple:[selectedPlot ntuple]];
    }
    if ( showAllState ) {
        cutList = docCutList;
	[cutBrowser reloadColumn:0];
    } else {
        if ( selectedPlot ) {
	    cutList = [selectedPlot cutList];
	    [cutBrowser reloadColumn:0];
	} else {
	    if ( cutList != nil ) {
	        cutList = nil;
		[cutBrowser reloadColumn:0];
	    }
	}
    }
    if ( cutPlot ) {
	cutBrowserCells = [cutBrowser matrixInColumn:0];
        i = [cutList indexOf:cutPlot];
	if ( i == NX_NOT_IN_LIST ) {
	    [cutBrowserCells selectCellAt:-1 :-1 ];
	} else {
	    [cutBrowserCells selectCellAt:i :0];
	}
    } else {
        if ( [cutList count] ) {
	    cutBrowserCells = [cutBrowser matrixInColumn:0];
	    [cutBrowserCells selectCellAt:0 :0];
	}
    }
    [self selectCut:self];
    return self;
}
- updateEmptySelection
{
    docCutList = [graphicView cutList];
    if ( showAllState ) {
        if ( cutList != docCutList ) {
	    cutList = docCutList;
	    [cutBrowser reloadColumn:0];
	}
    } else {
        cutList = nil;
	[cutBrowser reloadColumn:0];
    }
    [self selectCut:self];
    return self;
}
- setTuple:(ntuple) atuple
{
    if (selectedTuple == atuple)
	return self;
    selectedTuple = atuple;
    [tpBrowser reloadColumn:0];
    tpBrowserCells = [tpBrowser matrixInColumn:0];
    return self;
}
- selectCut:sender
{
    int		i;
    
    cutBrowserCells = [cutBrowser matrixInColumn:0];
    if ( !cutBrowserCells || (i=[cutBrowserCells selectedRow]) < 0 ) {
        cutPlot = nil;
	dependList = nil;
	[self setSliders:NO];
	return self;
    }
    cutPlot = [cutList objectAt:i];
    dependList = [cutPlot dependList];
    [cutPlot getCutParms:&parms];
    [self setSliders:YES];
    return self;
}
- selectCutVar
{
    [cutPlot getCutParms:&parms];
    [tpBrowserCells selectCellAt:parms.varIndex :0];
    [tpBrowserCells scrollCellToVisible:parms.varIndex :0];
    [radio selectCellAt:parms.cutCode :0];
    [self setSliders:YES];
    return self;
}
/* Delegate Methods for NXBrowsers */
- (int) browser: sender fillMatrix: matrix inColumn: (int) column
{
    id                  cut, aCell;
    int                 i, numRows, count;
    char                cutText[80];

    char               *cutType[] = {"Less", "Greater", "Within", "Outside"};

    numRows = 0;
    if (sender == tpBrowser) {
        [matrix allowEmptySel:NO];
	if ( !selectedTuple ) {
	    return numRows;
	}
	numRows = h_getNtDim(selectedTuple);
	for (i = 0; i < numRows; i++) {
	    [matrix insertRowAt:i];
	    aCell = [matrix cellAt:i :0];
	    [aCell setStringValue:h_getNtLabel(selectedTuple, i)];
	    [aCell setLeaf:YES];
	    [aCell setLoaded:YES];
	}
    } else if (sender == cutBrowser) {
    /*
     * load up a cell for each cut 
     */
	count = [cutList count];
	for (i = 0; i < count; i++) {
	    cut = [cutList objectAt:i];
	    [matrix insertRowAt:i];
	    aCell = [matrix cellAt:i :0];
	/*
	 * get variable that cut refers to 
	 */
	    [cut getCutParms:&parms];
	    strcpy(cutText, h_getNtLabel(selectedTuple, parms.varIndex));
	    strcat(cutText, " ");
	/*
	 * concat the function name 
	 */
	    [aCell setStringValue:strcat(cutText, cutType[parms.cutCode])];
	    [aCell setLeaf:YES];
	    [aCell setLoaded:YES];
	}
	numRows = i;
    }
    return numRows;
}
@end
